diff options
-rw-r--r-- | drivers/power/smb349-charger.c | 149 | ||||
-rw-r--r-- | drivers/usb/otg/tegra-otg.c | 20 | ||||
-rw-r--r-- | include/linux/smb349-charger.h | 2 |
3 files changed, 153 insertions, 18 deletions
diff --git a/drivers/power/smb349-charger.c b/drivers/power/smb349-charger.c index 6a4c738b4647..880fa04c5383 100644 --- a/drivers/power/smb349-charger.c +++ b/drivers/power/smb349-charger.c @@ -35,6 +35,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/usb/otg.h> #define SMB349_CHARGE 0x00 #define SMB349_CHRG_CRNTS 0x01 @@ -82,6 +83,8 @@ #define ENABLE_CHARGE 0x02 static struct smb349_charger *charger; +static int smb349_configure_charger(struct i2c_client *client, int value); +static int smb349_configure_interrupts(struct i2c_client *client); static int smb349_read(struct i2c_client *client, int reg) { @@ -165,33 +168,93 @@ static void smb349_clear_interrupts(struct i2c_client *client) __func__); } -static int smb349_configure_charger(struct i2c_client *client) +static int smb349_configure_otg(struct i2c_client *client, int enable) { int ret = 0; - /* Enable volatile writes to registers */ + /*Enable volatile writes to registers*/ ret = smb349_volatile_writes(client, SMB349_ENABLE_WRITE); if (ret < 0) { - dev_err(&client->dev, "%s() error in configuring charger..\n", + dev_err(&client->dev, "%s error in configuring otg..\n", __func__); goto error; } - /* Enable charging */ - ret = smb349_update_reg(client, SMB349_CMD_REG, ENABLE_CHARGE); - if (ret < 0) { - dev_err(&client->dev, "%s(): Failed in writing register" + if (enable) { + /* Enable OTG */ + ret = smb349_update_reg(client, SMB349_CMD_REG, 0x10); + if (ret < 0) { + dev_err(&client->dev, "%s: Failed in writing register" "0x%02x\n", __func__, SMB349_CMD_REG); - goto error; + goto error; + } + + } else { + /* Disable OTG */ + ret = smb349_read(client, SMB349_CMD_REG); + if (ret < 0) { + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + goto error; + } + + ret = smb349_write(client, SMB349_CMD_REG, (ret & (~(1<<4)))); + if (ret < 0) { + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + goto error; + } } - /* Configure THERM ctrl */ - ret = smb349_update_reg(client, SMB349_THERM_CTRL, THERM_CTRL); + /* Disable volatile writes to registers */ + ret = smb349_volatile_writes(client, SMB349_DISABLE_WRITE); if (ret < 0) { - dev_err(&client->dev, "%s: err %d\n", __func__, ret); + dev_err(&client->dev, "%s error in configuring OTG..\n", + __func__); + goto error; + } +error: + return ret; +} + +static int smb349_configure_charger(struct i2c_client *client, int value) +{ + int ret = 0; + + /* Enable volatile writes to registers */ + ret = smb349_volatile_writes(client, SMB349_ENABLE_WRITE); + if (ret < 0) { + dev_err(&client->dev, "%s() error in configuring charger..\n", + __func__); goto error; } + if (value) { + /* Enable charging */ + ret = smb349_update_reg(client, SMB349_CMD_REG, ENABLE_CHARGE); + if (ret < 0) { + dev_err(&client->dev, "%s(): Failed in writing register" + "0x%02x\n", __func__, SMB349_CMD_REG); + goto error; + } + + /* Configure THERM ctrl */ + ret = smb349_update_reg(client, SMB349_THERM_CTRL, THERM_CTRL); + if (ret < 0) { + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + goto error; + } + } else { + ret = smb349_read(client, SMB349_CMD_REG); + if (ret < 0) { + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + goto error; + } + + ret = smb349_write(client, SMB349_CMD_REG, (ret & (~(1<<1)))); + if (ret < 0) { + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + goto error; + } + } /* Disable volatile writes to registers */ ret = smb349_volatile_writes(client, SMB349_DISABLE_WRITE); if (ret < 0) { @@ -214,14 +277,13 @@ static irqreturn_t smb349_status_isr(int irq, void *dev_id) "0x%02x\n", __func__, SMB349_STS_REG_D); goto irq_error; } else if (val != 0) { - if (val & DEDICATED_CHARGER) charger->chrg_type = AC; else if (val & CHRG_DOWNSTRM_PORT) charger->chrg_type = USB; /* configure charger */ - ret = smb349_configure_charger(client); + ret = smb349_configure_charger(client, 1); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring" "charger..\n", __func__); @@ -232,17 +294,21 @@ static irqreturn_t smb349_status_isr(int irq, void *dev_id) } else { charger->state = stopped; - ret = smb349_read(client, SMB349_CMD_REG); + /* Disable charger */ + ret = smb349_configure_charger(client, 0); if (ret < 0) { - dev_err(&client->dev, "%s: err %d\n", __func__, ret); + dev_err(&client->dev, "%s() error in configuring" + "charger..\n", __func__); goto irq_error; } - ret = smb349_write(client, SMB349_CMD_REG, (ret & (~(1<<1)))); + ret = smb349_configure_interrupts(client); if (ret < 0) { - dev_err(&client->dev, "%s: err %d\n", __func__, ret); + dev_err(&client->dev, "%s() error in configuring" + "charger..\n", __func__); goto irq_error; } + } if (charger->charger_cb) @@ -319,6 +385,46 @@ error: return ret; } +static void smb349_otg_status(enum usb_otg_state otg_state, void *data) +{ + struct i2c_client *client = charger->client; + int ret; + + if (otg_state == OTG_STATE_A_HOST) { + + /* configure charger */ + ret = smb349_configure_charger(client, 0); + if (ret < 0) + dev_err(&client->dev, "%s() error in configuring" + "otg..\n", __func__); + + /* ENABLE OTG */ + ret = smb349_configure_otg(client, 1); + if (ret < 0) + dev_err(&client->dev, "%s() error in configuring" + "otg..\n", __func__); + + } else if (otg_state == OTG_STATE_A_SUSPEND) { + + /* Disable OTG */ + ret = smb349_configure_otg(client, 0); + if (ret < 0) + dev_err(&client->dev, "%s() error in configuring" + "otg..\n", __func__); + + /* configure charger */ + ret = smb349_configure_charger(client, 1); + if (ret < 0) + dev_err(&client->dev, "%s() error in configuring" + "otg..\n", __func__); + + ret = smb349_configure_interrupts(client); + if (ret < 0) + dev_err(&client->dev, "%s() error in configuring" + "otg..\n", __func__); + } +} + static int __devinit smb349_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -343,6 +449,14 @@ static int __devinit smb349_probe(struct i2c_client *client, goto error; } + ret = register_otg_callback(smb349_otg_status, charger); + if (ret < 0) + goto error; + + ret = smb349_configure_charger(client, 1); + if (ret < 0) + return ret; + ret = smb349_configure_interrupts(client); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", @@ -359,7 +473,6 @@ static int __devinit smb349_probe(struct i2c_client *client, __func__); goto error; } - return 0; error: kfree(charger); diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index c13c9b6f089a..ffbeede75ed8 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -43,6 +43,8 @@ #define USB_VBUS_STATUS (1 << 10) #define USB_INTS (USB_VBUS_INT_STATUS | USB_ID_INT_STATUS) +typedef void (*callback_t)(enum usb_otg_state otg_state, void *args); + struct tegra_otg_data { struct otg_transceiver otg; unsigned long int_status; @@ -55,6 +57,9 @@ struct tegra_otg_data { unsigned int intr_reg_data; bool detect_vbus; bool clk_enabled; + callback_t charger_cb; + void *charger_cb_data; + }; static struct tegra_otg_data *tegra_clone; @@ -161,6 +166,16 @@ void tegra_stop_host(struct tegra_otg_data *tegra) } } +int register_otg_callback(callback_t cb, void *args) +{ + if (!tegra_clone) + return -ENODEV; + tegra_clone->charger_cb = cb; + tegra_clone->charger_cb_data = args; + return 0; +} +EXPORT_SYMBOL_GPL(register_otg_callback); + static void irq_work(struct work_struct *work) { struct tegra_otg_data *tegra = @@ -209,6 +224,9 @@ static void irq_work(struct work_struct *work) dev_info(tegra->otg.dev, "%s --> %s\n", tegra_state_name(from), tegra_state_name(to)); + if (tegra->charger_cb) + tegra->charger_cb(to, tegra->charger_cb_data); + if (to == OTG_STATE_A_SUSPEND) { if (from == OTG_STATE_A_HOST) tegra_stop_host(tegra); @@ -222,6 +240,8 @@ static void irq_work(struct work_struct *work) tegra_start_host(tegra); } } + + clk_disable(tegra->clk); tegra_otg_disable_clk(); } diff --git a/include/linux/smb349-charger.h b/include/linux/smb349-charger.h index e83a678d9958..311b2f4bb087 100644 --- a/include/linux/smb349-charger.h +++ b/include/linux/smb349-charger.h @@ -50,10 +50,12 @@ struct smb349_charger { }; int smb349_battery_online(void); +typedef void (*callback_t)(enum usb_otg_state otg_state, void *args); /* * Register callback function for the client. * Used by fuel-gauge driver to get battery charging properties. */ extern int register_callback(charging_callback_t cb, void *args); +extern int register_otg_callback(callback_t cb, void *args); #endif /*__LINUX_SMB349_CHARGER_H */ |