summaryrefslogtreecommitdiff
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
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>
-rw-r--r--drivers/mfd/tc35892.c131
-rw-r--r--include/linux/mfd/tc35892.h60
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