diff options
author | David Paris <david.paris-nonst@stericsson.com> | 2011-03-04 14:57:08 +0100 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@stericsson.com> | 2011-09-19 16:00:14 +0200 |
commit | c049b6f7f97e87f155ce6059bfc6b50a28087d6b (patch) | |
tree | 7340cdbe022332663cf79ade03b34385af3da7cb /drivers/mfd | |
parent | 25d6e2fad92661e169809f9238ce56e4eda24727 (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.c | 131 |
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, |