changed Makefile and profiles, added patches for kernel 2.6.24
[openwrt.git] / target / linux / s3c24xx / patches-2.6.24 / 1265-gta01-pcf50606-disable-irq-from-suspend-until-resume.patch
1 From 0c136b451381e760c056a7683b7fc28901f54da4 Mon Sep 17 00:00:00 2001
2 From: Mike Westerhof <mwester@dls.net>
3 Date: Fri, 8 Aug 2008 13:10:59 +0100
4 Subject: [PATCH] gta01-pcf50606-disable-irq-from-suspend-until-resume.patch
5
6     This patch is the pcf50606 equivalent of the pcf50633 patch that
7     disables interrupts from the chip until after resume is complete.
8     In order to ensure no data is lost, the work function is called
9     post-resume to process any pending interrupts.
10
11     Most of the code was quite literally re-used from Andy Green's
12     original patch.
13
14 Signed-off-by: Mike Westerhof <mwester@dls.net>
15 ---
16  drivers/i2c/chips/pcf50606.c |  148 ++++++++++++++++++++++++++++++++++++++++--
17  1 files changed, 142 insertions(+), 6 deletions(-)
18
19 diff --git a/drivers/i2c/chips/pcf50606.c b/drivers/i2c/chips/pcf50606.c
20 index ddba1c7..18263fb 100644
21 --- a/drivers/i2c/chips/pcf50606.c
22 +++ b/drivers/i2c/chips/pcf50606.c
23 @@ -38,6 +38,7 @@
24  #include <linux/interrupt.h>
25  #include <linux/irq.h>
26  #include <linux/workqueue.h>
27 +#include <linux/delay.h>
28  #include <linux/rtc.h>
29  #include <linux/bcd.h>
30  #include <linux/watchdog.h>
31 @@ -95,6 +96,15 @@ enum close_state {
32         CLOSE_STATE_ALLOW = 0x2342,
33  };
34  
35 +enum pcf50606_suspend_states {
36 +       PCF50606_SS_RUNNING,
37 +       PCF50606_SS_STARTING_SUSPEND,
38 +       PCF50606_SS_COMPLETED_SUSPEND,
39 +       PCF50606_SS_RESUMING_BUT_NOT_US_YET,
40 +       PCF50606_SS_STARTING_RESUME,
41 +       PCF50606_SS_COMPLETED_RESUME,
42 +};
43 +
44  struct pcf50606_data {
45         struct i2c_client client;
46         struct pcf50606_platform_data *pdata;
47 @@ -110,6 +120,7 @@ struct pcf50606_data {
48         int onkey_seconds;
49         int irq;
50         int coldplug_done;
51 +       enum pcf50606_suspend_states suspend_state;
52  #ifdef CONFIG_PM
53         struct {
54                 u_int8_t dcdc1, dcdc2;
55 @@ -160,6 +171,10 @@ static const u_int16_t ntc_table_10k_3370B[] = {
56  static inline int __reg_write(struct pcf50606_data *pcf, u_int8_t reg,
57                               u_int8_t val)
58  {
59 +       if (pcf->suspend_state == PCF50606_SS_COMPLETED_SUSPEND) {
60 +               dev_err(&pcf->client.dev, "__reg_write while suspended.\n");
61 +               dump_stack();
62 +       }
63         return i2c_smbus_write_byte_data(&pcf->client, reg, val);
64  }
65  
66 @@ -178,6 +193,10 @@ static inline int32_t __reg_read(struct pcf50606_data *pcf, u_int8_t reg)
67  {
68         int32_t ret;
69  
70 +       if (pcf->suspend_state == PCF50606_SS_COMPLETED_SUSPEND) {
71 +               dev_err(&pcf->client.dev, "__reg_read while suspended.\n");
72 +               dump_stack();
73 +       }
74         ret = i2c_smbus_read_byte_data(&pcf->client, reg);
75  
76         return ret;
77 @@ -569,6 +588,48 @@ static void pcf50606_work(struct work_struct *work)
78  
79         mutex_lock(&pcf->working_lock);
80         pcf->working = 1;
81 +
82 +       /* sanity */
83 +       if (!&pcf->client.dev)
84 +               goto bail;
85 +
86 +       /*
87 +        * if we are presently suspending, we are not in a position to deal
88 +        * with pcf50606 interrupts at all.
89 +        *
90 +        * Because we didn't clear the int pending registers, there will be
91 +        * no edge / interrupt waiting for us when we wake.  But it is OK
92 +        * because at the end of our resume, we call this workqueue function
93 +        * gratuitously, clearing the pending register and re-enabling
94 +        * servicing this interrupt.
95 +        */
96 +
97 +       if ((pcf->suspend_state == PCF50606_SS_STARTING_SUSPEND) ||
98 +           (pcf->suspend_state == PCF50606_SS_COMPLETED_SUSPEND))
99 +               goto bail;
100 +
101 +       /*
102 +        * If we are inside suspend -> resume completion time we don't attempt
103 +        * service until we have fully resumed.  Although we could talk to the
104 +        * device as soon as I2C is up, the regs in the device which we might
105 +        * choose to modify as part of the service action have not been
106 +        * reloaded with their pre-suspend states yet.  Therefore we will
107 +        * defer our service if we are called like that until our resume has
108 +        * completed.
109 +        *
110 +        * This shouldn't happen any more because we disable servicing this
111 +        * interrupt in suspend and don't re-enable it until resume is
112 +        * completed.
113 +        */
114 +
115 +       if (pcf->suspend_state &&
116 +               (pcf->suspend_state != PCF50606_SS_COMPLETED_RESUME))
117 +               goto reschedule;
118 +
119 +       /* this is the case early in resume! Sanity check! */
120 +       if (i2c_get_clientdata(&pcf->client) == NULL)
121 +               goto reschedule;
122 +
123         /*
124          * p35 pcf50606 datasheet rev 2.2:
125          * ''The system controller shall read all interrupt registers in
126 @@ -576,10 +637,27 @@ static void pcf50606_work(struct work_struct *work)
127          * because if you don't INT# gets stuck asserted forever after a
128          * while
129          */
130 -       ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50606_REG_INT1, 3,
131 -                                           pcfirq);
132 -       if (ret != 3)
133 +       ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50606_REG_INT1,
134 +                                           sizeof(pcfirq), pcfirq);
135 +       if (ret != sizeof(pcfirq)) {
136                 DEBUGPC("Oh crap PMU IRQ register read failed %d\n", ret);
137 +               /*
138 +                * it shouldn't fail, we no longer attempt to use
139 +                * I2C while it can be suspended.  But we don't have
140 +                * much option but to retry if if it ever did fail,
141 +                * because if we don't service the interrupt to clear
142 +                * it, we will never see another PMU interrupt edge.
143 +                */
144 +               goto reschedule;
145 +       }
146 +
147 +       /* hey did we just resume? (because we don't get here unless we are
148 +        * running normally or the first call after resumption)
149 +        *
150 +        * pcf50606 resume is really really over now then.
151 +        */
152 +       if (pcf->suspend_state != PCF50606_SS_RUNNING)
153 +               pcf->suspend_state = PCF50606_SS_RUNNING;
154  
155         if (!pcf->coldplug_done) {
156                 DEBUGPC("PMU Coldplug init\n");
157 @@ -814,10 +892,26 @@ static void pcf50606_work(struct work_struct *work)
158  
159         DEBUGPC("\n");
160  
161 +bail:
162         pcf->working = 0;
163         input_sync(pcf->input_dev);
164         put_device(&pcf->client.dev);
165         mutex_unlock(&pcf->working_lock);
166 +
167 +       return;
168 +
169 +reschedule:
170 +
171 +       if ((pcf->suspend_state != PCF50606_SS_STARTING_SUSPEND) &&
172 +           (pcf->suspend_state != PCF50606_SS_COMPLETED_SUSPEND)) {
173 +               msleep(10);
174 +               dev_info(&pcf->client.dev, "rescheduling interrupt service\n");
175 +       }
176 +       if (!schedule_work(&pcf->work))
177 +               dev_err(&pcf->client.dev, "int service reschedule failed\n");
178 +
179 +       /* we don't put the device here, hold it for next time */
180 +       mutex_unlock(&pcf->working_lock);
181  }
182  
183  static irqreturn_t pcf50606_irq(int irq, void *_pcf)
184 @@ -828,7 +922,7 @@ static irqreturn_t pcf50606_irq(int irq, void *_pcf)
185                 irq, _pcf);
186         get_device(&pcf->client.dev);
187         if (!schedule_work(&pcf->work) && !pcf->working)
188 -               dev_dbg(&pcf->client.dev, "work item may be lost\n");
189 +               dev_err(&pcf->client.dev, "pcf irq work already queued.\n");
190  
191         return IRQ_HANDLED;
192  }
193 @@ -1882,12 +1976,27 @@ static int pcf50606_suspend(struct device *dev, pm_message_t state)
194         struct pcf50606_data *pcf = i2c_get_clientdata(client);
195         int i;
196  
197 +       /* we suspend once (!) as late as possible in the suspend sequencing */
198 +
199 +       if ((state.event != PM_EVENT_SUSPEND) ||
200 +           (pcf->suspend_state != PCF50606_SS_RUNNING))
201 +               return -EBUSY;
202 +
203         /* The general idea is to power down all unused power supplies,
204          * and then mask all PCF50606 interrup sources but EXTONR, ONKEYF
205          * and ALARM */
206  
207         mutex_lock(&pcf->lock);
208  
209 +       pcf->suspend_state = PCF50606_SS_STARTING_SUSPEND;
210 +
211 +       /* we are not going to service any further interrupts until we
212 +        * resume.  If the IRQ workqueue is still pending in the background,
213 +        * it will bail when it sees we set suspend state above.
214 +        */
215 +
216 +       disable_irq(pcf->irq);
217 +
218         /* Save all registers that don't "survive" standby state */
219         pcf->standby_regs.dcdc1 = __reg_read(pcf, PCF50606_REG_DCDC1);
220         pcf->standby_regs.dcdc2 = __reg_read(pcf, PCF50606_REG_DCDC2);
221 @@ -1928,6 +2037,8 @@ static int pcf50606_suspend(struct device *dev, pm_message_t state)
222         __reg_write(pcf, PCF50606_REG_INT2M, ~INT2M_RESUMERS & 0xff);
223         __reg_write(pcf, PCF50606_REG_INT3M, ~INT3M_RESUMERS & 0xff);
224  
225 +       pcf->suspend_state = PCF50606_SS_COMPLETED_SUSPEND;
226 +
227         mutex_unlock(&pcf->lock);
228  
229         return 0;
230 @@ -1940,6 +2051,8 @@ static int pcf50606_resume(struct device *dev)
231  
232         mutex_lock(&pcf->lock);
233  
234 +       pcf->suspend_state = PCF50606_SS_STARTING_RESUME;
235 +
236         /* Resume all saved registers that don't "survive" standby state */
237         __reg_write(pcf, PCF50606_REG_INT1M, pcf->standby_regs.int1m);
238         __reg_write(pcf, PCF50606_REG_INT2M, pcf->standby_regs.int2m);
239 @@ -1958,10 +2071,17 @@ static int pcf50606_resume(struct device *dev)
240         __reg_write(pcf, PCF50606_REG_ADCC2, pcf->standby_regs.adcc2);
241         __reg_write(pcf, PCF50606_REG_PWMC1, pcf->standby_regs.pwmc1);
242  
243 +       pcf->suspend_state = PCF50606_SS_COMPLETED_RESUME;
244 +
245 +       enable_irq(pcf->irq);
246 +
247         mutex_unlock(&pcf->lock);
248  
249 -       /* Hack to fix the gta01 power button problem on resume */
250 -       pcf50606_irq(0, pcf);
251 +       /* Call PCF work function; this fixes an issue on the gta01 where
252 +        * the power button "goes away" if it is used to wake the device.
253 +        */
254 +       get_device(&pcf->client.dev);
255 +       pcf50606_work(&pcf->work);
256  
257         return 0;
258  }
259 @@ -1999,9 +2119,25 @@ static int pcf50606_plat_remove(struct platform_device *pdev)
260         return 0;
261  }
262  
263 +/* We have this purely to capture an early indication that we are coming out
264 + * of suspend, before our device resume got called; async interrupt service is
265 + * interested in this.
266 + */
267 +
268 +static int pcf50606_plat_resume(struct platform_device *pdev)
269 +{
270 +       /* i2c_get_clientdata(to_i2c_client(&pdev->dev)) returns NULL at this
271 +        * early resume time so we have to use pcf50606_global
272 +        */
273 +       pcf50606_global->suspend_state = PCF50606_SS_RESUMING_BUT_NOT_US_YET;
274 +
275 +       return 0;
276 +}
277 +
278  static struct platform_driver pcf50606_plat_driver = {
279         .probe  = pcf50606_plat_probe,
280         .remove = pcf50606_plat_remove,
281 +       .resume_early = pcf50606_plat_resume,
282         .driver = {
283                 .owner  = THIS_MODULE,
284                 .name   = "pcf50606",
285 -- 
286 1.5.6.5
287