summaryrefslogtreecommitdiff
path: root/drivers/mfd/tps80031.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/tps80031.c')
-rw-r--r--drivers/mfd/tps80031.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c
index e8ea75c424c6..f0f2ce1f6840 100644
--- a/drivers/mfd/tps80031.c
+++ b/drivers/mfd/tps80031.c
@@ -105,6 +105,9 @@
#define TPS80031_CFG_INPUT_PUPD3 0xF2
#define TPS80031_CFG_INPUT_PUPD4 0xF3
+#define TPS80031_BBSPOR_CFG 0xE6
+#define TPS80031_BBSPOR_CHG_EN 0x8
+
struct tps80031_pupd_data {
u8 reg;
u8 pullup_bit;
@@ -568,6 +571,17 @@ static void tps80031_pupd_init(struct tps80031 *tps80031,
}
}
+static void tps80031_backup_battery_charger_control(struct tps80031 *tps80031,
+ int enable)
+{
+ if (enable)
+ tps80031_update(tps80031->dev, SLAVE_ID1, TPS80031_BBSPOR_CFG,
+ TPS80031_BBSPOR_CHG_EN, TPS80031_BBSPOR_CHG_EN);
+ else
+ tps80031_update(tps80031->dev, SLAVE_ID1, TPS80031_BBSPOR_CFG,
+ 0, TPS80031_BBSPOR_CHG_EN);
+}
+
static void tps80031_init_ext_control(struct tps80031 *tps80031,
struct tps80031_platform_data *pdata) {
int ret;
@@ -874,8 +888,22 @@ static irqreturn_t tps80031_irq(int irq, void *data)
acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0];
if (acks) {
- ret = tps80031_writes(tps80031->dev, SLAVE_ID2,
- TPS80031_INT_STS_A, 3, tmp);
+ /*
+ * Hardware behavior: hardware have the shadow register for
+ * interrupt status register which is updated if interrupt
+ * comes just after the interrupt status read. This shadow
+ * register gets written to main status register and cleared
+ * if any byte write happens in any of status register like
+ * STS_A, STS_B or STS_C.
+ * Hence here to clear the original interrupt status and
+ * updating the STS register with the shadow register, it is
+ * require to write only one byte in any of STS register.
+ * Having multiple register write can cause the STS register
+ * to clear without handling those interrupt and can cause
+ * interrupt miss.
+ */
+ ret = tps80031_write(tps80031->dev, SLAVE_ID2,
+ TPS80031_INT_STS_A, 0);
if (ret < 0) {
dev_err(tps80031->dev, "failed to write "
"interrupt status\n");
@@ -1273,6 +1301,8 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
tps80031_debuginit(tps80031);
+ tps80031_backup_battery_charger_control(tps80031, 1);
+
if (pdata->use_power_off && !pm_power_off)
pm_power_off = tps80031_power_off;
@@ -1288,13 +1318,17 @@ fail:
#ifdef CONFIG_PM
static int tps80031_i2c_suspend(struct i2c_client *client, pm_message_t state)
{
+ struct tps80031 *tps80031 = i2c_get_clientdata(client);
if (client->irq)
disable_irq(client->irq);
+ tps80031_backup_battery_charger_control(tps80031, 0);
return 0;
}
static int tps80031_i2c_resume(struct i2c_client *client)
{
+ struct tps80031 *tps80031 = i2c_get_clientdata(client);
+ tps80031_backup_battery_charger_control(tps80031, 1);
if (client->irq)
enable_irq(client->irq);
return 0;