diff options
author | David Paris <david.paris-nonst@stericsson.com> | 2011-03-04 14:57:08 +0100 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-05-22 10:59:59 +0200 |
commit | 2cfecece99f1f7b737663f778069d907a75b6063 (patch) | |
tree | 3b4299743ecf0a8abe36ca4a700cd8762affd081 | |
parent | ba133989bb85a49900862b7851b11f0680a967e9 (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>
-rw-r--r-- | drivers/mfd/tc35892.c | 131 | ||||
-rw-r--r-- | include/linux/mfd/tc35892.h | 60 |
2 files changed, 155 insertions, 36 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, diff --git a/include/linux/mfd/tc35892.h b/include/linux/mfd/tc35892.h index e47f770d306..41b572c1f8e 100644 --- a/include/linux/mfd/tc35892.h +++ b/include/linux/mfd/tc35892.h @@ -15,21 +15,43 @@ #define TC35892_RSTCTRL_KBDRST (1 << 1) #define TC35892_RSTCTRL_GPIRST (1 << 0) -#define TC35892_IRQST 0x91 -#define TC35892_MANFCODE_MAGIC 0x03 #define TC35892_MANFCODE 0x80 +#define TC35892_MANFCODE_MAGIC 0x03 #define TC35892_VERSION 0x81 -#define TC35892_IOCFG 0xA7 - +#define TC35892_RSTCTRL 0x82 +#define TC35892_EXTRSTN 0x83 +#define TC35892_RSTINTCLR 0x84 #define TC35892_CLKMODE 0x88 #define TC35892_CLKCFG 0x89 #define TC35892_CLKEN 0x8A +#define TC35892_IRQST 0x91 -#define TC35892_RSTCTRL 0x82 -#define TC35892_EXTRSTN 0x83 -#define TC35892_RSTINTCLR 0x84 +#define TC35892_DRIVE0_L 0xA0 +#define TC35892_DRIVE0_H 0xA1 +#define TC35892_DRIVE1_L 0xA2 +#define TC35892_DRIVE1_H 0xA3 +#define TC35892_DRIVE2_L 0xA4 +#define TC35892_DRIVE2_H 0XA5 +#define TC35892_DRIVE3 0xA6 +#define TC35892_IOCFG 0xA7 + +#define TC35892_IOPC0_L 0xAA +#define TC35892_IOPC0_H 0xAB +#define TC35892_IOPC1_L 0xAC +#define TC35892_IOPC1_H 0xAD +#define TC35892_IOPC2_L 0xAE +#define TC35892_IOPC2_H 0xAF +#define TC35892_GPIODATA0 0xC0 +#define TC35892_GPIOMASK0 0xC1 +#define TC35892_GPIODATA1 0xC2 +#define TC35892_GPIOMASK1 0xC3 +#define TC35892_GPIODATA2 0xC4 +#define TC35892_GPIOMASK2 0xC5 +#define TC35892_GPIODIR0 0xC6 +#define TC35892_GPIODIR1 0xC7 +#define TC35892_GPIODIR2 0xC8 #define TC35892_GPIOIS0 0xC9 #define TC35892_GPIOIS1 0xCA #define TC35892_GPIOIS2 0xCB @@ -51,17 +73,12 @@ #define TC35892_GPIOIC0 0xDC #define TC35892_GPIOIC1 0xDD #define TC35892_GPIOIC2 0xDE - -#define TC35892_GPIODATA0 0xC0 -#define TC35892_GPIOMASK0 0xc1 -#define TC35892_GPIODATA1 0xC2 -#define TC35892_GPIOMASK1 0xc3 -#define TC35892_GPIODATA2 0xC4 -#define TC35892_GPIOMASK2 0xC5 - -#define TC35892_GPIODIR0 0xC6 -#define TC35892_GPIODIR1 0xC7 -#define TC35892_GPIODIR2 0xC8 +#define TC35892_GPIOODM0 0xE0 +#define TC35892_GPIOODE0 0xE1 +#define TC35892_GPIOODM1 0xE2 +#define TC35892_GPIOODE1 0xE3 +#define TC35892_GPIOODM2 0xE4 +#define TC35892_GPIOODE2 0xE5 #define TC35892_GPIOSYNC0 0xE6 #define TC35892_GPIOSYNC1 0xE7 @@ -71,13 +88,6 @@ #define TC35892_GPIOWAKE1 0xEA #define TC35892_GPIOWAKE2 0xEB -#define TC35892_GPIOODM0 0xE0 -#define TC35892_GPIOODE0 0xE1 -#define TC35892_GPIOODM1 0xE2 -#define TC35892_GPIOODE1 0xE3 -#define TC35892_GPIOODM2 0xE4 -#define TC35892_GPIOODE2 0xE5 - #define TC35892_INT_GPIIRQ 0 #define TC35892_INT_TI0IRQ 1 #define TC35892_INT_TI1IRQ 2 |