add support for target 3c24xx (more known as Openmoko GTA02 "Freerunner") and merge...
[openwrt/svn-archive/archive.git] / target / linux / s3c24xx / patches / 0159-fix-pcf50633-suspend-resume-onehit-i2c-other-meddlin.patch
1 From 286581f7a1cd2536b70cc0cfbc742ee45260252e Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Fri, 25 Jul 2008 23:06:12 +0100
4 Subject: [PATCH] fix-pcf50633-suspend-resume-onehit-i2c-other-meddling.patch
5
6 - speed up suspend and resume by using one hit i2c bulk transactions
7 - don't bother storing int mask set on suspend, the default one is
8 what we use anyway
9 - put stack_trace() on pcf50633 low level access that fire if we
10 try to touch them before we resumed
11 - cosmetic source cleanup
12 - reduces resume time for pcf50633 from 450ms to 255ms
13
14 Signed-off-by: Andy Green <andy@openmoko.com>
15 ---
16 arch/arm/mach-s3c2440/mach-gta02.c | 21 ++-------
17 drivers/i2c/chips/pcf50633.c | 83 +++++++++++++++++++----------------
18 2 files changed, 49 insertions(+), 55 deletions(-)
19
20 diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
21 index 9ba1036..22de181 100644
22 --- a/arch/arm/mach-s3c2440/mach-gta02.c
23 +++ b/arch/arm/mach-s3c2440/mach-gta02.c
24 @@ -477,24 +477,11 @@ static struct pcf50633_platform_data gta02_pcf_pdata = {
25 .r_fix_batt_par = 10000,
26 .r_sense_milli = 220,
27 .resumers = {
28 - [0] = /* PCF50633_INT1_ADPINS | */
29 - /* PCF50633_INT1_ADPREM | */
30 - PCF50633_INT1_USBINS |
31 - PCF50633_INT1_USBREM |
32 - PCF50633_INT1_ALARM,
33 + [0] = PCF50633_INT1_USBINS |
34 + PCF50633_INT1_USBREM |
35 + PCF50633_INT1_ALARM,
36 [1] = PCF50633_INT2_ONKEYF,
37 - [2] = /* PCF50633_INT3_BATFULL | */
38 - /* PCF50633_INT3_CHGHALT | */
39 - /* PCF50633_INT3_THLIMON | */
40 - /* PCF50633_INT3_THLIMOFF | */
41 - /* PCF50633_INT3_USBLIMON | */
42 - /* PCF50633_INT3_USBLIMOFF | */
43 - PCF50633_INT3_ONKEY1S ,
44 - [3] = 0 /* |
45 - PCF50633_INT4_LOWSYS | */
46 - /* PCF50633_INT4_LOWBAT | */
47 - /* PCF50633_INT4_HIGHTMP */,
48 - [4] = 0
49 + [2] = PCF50633_INT3_ONKEY1S
50 },
51 .rails = {
52 [PCF50633_REGULATOR_AUTO] = {
53 diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
54 index f6886d7..c148ea7 100644
55 --- a/drivers/i2c/chips/pcf50633.c
56 +++ b/drivers/i2c/chips/pcf50633.c
57 @@ -163,10 +163,7 @@ struct pcf50633_data {
58 u_int8_t down2out, down2ena;
59 u_int8_t memldoout, memldoena;
60 u_int8_t ledout, ledena, leddim;
61 - struct {
62 - u_int8_t out;
63 - u_int8_t ena;
64 - } ldo[__NUM_PCF50633_REGS];
65 + u_int8_t ldo[__NUM_PCF50633_REGS][2];
66 } standby_regs;
67
68 struct resume_dependency resume_dependency;
69 @@ -187,6 +184,10 @@ static struct platform_device *pcf50633_pdev;
70
71 static int __reg_write(struct pcf50633_data *pcf, u_int8_t reg, u_int8_t val)
72 {
73 + if (pcf->have_been_suspended == 1) {
74 + dev_err(&pcf->client.dev, "__reg_write while suspended\n");
75 + dump_stack();
76 + }
77 return i2c_smbus_write_byte_data(&pcf->client, reg, val);
78 }
79
80 @@ -205,6 +206,10 @@ static int32_t __reg_read(struct pcf50633_data *pcf, u_int8_t reg)
81 {
82 int32_t ret;
83
84 + if (pcf->have_been_suspended == 1) {
85 + dev_err(&pcf->client.dev, "__reg_read while suspended\n");
86 + dump_stack();
87 + }
88 ret = i2c_smbus_read_byte_data(&pcf->client, reg);
89
90 return ret;
91 @@ -2155,6 +2160,13 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
92 struct i2c_client *client = to_i2c_client(dev);
93 struct pcf50633_data *pcf = i2c_get_clientdata(client);
94 int i;
95 + int ret;
96 + u_int8_t tmp;
97 +
98 + /* we suspend once (!) as late as possible in the suspend sequencing */
99 +
100 + if ((state.event != PM_EVENT_SUSPEND) || (pcf->have_been_suspended))
101 + return 0;
102
103 /* The general idea is to power down all unused power supplies,
104 * and then mask all PCF50606 interrup sources but EXTONR, ONKEYF
105 @@ -2176,25 +2188,25 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
106 pcf->standby_regs.ledout = __reg_read(pcf, PCF50633_REG_LEDOUT);
107 pcf->standby_regs.ledena = __reg_read(pcf, PCF50633_REG_LEDENA);
108 pcf->standby_regs.leddim = __reg_read(pcf, PCF50633_REG_LEDDIM);
109 - /* FIXME: one big read? */
110 - for (i = 0; i < 7; i++) {
111 - u_int8_t reg_out = PCF50633_REG_LDO1OUT + 2*i;
112 - pcf->standby_regs.ldo[i].out = __reg_read(pcf, reg_out);
113 - pcf->standby_regs.ldo[i].ena = __reg_read(pcf, reg_out+1);
114 - }
115 +
116 + /* regulator voltages and enable states */
117 + ret = i2c_smbus_read_i2c_block_data(&pcf->client,
118 + PCF50633_REG_LDO1OUT, 14,
119 + &pcf->standby_regs.ldo[0][0]);
120 + if (ret != 14)
121 + dev_err(dev, "Failed to save LDO levels and enables :-(\n");
122
123 /* switch off power supplies that are not needed during suspend */
124 for (i = 0; i < __NUM_PCF50633_REGULATORS; i++) {
125 - if (!(pcf->pdata->rails[i].flags & PMU_VRAIL_F_SUSPEND_ON)) {
126 - u_int8_t tmp;
127 -
128 - DEBUGP("disabling pcf50633 regulator %u\n", i);
129 - /* we cannot use pcf50633_onoff_set() because we're
130 - * already under the mutex */
131 - tmp = __reg_read(pcf, regulator_registers[i]+1);
132 - tmp &= 0xfe;
133 - __reg_write(pcf, regulator_registers[i]+1, tmp);
134 - }
135 + if ((pcf->pdata->rails[i].flags & PMU_VRAIL_F_SUSPEND_ON))
136 + continue;
137 +
138 + dev_dbg(dev, "disabling regulator %u\n", i);
139 + /* we cannot use pcf50633_onoff_set() because we're
140 + * already under the mutex */
141 + tmp = __reg_read(pcf, regulator_registers[i]+1);
142 + tmp &= 0xfe;
143 + __reg_write(pcf, regulator_registers[i]+1, tmp);
144 }
145
146 /* turn off the backlight */
147 @@ -2202,11 +2214,9 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
148 __reg_write(pcf, PCF50633_REG_LEDOUT, 2);
149 __reg_write(pcf, PCF50633_REG_LEDENA, 0x00);
150
151 - pcf->standby_regs.int1m = __reg_read(pcf, PCF50633_REG_INT1M);
152 - pcf->standby_regs.int2m = __reg_read(pcf, PCF50633_REG_INT2M);
153 - pcf->standby_regs.int3m = __reg_read(pcf, PCF50633_REG_INT3M);
154 - pcf->standby_regs.int4m = __reg_read(pcf, PCF50633_REG_INT4M);
155 - pcf->standby_regs.int5m = __reg_read(pcf, PCF50633_REG_INT5M);
156 + /* set interrupt masks so only those sources we want to wake
157 + * us are able to
158 + */
159 __reg_write(pcf, PCF50633_REG_INT1M, ~pcf->pdata->resumers[0]);
160 __reg_write(pcf, PCF50633_REG_INT2M, ~pcf->pdata->resumers[1]);
161 __reg_write(pcf, PCF50633_REG_INT3M, ~pcf->pdata->resumers[2]);
162 @@ -2240,16 +2250,13 @@ static int pcf50633_resume(struct device *dev)
163 {
164 struct i2c_client *client = to_i2c_client(dev);
165 struct pcf50633_data *pcf = i2c_get_clientdata(client);
166 - int i;
167 + int ret;
168
169 mutex_lock(&pcf->lock);
170
171 - /* Resume all saved registers that don't "survive" standby state */
172 - __reg_write(pcf, PCF50633_REG_INT1M, pcf->standby_regs.int1m);
173 - __reg_write(pcf, PCF50633_REG_INT2M, pcf->standby_regs.int2m);
174 - __reg_write(pcf, PCF50633_REG_INT3M, pcf->standby_regs.int3m);
175 - __reg_write(pcf, PCF50633_REG_INT4M, pcf->standby_regs.int4m);
176 - __reg_write(pcf, PCF50633_REG_INT5M, pcf->standby_regs.int5m);
177 + pcf->have_been_suspended = 2; /* resuming */
178 +
179 + /* these guys get reset while pcf50633 is suspend state, refresh */
180
181 __reg_write(pcf, PCF50633_REG_OOCTIM2, pcf->standby_regs.ooctim2);
182 __reg_write(pcf, PCF50633_REG_AUTOOUT, pcf->standby_regs.autoout);
183 @@ -2265,12 +2272,12 @@ static int pcf50633_resume(struct device *dev)
184 if (!pcf->pdata->defer_resume_backlight)
185 pcf50633_backlight_resume(pcf);
186
187 - /* FIXME: one big read? */
188 - for (i = 0; i < 7; i++) {
189 - u_int8_t reg_out = PCF50633_REG_LDO1OUT + 2*i;
190 - __reg_write(pcf, reg_out, pcf->standby_regs.ldo[i].out);
191 - __reg_write(pcf, reg_out+1, pcf->standby_regs.ldo[i].ena);
192 - }
193 + /* regulator voltages and enable states */
194 + ret = i2c_smbus_write_i2c_block_data(&pcf->client,
195 + PCF50633_REG_LDO1OUT, 14,
196 + &pcf->standby_regs.ldo[0][0]);
197 + if (ret)
198 + dev_err(dev, "Failed to restore LDOs :-( %d\n", ret);
199
200 mutex_unlock(&pcf->lock);
201
202 --
203 1.5.6.3
204