summaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
authorDavid Paris <david.paris-nonst@stericsson.com>2011-03-04 14:57:08 +0100
committerUlf Hansson <ulf.hansson@stericsson.com>2011-09-19 16:00:14 +0200
commitc049b6f7f97e87f155ce6059bfc6b50a28087d6b (patch)
tree7340cdbe022332663cf79ade03b34385af3da7cb /drivers/mfd
parent25d6e2fad92661e169809f9238ce56e4eda24727 (diff)
MFD: tc35892: Optimize power save settings for suspend
Compared to HSI GPIO V3.1, register 0x82 is set with a different value 0x82 = 0xE (HSI GPIO V3.1) 0x82 = 0xF (on android) In case of android, it seems that GPIO reset should be applied to reach 13uA of consumption on TC35892 when AP in DeepSleep Change-Id: I64eaa4304fcd9f71546cadba0aa703c91b6075df Signed-off-by: David Paris <david.paris-nonst@stericsson.com> Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/tc35892.c131
1 files changed, 120 insertions, 11 deletions
diff --git a/drivers/mfd/tc35892.c b/drivers/mfd/tc35892.c
index 33d44bbc731..c997a4b67aa 100644
--- a/drivers/mfd/tc35892.c
+++ b/drivers/mfd/tc35892.c
@@ -325,17 +325,112 @@ static int __devexit tc35892_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
+
+static u32 sleep_regs[] = {
+ TC35892_IOPC0_L,
+ TC35892_IOPC0_H,
+ TC35892_IOPC1_L,
+ TC35892_IOPC1_H,
+ TC35892_IOPC2_L,
+ TC35892_IOPC2_H,
+ TC35892_DRIVE0_L,
+ TC35892_DRIVE0_H,
+ TC35892_DRIVE1_L,
+ TC35892_DRIVE1_H,
+ TC35892_DRIVE2_L,
+ TC35892_DRIVE2_H,
+ TC35892_DRIVE3,
+ TC35892_GPIODATA0,
+ TC35892_GPIOMASK0,
+ TC35892_GPIODATA1,
+ TC35892_GPIOMASK1,
+ TC35892_GPIODATA2,
+ TC35892_GPIOMASK2,
+ TC35892_GPIODIR0,
+ TC35892_GPIODIR1,
+ TC35892_GPIODIR2,
+ TC35892_GPIOIE0,
+ TC35892_GPIOIE1,
+ TC35892_GPIOIE2,
+ TC35892_RSTCTRL,
+ TC35892_CLKCFG,
+};
+
+static u8 sleep_regs_val[] = {
+ 0x00, /* TC35892_IOPC0_L */
+ 0x00, /* TC35892_IOPC0_H */
+ 0x00, /* TC35892_IOPC1_L */
+ 0x00, /* TC35892_IOPC1_H */
+ 0x00, /* TC35892_IOPC2_L */
+ 0x00, /* TC35892_IOPC2_H */
+ 0xff, /* TC35892_DRIVE0_L */
+ 0xff, /* TC35892_DRIVE0_H */
+ 0xff, /* TC35892_DRIVE1_L */
+ 0xff, /* TC35892_DRIVE1_H */
+ 0xff, /* TC35892_DRIVE2_L */
+ 0xff, /* TC35892_DRIVE2_H */
+ 0x0f, /* TC35892_DRIVE3 */
+ 0x80, /* TC35892_GPIODATA0 */
+ 0x80, /* TC35892_GPIOMASK0 */
+ 0x80, /* TC35892_GPIODATA1 */
+ 0x80, /* TC35892_GPIOMASK1 */
+ 0x06, /* TC35892_GPIODATA2 */
+ 0x06, /* TC35892_GPIOMASK2 */
+ 0xf0, /* TC35892_GPIODIR0 */
+ 0xe0, /* TC35892_GPIODIR1 */
+ 0xee, /* TC35892_GPIODIR2 */
+ 0x0f, /* TC35892_GPIOIE0 */
+ 0x1f, /* TC35892_GPIOIE1 */
+ 0x11, /* TC35892_GPIOIE2 */
+ 0x0f, /* TC35892_RSTCTRL */
+ 0xb0 /* TC35892_CLKCFG */
+
+};
+
+static u8 sleep_regs_backup[ARRAY_SIZE(sleep_regs)];
+
static int tc35892_suspend(struct device *dev)
{
struct tc35892 *tc35892 = dev_get_drvdata(dev);
struct i2c_client *client = tc35892->i2c;
int ret = 0;
-
- /* put the system to sleep mode */
- if (!device_may_wakeup(&client->dev))
- ret = tc35892_reg_write(tc35892, TC35892_CLKMODE,
- TC35892_CLKMODE_MODCTL_SLEEP);
-
+ int i, j;
+ int val;
+
+ /* Put the system to sleep mode */
+ if (!device_may_wakeup(&client->dev)) {
+ for (i = 0; i < ARRAY_SIZE(sleep_regs); i++) {
+ val = tc35892_reg_read(tc35892,
+ sleep_regs[i]);
+ if (val < 0)
+ goto out;
+
+ sleep_regs_backup[i] = (u8) (val & 0xff);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sleep_regs); i++) {
+ ret = tc35892_reg_write(tc35892,
+ sleep_regs[i],
+ sleep_regs_val[i]);
+ if (ret < 0)
+ goto fail;
+
+ }
+
+ ret = tc35892_reg_write(tc35892,
+ TC35892_CLKMODE,
+ TC35892_CLKMODE_MODCTL_SLEEP);
+ }
+out:
+ return ret;
+fail:
+ for (j = 0; j <= i; j++) {
+ ret = tc35892_reg_write(tc35892,
+ sleep_regs[i],
+ sleep_regs_backup[i]);
+ if (ret < 0)
+ break;
+ }
return ret;
}
@@ -344,16 +439,30 @@ static int tc35892_resume(struct device *dev)
struct tc35892 *tc35892 = dev_get_drvdata(dev);
struct i2c_client *client = tc35892->i2c;
int ret = 0;
+ int i;
- /* enable the system into operation */
+ /* Enable the system into operation */
if (!device_may_wakeup(&client->dev))
- ret = tc35892_reg_write(tc35892, TC35892_CLKMODE,
- TC35892_CLKMODE_MODCTL_OPERATION);
-
+ {
+ ret = tc35892_reg_write(tc35892,
+ TC35892_CLKMODE,
+ TC35892_CLKMODE_MODCTL_OPERATION);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < ARRAY_SIZE(sleep_regs); i++) {
+ ret = tc35892_reg_write(tc35892,
+ sleep_regs[i],
+ sleep_regs_backup[i]);
+ /* Not much to do here if we fail */
+ if (ret < 0)
+ break;
+ }
+ }
+out:
return ret;
}
-
static const struct dev_pm_ops tc35892_dev_pm_ops = {
.suspend = tc35892_suspend,
.resume = tc35892_resume,