changed Makefile and profiles, added patches for kernel 2.6.24
[openwrt.git] / target / linux / s3c24xx / patches-2.6.26 / 0177-fix-pcf50633-disable-irq-from-suspend-until-resume.p.patch
1 From e9c3ab43aecc2b4b0024bda7799987fd77a08fcb Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Fri, 25 Jul 2008 23:06:15 +0100
4 Subject: [PATCH] fix-pcf50633-disable-irq-from-suspend-until-resume.patch
5
6 Disable pcf interrupt (not for wake, just as interrupt) in
7 suspend, re-enable it again just before we force-call the
8 workqueue function at end of pcf resume, which leads to
9 pcf interrupt source registers getting cleared so it can
10 signal an interrupt normally again.
11
12 This change ends the uncontrolled appearance of pcf interrupts
13 during resume time which previously caused the work to attempt
14 to use the I2C stuff before i2c host device had itself resumed.
15 Now the isr work is only queued, and the isr work function called,
16 definitively after pcf resume completes.
17
18 In suspend time, the work function may have been queued some
19 time before and be pending, and it could still show up at a
20 bad time.  Therefore if the work function sees that it is
21 coming since the start of pcf50633 suspend function, it
22 aborts without attempting to read the pcf interrupt regs,
23 leaving them for resume to take care of.
24
25 USB current limit and no battery work functions are also made
26 aware of suspend state and act accordingly.
27
28 Lastly I noticed that in early resume, i2c_get_clientdata(&pcf->client)
29 returns NULL, presumably because i2c device is still suspended.  This
30 could easily make trouble for async events like interrupt work,
31 since pcf pointer is the client data.  Disabling appearance of the
32 work until after pcf50633 resume will also avoid that.
33
34 Signed-off-by: Andy Green <andy@openmoko.com>
35 ---
36  drivers/i2c/chips/pcf50633.c |   89 +++++++++++++++++++++++++++++------------
37  1 files changed, 63 insertions(+), 26 deletions(-)
38
39 diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
40 index 87a3003..33c4ef4 100644
41 --- a/drivers/i2c/chips/pcf50633.c
42 +++ b/drivers/i2c/chips/pcf50633.c
43 @@ -632,6 +632,11 @@ static void pcf50633_work_usbcurlim(struct work_struct *work)
44  
45         mutex_lock(&pcf->working_lock_usb_curlimit);
46  
47 +       /* just can't cope with it if we are suspending, don't reschedule */
48 +       if ((pcf->suspend_state == PCF50633_SS_STARTING_SUSPEND) ||
49 +           (pcf->suspend_state == PCF50633_SS_COMPLETED_SUSPEND))
50 +               goto bail;
51 +
52         dev_info(&pcf->client.dev, "pcf50633_work_usbcurlim\n");
53  
54         if (!pcf->probe_completed)
55 @@ -663,7 +668,8 @@ bail:
56  reschedule:
57         dev_info(&pcf->client.dev, "pcf50633_work_usbcurlim rescheduling\n");
58         if (!schedule_work(&pcf->work_usb_curlimit))
59 -               dev_err(&pcf->client.dev, "work item may be lost\n");
60 +               dev_err(&pcf->client.dev, "curlim reschedule work "
61 +                                                           "already queued\n");
62  
63         mutex_unlock(&pcf->working_lock_usb_curlimit);
64         /* don't spew, delaying whatever else is happening */
65 @@ -700,7 +706,7 @@ int pcf50633_notify_usb_current_limit_change(struct pcf50633_data *pcf,
66         pcf->pending_curlimit = ma;
67  
68         if (!schedule_work(&pcf->work_usb_curlimit))
69 -               dev_err(&pcf->client.dev, "work item may be lost\n");
70 +               dev_err(&pcf->client.dev, "curlim work item already queued\n");
71  
72         return 0;
73  }
74 @@ -727,6 +733,9 @@ static void pcf50633_work_nobat(struct work_struct *work)
75         while (1) {
76                 msleep(1000);
77  
78 +               if (pcf->suspend_state != PCF50633_SS_RUNNING)
79 +                       continue;
80 +
81                 /* there's a battery in there now? */
82                 if (reg_read(pcf, PCF50633_REG_MBCS3) & 0x40) {
83  
84 @@ -761,6 +770,10 @@ static void pcf50633_work(struct work_struct *work)
85         mutex_lock(&pcf->working_lock);
86         pcf->working = 1;
87  
88 +       /* sanity */
89 +       if (!&pcf->client.dev)
90 +               goto bail;
91 +
92         /*
93          * if we are presently suspending, we are not in a position to deal
94          * with pcf50633 interrupts at all.
95 @@ -784,42 +797,55 @@ static void pcf50633_work(struct work_struct *work)
96          * reloaded with their pre-suspend states yet.  Therefore we will
97          * defer our service if we are called like that until our resume has
98          * completed.
99 +        *
100 +        * This shouldn't happen any more because we disable servicing this
101 +        * interrupt in suspend and don't re-enable it until resume is
102 +        * completed.
103          */
104  
105 -       if (pcf->have_been_suspended && (pcf->have_been_suspended < 3))
106 +       if (pcf->suspend_state &&
107 +               (pcf->suspend_state != PCF50633_SS_COMPLETED_RESUME))
108 +               goto reschedule;
109 +
110 +       /* this is the case early in resume! Sanity check! */
111 +       if (i2c_get_clientdata(&pcf->client) == NULL)
112                 goto reschedule;
113  
114         /*
115 -        * datasheet says we have to read the five IRQ
116 -        * status regs in one transaction
117 -        */
118 -       ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50633_REG_INT1, 5,
119 -                                           pcfirq);
120 -       if (ret != 5) {
121 +       * datasheet says we have to read the five IRQ
122 +       * status regs in one transaction
123 +       */
124 +       ret = i2c_smbus_read_i2c_block_data(&pcf->client,
125 +                                               PCF50633_REG_INT1,
126 +                                               sizeof(pcfirq),
127 +                                               pcfirq);
128 +       if (ret != sizeof(pcfirq)) {
129                 dev_info(&pcf->client.dev,
130                          "Oh crap PMU IRQ register read failed -- "
131                          "retrying later %d\n", ret);
132                 /*
133 -                * it shouldn't fail, we no longer attempt to use I2C while
134 -                * it can be suspended.  But we don't have much option but to
135 -                * retry if if it ever did fail, because if we don't service
136 -                * the interrupt to clear it, we will never see another PMU
137 -                * interrupt edge.
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? */
148 -
149 -       if (pcf->have_been_suspended) {
150 -               /* resume is officially over now then */
151 -               pcf->have_been_suspended = 0;
152 +       /* hey did we just resume? (because we don't get here unless we are
153 +        * running normally or the first call after resumption)
154 +        */
155  
156 +       if (pcf->suspend_state != PCF50633_SS_RUNNING) {
157                 /*
158 -                * grab a copy of resume interrupt reasons
159 -                * from pcf50633 POV
160 -                */
161 +               * grab a copy of resume interrupt reasons
162 +               * from pcf50633 POV
163 +               */
164                 memcpy(pcf->pcfirq_resume, pcfirq, sizeof(pcf->pcfirq_resume));
165 +
166 +               /* pcf50633 resume is really really over now then */
167 +               pcf->suspend_state = PCF50633_SS_RUNNING;
168         }
169  
170         if (!pcf->coldplug_done) {
171 @@ -1168,6 +1194,7 @@ static void pcf50633_work(struct work_struct *work)
172  
173         DEBUGPC("\n");
174  
175 +bail:
176         pcf->working = 0;
177         input_sync(pcf->input_dev);
178         put_device(&pcf->client.dev);
179 @@ -1201,7 +1228,7 @@ static irqreturn_t pcf50633_irq(int irq, void *_pcf)
180  
181         get_device(&pcf->client.dev);
182         if (!schedule_work(&pcf->work) && !pcf->working)
183 -               dev_err(&pcf->client.dev, "work item may be lost\n");
184 +               dev_err(&pcf->client.dev, "pcf irq work already queued\n");
185  
186         return IRQ_HANDLED;
187  }
188 @@ -2303,7 +2330,7 @@ int pcf50633_report_resumers(struct pcf50633_data *pcf, char *buf)
189         char *end = buf;
190         int n;
191  
192 -       for (n = 0; n < 40; n++)
193 +       for (n = 0; n < ARRAY_SIZE(int_names); n++)
194                 if (int_names[n]) {
195                         if (pcf->pcfirq_resume[n >> 3] & (1 >> (n & 7)))
196                                 end += sprintf(end, "  * %s\n", int_names[n]);
197 @@ -2352,6 +2379,15 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
198  
199         mutex_lock(&pcf->lock);
200  
201 +       pcf->suspend_state = PCF50633_SS_STARTING_SUSPEND;
202 +
203 +       /* we are not going to service any further interrupts until we
204 +        * resume.  If the IRQ workqueue is still pending in the background,
205 +        * it will bail when it sees we set suspend state above
206 +        */
207 +
208 +       disable_irq(pcf->irq);
209 +
210         /* Save all registers that don't "survive" standby state */
211         pcf->standby_regs.ooctim2 = __reg_read(pcf, PCF50633_REG_OOCTIM2);
212  
213 @@ -2495,6 +2531,8 @@ static int pcf50633_resume(struct device *dev)
214  
215         pcf->suspend_state = PCF50633_SS_COMPLETED_RESUME;
216  
217 +       enable_irq(pcf->irq);
218 +
219         mutex_unlock(&pcf->lock);
220  
221         /* gratuitous call to PCF work function, in the case that the PCF
222 @@ -2504,8 +2542,7 @@ static int pcf50633_resume(struct device *dev)
223          */
224  
225         get_device(&pcf->client.dev);
226 -       if (!schedule_work(&pcf->work) && !pcf->working)
227 -               dev_err(&pcf->client.dev, "resume work item may be lost\n");
228 +       pcf50633_work(&pcf->work);
229  
230         callback_all_resume_dependencies(&pcf->resume_dependency);
231  
232 -- 
233 1.5.6.3
234