disable IMQ on 2.6.28 as well -- people should use IFB..
[openwrt.git] / target / linux / s3c24xx / patches / 0153-introduce-charging-led-behaviour.patch.patch
1 From 86bec3382cd1694a3b5cd6d8796cfcbdbe5ca5ff Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Fri, 25 Jul 2008 23:06:11 +0100
4 Subject: [PATCH] introduce-charging-led-behaviour.patch
5
6 Creates a new behaviour requested by Will that the red LED on GTA02
7 is lit during battery charging.and goes out when the battery is full.
8
9 This is done by leveraging the PMU interrupts, but in one scenario
10 there is no interrupt that occurs, when the battery is replaced after
11 being removed with the USB power in all the while.  So a sleepy work
12 function is started under those circumstances to watch for battery
13 reinsertion or USB cable pull.
14
15 100mA limit was not being observed under some conditions so this was
16 fixed and tested with a USB cable with D+/D- disconnected.  1A
17 charger behaviour was also tested.
18
19 Showing the charging action exposes some inconsistency in pcf50633
20 charging action.  If your battery is nearly full, it will keep
21 charging it at decreasing current even after it thinks it is at
22 100% capacity for a long while.  But if you pull that same battery
23 and re-insert it, the charger state machine in pcf50633 believe it is
24 full and won't charge it.
25
26 Signed-off-by: Andy Green <andy@openmoko.com>
27 ---
28  arch/arm/mach-s3c2440/mach-gta02.c |    8 ++
29  drivers/i2c/chips/pcf50633.c       |  212 ++++++++++++++++++++++++++++++++++--
30  include/linux/pcf506xx.h           |    2 +
31  3 files changed, 214 insertions(+), 8 deletions(-)
32
33 diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
34 index 601f7bc..d7882ea 100644
35 --- a/arch/arm/mach-s3c2440/mach-gta02.c
36 +++ b/arch/arm/mach-s3c2440/mach-gta02.c
37 @@ -437,6 +437,14 @@ static int pmu_callback(struct device *dev, unsigned int feature,
38                 case PMU_EVT_USB_REMOVE:
39                         pcf50633_charge_enable(pcf50633_global, 0);
40                         break;
41 +               case PMU_EVT_CHARGER_IDLE:
42 +                       /* printk(KERN_ERR"PMU_EVT_CHARGER_IDLE\n"); */
43 +                       neo1973_gpb_setpin(GTA02_GPIO_AUX_LED, 0);
44 +                       break;
45 +               case PMU_EVT_CHARGER_ACTIVE:
46 +                       /* printk(KERN_ERR"PMU_EVT_CHARGER_ACTIVE\n"); */
47 +                       neo1973_gpb_setpin(GTA02_GPIO_AUX_LED, 1);
48 +                       break;
49                 default:
50                         break;
51                 }
52 diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
53 index 8ba81d2..38cabd2 100644
54 --- a/drivers/i2c/chips/pcf50633.c
55 +++ b/drivers/i2c/chips/pcf50633.c
56 @@ -47,6 +47,7 @@
57  #include <linux/platform_device.h>
58  #include <linux/pcf50633.h>
59  #include <linux/apm-emulation.h>
60 +#include <linux/jiffies.h>
61  
62  #include <asm/mach-types.h>
63  #include <asm/arch/gta02.h>
64 @@ -121,8 +122,23 @@ struct pcf50633_data {
65         int onkey_seconds;
66         int irq;
67         int have_been_suspended;
68 +       int usb_removal_count;
69         unsigned char pcfirq_resume[5];
70  
71 +       /* if he pulls battery while charging, we notice that and correctly
72 +        * report that the charger is idle.  But there is no interrupt that
73 +        * fires if he puts a battery back in and charging resumes.  So when
74 +        * the battery is pulled, we run this work function looking for
75 +        * either charger resumption or USB cable pull
76 +        */
77 +       struct mutex working_lock_nobat;
78 +       struct work_struct work_nobat;
79 +       int working_nobat;
80 +       int usb_removal_count_nobat;
81 +       int jiffies_last_bat_ins;
82 +
83 +       int last_curlim_set;
84 +
85         int coldplug_done; /* cleared by probe, set by first work service */
86         int flag_bat_voltage_read; /* ipc to /sys batt voltage read func */
87  
88 @@ -259,6 +275,8 @@ static u_int16_t async_adc_complete(struct pcf50633_data *pcf)
89                         (__reg_read(pcf, PCF50633_REG_ADCS3) &
90                                                   PCF50633_ADCS3_ADCDAT1L_MASK);
91  
92 +       DEBUGPC("adc result = %d\n", ret);
93 +
94         return ret;
95  }
96  
97 @@ -512,8 +530,7 @@ static void configure_pmu_for_charger(struct pcf50633_data *pcf,
98  {
99         switch (type) {
100         case CHARGER_TYPE_NONE:
101 -               __reg_write(pcf, PCF50633_REG_MBCC7,
102 -                                                   PCF50633_MBCC7_USB_SUSPEND);
103 +               pcf50633_usb_curlim_set(pcf, 0);
104                 break;
105         /*
106          * the PCF50633 has a feature that it will supply only excess current
107 @@ -521,10 +538,19 @@ static void configure_pmu_for_charger(struct pcf50633_data *pcf,
108          * 500mA setting is "up to 500mA" according to that.
109          */
110         case CHARGER_TYPE_HOSTUSB:
111 -               __reg_write(pcf, PCF50633_REG_MBCC7, PCF50633_MBCC7_USB_500mA);
112 +               /* USB subsystem should call pcf50633_usb_curlim_set to set
113 +                * what was negotiated with the host when it is enumerated
114 +                * successfully.  If we get called again after a good
115 +                * negotiation, we keep what was negotiated.  (Removal of
116 +                * USB plug destroys pcf->last_curlim_set to 0)
117 +                */
118 +               if (pcf->last_curlim_set > 100)
119 +                       pcf50633_usb_curlim_set(pcf, pcf->last_curlim_set);
120 +               else
121 +                       pcf50633_usb_curlim_set(pcf, 100);
122                 break;
123         case CHARGER_TYPE_1A:
124 -               __reg_write(pcf, PCF50633_REG_MBCC7, PCF50633_MBCC7_USB_1000mA);
125 +               pcf50633_usb_curlim_set(pcf, 1000);
126                 /*
127                  * stop GPO / EN_HOSTUSB power driving out on the same
128                  * USB power pins we have a 1A charger on right now!
129 @@ -536,6 +562,12 @@ static void configure_pmu_for_charger(struct pcf50633_data *pcf,
130                                                  PCF50633_REG_GPIO1CFG) & 0xf0);
131                 break;
132         }
133 +
134 +       /* max out USB fast charge current -- actual current drawn is
135 +        * additionally limited by USB limit so no worries
136 +        */
137 +       __reg_write(pcf, PCF50633_REG_MBCC5, 0xff);
138 +
139  }
140  
141  static void trigger_next_adc_job_if_any(struct pcf50633_data *pcf)
142 @@ -562,6 +594,49 @@ static void add_request_to_adc_queue(struct pcf50633_data *pcf,
143                 trigger_next_adc_job_if_any(pcf);
144  }
145  
146 +/* we are run when we see a NOBAT situation, because there is no interrupt
147 + * source in pcf50633 that triggers on resuming charging.  It watches to see
148 + * if charging resumes, it reassesses the charging source if it does.  If the
149 + * USB power disappears, it is also a sign there must be a battery and it is
150 + * NOT being charged, so it exits since the next move must be USB insertion for
151 + * change of charger state
152 + */
153 +
154 +static void pcf50633_work_nobat(struct work_struct *work)
155 +{
156 +       struct pcf50633_data *pcf =
157 +                       container_of(work, struct pcf50633_data, work_nobat);
158 +
159 +       mutex_lock(&pcf->working_lock_nobat);
160 +       pcf->working_nobat = 1;
161 +       mutex_unlock(&pcf->working_lock_nobat);
162 +
163 +       while (1) {
164 +               msleep(1000);
165 +
166 +               /* there's a battery in there now? */
167 +               if (reg_read(pcf, PCF50633_REG_MBCS3) & 0x40) {
168 +
169 +                       pcf->jiffies_last_bat_ins = jiffies;
170 +
171 +                       /* figure out our charging stance */
172 +                       add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
173 +                                                    PCF50633_ADCC1_AVERAGE_16);
174 +                       goto bail;
175 +               }
176 +
177 +               /* he pulled USB cable since we were started?  exit then */
178 +               if (pcf->usb_removal_count_nobat != pcf->usb_removal_count)
179 +                       goto bail;
180 +       }
181 +
182 +bail:
183 +       mutex_lock(&pcf->working_lock_nobat);
184 +       pcf->working_nobat = 0;
185 +       mutex_unlock(&pcf->working_lock_nobat);
186 +}
187 +
188 +
189  static void pcf50633_work(struct work_struct *work)
190  {
191         struct pcf50633_data *pcf =
192 @@ -674,20 +749,29 @@ static void pcf50633_work(struct work_struct *work)
193                 if (pcf->pdata->cb)
194                         pcf->pdata->cb(&pcf->client.dev,
195                                        PCF50633_FEAT_MBC, PMU_EVT_USB_INSERT);
196 +               msleep(500); /* debounce, allow to see any ID resistor */
197                 /* completion irq will figure out our charging stance */
198                 add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
199                                      PCF50633_ADCC1_AVERAGE_16);
200         }
201         if (pcfirq[0] & PCF50633_INT1_USBREM) {
202                 DEBUGPC("USBREM ");
203 +
204 +               pcf->usb_removal_count++;
205 +
206                 /* only deal if we had understood it was in */
207                 if (pcf->flags & PCF50633_F_USB_PRESENT) {
208                         input_report_key(pcf->input_dev, KEY_POWER2, 0);
209                         apm_queue_event(APM_POWER_STATUS_CHANGE);
210                         pcf->flags &= ~PCF50633_F_USB_PRESENT;
211 +
212                         if (pcf->pdata->cb)
213                                 pcf->pdata->cb(&pcf->client.dev,
214                                         PCF50633_FEAT_MBC, PMU_EVT_USB_REMOVE);
215 +
216 +                       /* destroy any memory of grant of power from host */
217 +                       pcf->last_curlim_set = 0;
218 +
219                         /* completion irq will figure out our charging stance */
220                         add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
221                                         PCF50633_ADCC1_AVERAGE_16);
222 @@ -759,6 +843,33 @@ static void pcf50633_work(struct work_struct *work)
223  
224         if (pcfirq[2] & PCF50633_INT3_BATFULL) {
225                 DEBUGPC("BATFULL ");
226 +
227 +               /* the problem is, we get a false BATFULL if we inserted battery
228 +                * while USB powered.  Defeat BATFULL if we recently inserted
229 +                * battery
230 +                */
231 +
232 +               if ((jiffies - pcf->jiffies_last_bat_ins) < (HZ * 2)) {
233 +
234 +                       DEBUGPC("*** Ignoring BATFULL ***\n");
235 +
236 +                       ret = reg_read(pcf, PCF50633_REG_MBCC7) &
237 +                                       PCF56033_MBCC7_USB_MASK;
238 +
239 +
240 +                       reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
241 +                                        PCF56033_MBCC7_USB_MASK,
242 +                                        PCF50633_MBCC7_USB_SUSPEND);
243 +
244 +                       reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
245 +                                        PCF56033_MBCC7_USB_MASK,
246 +                                        ret);
247 +               } else {
248 +                       if (pcf->pdata->cb)
249 +                               pcf->pdata->cb(&pcf->client.dev,
250 +                                      PCF50633_FEAT_MBC, PMU_EVT_CHARGER_IDLE);
251 +               }
252 +
253                 /* FIXME: signal this to userspace */
254         }
255         if (pcfirq[2] & PCF50633_INT3_CHGHALT) {
256 @@ -796,8 +907,7 @@ static void pcf50633_work(struct work_struct *work)
257  
258                 switch (pcf->adc_queue_mux[tail]) {
259                 case PCF50633_ADCC1_MUX_BATSNS_RES: /* battery voltage */
260 -                       pcf->flag_bat_voltage_read =
261 -                                                 async_adc_complete(pcf);
262 +                       pcf->flag_bat_voltage_read = async_adc_complete(pcf);
263                         break;
264                 case PCF50633_ADCC1_MUX_ADCIN1: /* charger type */
265                         pcf->charger_adc_result_raw = async_adc_complete(pcf);
266 @@ -829,8 +939,37 @@ static void pcf50633_work(struct work_struct *work)
267                     (PCF50633_MBCS1_USBPRES | PCF50633_MBCS1_USBOK)) {
268                         /*
269                          * hey no need to freak out, we have some kind of
270 -                        * valid charger power
271 +                        * valid charger power to keep us going -- but note that
272 +                        * we are not actually charging anything
273 +                        */
274 +                       if (pcf->pdata->cb)
275 +                               pcf->pdata->cb(&pcf->client.dev,
276 +                                      PCF50633_FEAT_MBC, PMU_EVT_CHARGER_IDLE);
277 +
278 +                       reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
279 +                                       PCF50633_MBCC1_RESUME,
280 +                                       PCF50633_MBCC1_RESUME);
281 +       
282 +                       /*
283 +                        * Well, we are not charging anything right this second
284 +                        * ... however in the next ~30s before we get the next
285 +                        * NOBAT, he might insert a battery.  So we schedule a
286 +                        * work function checking to see if
287 +                        * we started charging something during that time.
288 +                        * USB removal as well as charging terminates the work
289 +                        * function so we can't get terminally confused
290                          */
291 +                       mutex_lock(&pcf->working_lock_nobat);
292 +                       if (!pcf->working_nobat) {
293 +                               pcf->usb_removal_count_nobat =
294 +                                                       pcf->usb_removal_count;
295 +
296 +                               if (!schedule_work(&pcf->work_nobat))
297 +                                       DEBUGPC("failed to schedule nobat\n");
298 +                       }
299 +                       mutex_unlock(&pcf->working_lock_nobat);
300 +
301 +
302                         DEBUGPC("(NO)BAT ");
303                 } else {
304                         /* Really low battery voltage, we have 8 seconds left */
305 @@ -1063,10 +1202,13 @@ void pcf50633_usb_curlim_set(struct pcf50633_data *pcf, int ma)
306  {
307         u_int8_t bits;
308  
309 +       pcf->last_curlim_set = ma;
310 +
311         dev_dbg(&pcf->client.dev, "setting usb current limit to %d ma", ma);
312  
313 -       if (ma >= 1000)
314 +       if (ma >= 1000) {
315                 bits = PCF50633_MBCC7_USB_1000mA;
316 +       }
317         else if (ma >= 500)
318                 bits = PCF50633_MBCC7_USB_500mA;
319         else if (ma >= 100)
320 @@ -1074,8 +1216,40 @@ void pcf50633_usb_curlim_set(struct pcf50633_data *pcf, int ma)
321         else
322                 bits = PCF50633_MBCC7_USB_SUSPEND;
323  
324 +       DEBUGPC("pcf50633_usb_curlim_set -> %dmA\n", ma);
325 +
326 +       if (!pcf->pdata->cb)
327 +               goto set_it;
328 +
329 +       switch (bits) {
330 +       case PCF50633_MBCC7_USB_100mA:
331 +       case PCF50633_MBCC7_USB_SUSPEND:
332 +                /* no charging is gonna be happening */
333 +               pcf->pdata->cb(&pcf->client.dev,
334 +                              PCF50633_FEAT_MBC, PMU_EVT_CHARGER_IDLE);
335 +               break;
336 +       default: /* right charging context that if there is power, we charge */
337 +               if (pcf->flags & PCF50633_F_USB_PRESENT)
338 +                       pcf->pdata->cb(&pcf->client.dev,
339 +                              PCF50633_FEAT_MBC, PMU_EVT_CHARGER_ACTIVE);
340 +               break;
341 +       }
342 +
343 +set_it:
344         reg_set_bit_mask(pcf, PCF50633_REG_MBCC7, PCF56033_MBCC7_USB_MASK,
345                          bits);
346 +
347 +       /* clear batfull */
348 +       reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
349 +                               PCF50633_MBCC1_AUTORES,
350 +                               0);
351 +       reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
352 +                               PCF50633_MBCC1_RESUME,
353 +                               PCF50633_MBCC1_RESUME);
354 +       reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
355 +                               PCF50633_MBCC1_AUTORES,
356 +                               PCF50633_MBCC1_AUTORES);
357 +
358  }
359  EXPORT_SYMBOL_GPL(pcf50633_usb_curlim_set);
360  
361 @@ -1105,16 +1279,36 @@ static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, NULL);
362  void pcf50633_charge_enable(struct pcf50633_data *pcf, int on)
363  {
364         u_int8_t bits;
365 +       u_int8_t usblim;
366  
367         if (!(pcf->pdata->used_features & PCF50633_FEAT_MBC))
368                 return;
369  
370 +       DEBUGPC("pcf50633_charge_enable %d\n", on);
371 +
372         if (on) {
373                 pcf->flags |= PCF50633_F_CHG_ENABLED;
374                 bits = PCF50633_MBCC1_CHGENA;
375 +               usblim = reg_read(pcf, PCF50633_REG_MBCC7) &
376 +                                                       PCF56033_MBCC7_USB_MASK;
377 +               switch (usblim) {
378 +               case PCF50633_MBCC7_USB_1000mA:
379 +               case PCF50633_MBCC7_USB_500mA:
380 +                       if (pcf->flags & PCF50633_F_USB_PRESENT)
381 +                               if (pcf->pdata->cb)
382 +                                       pcf->pdata->cb(&pcf->client.dev,
383 +                                                      PCF50633_FEAT_MBC,
384 +                                                      PMU_EVT_CHARGER_ACTIVE);
385 +                       break;
386 +               default:
387 +                       break;
388 +               }
389         } else {
390                 pcf->flags &= ~PCF50633_F_CHG_ENABLED;
391                 bits = 0;
392 +               if (pcf->pdata->cb)
393 +                       pcf->pdata->cb(&pcf->client.dev,
394 +                                      PCF50633_FEAT_MBC, PMU_EVT_CHARGER_IDLE);
395         }
396         reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, PCF50633_MBCC1_CHGENA,
397                          bits);
398 @@ -1703,7 +1897,9 @@ static int pcf50633_detect(struct i2c_adapter *adapter, int address, int kind)
399  
400         mutex_init(&data->lock);
401         mutex_init(&data->working_lock);
402 +       mutex_init(&data->working_lock_nobat);
403         INIT_WORK(&data->work, pcf50633_work);
404 +       INIT_WORK(&data->work_nobat, pcf50633_work_nobat);
405         data->irq = irq;
406         data->working = 0;
407         data->onkey_seconds = -1;
408 diff --git a/include/linux/pcf506xx.h b/include/linux/pcf506xx.h
409 index 33be73e..9069bd4 100644
410 --- a/include/linux/pcf506xx.h
411 +++ b/include/linux/pcf506xx.h
412 @@ -21,6 +21,8 @@ enum pmu_event {
413         PMU_EVT_USB_INSERT,
414         PMU_EVT_USB_REMOVE,
415  #endif
416 +       PMU_EVT_CHARGER_ACTIVE,
417 +       PMU_EVT_CHARGER_IDLE,
418         __NUM_PMU_EVTS
419  };
420  
421 -- 
422 1.5.6.3
423