merge of '7393275c6ccce67cadeb49d4afb3459e56edf8a9'
[vuplus_openembedded] / packages / linux / linux-rp-2.6.24 / tosa / 0060-Add-support-for-power_supply-on-tosa.patch
1 From f6ec15733eb55e851c8ad19c2143d425558f6044 Mon Sep 17 00:00:00 2001
2 From: Dmitry Baryshkov <dbaryshkov@gmail.com>
3 Date: Mon, 4 Feb 2008 20:11:58 +0300
4 Subject: [PATCH 60/64] Add support for power_supply on tosa
5
6 Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
7 ---
8  arch/arm/mach-pxa/Makefile     |    2 +-
9  arch/arm/mach-pxa/tosa_power.c |   82 +++++++
10  drivers/leds/leds-tosa.c       |    2 +-
11  drivers/power/Kconfig          |    7 +
12  drivers/power/Makefile         |    1 +
13  drivers/power/tosa_battery.c   |  458 ++++++++++++++++++++++++++++++++++++++++
14  6 files changed, 550 insertions(+), 2 deletions(-)
15  create mode 100644 arch/arm/mach-pxa/tosa_power.c
16  create mode 100644 drivers/power/tosa_battery.c
17
18 diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
19 index f276d24..2b68254 100644
20 --- a/arch/arm/mach-pxa/Makefile
21 +++ b/arch/arm/mach-pxa/Makefile
22 @@ -21,7 +21,7 @@ obj-$(CONFIG_PXA_SHARP_C7xx)  += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o cor
23  obj-$(CONFIG_PXA_SHARP_Cxx00)  += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o
24  obj-$(CONFIG_MACH_AKITA)       += akita-ioexp.o
25  obj-$(CONFIG_MACH_POODLE)      += poodle.o corgi_ssp.o sharpsl_pm.o poodle_pm.o
26 -obj-$(CONFIG_MACH_TOSA)                += tosa.o
27 +obj-$(CONFIG_MACH_TOSA)                += tosa.o tosa_power.o
28  obj-$(CONFIG_MACH_EM_X270)     += em-x270.o
29  
30  ifeq ($(CONFIG_MACH_ZYLONITE),y)
31 diff --git a/arch/arm/mach-pxa/tosa_power.c b/arch/arm/mach-pxa/tosa_power.c
32 new file mode 100644
33 index 0000000..61ca7dc
34 --- /dev/null
35 +++ b/arch/arm/mach-pxa/tosa_power.c
36 @@ -0,0 +1,82 @@
37 +/*
38 + * Battery and Power Management code for the Sharp SL-6000x
39 + *
40 + * Copyright (c) 2005 Dirk Opfer
41 + * Copyright (c) 2008 Dmitry Baryshkov
42 + *
43 + * This program is free software; you can redistribute it and/or modify
44 + * it under the terms of the GNU General Public License version 2 as
45 + * published by the Free Software Foundation.
46 + *
47 + */
48 +#include <linux/kernel.h>
49 +#include <linux/module.h>
50 +#include <linux/power_supply.h>
51 +#include <linux/pda_power.h>
52 +#include <linux/platform_device.h>
53 +#include <linux/interrupt.h>
54 +
55 +#include <asm/arch/tosa.h>
56 +#include <asm/gpio.h>
57 +
58 +static int tosa_power_ac_online(void)
59 +{
60 +       return gpio_get_value(TOSA_GPIO_AC_IN) == 0;
61 +}
62 +
63 +static char *tosa_ac_supplied_to[] = {
64 +       "main-battery",
65 +       "backup-battery",
66 +       "jacket-battery",
67 +};
68 +
69 +static struct pda_power_pdata tosa_power_data = {
70 +       .is_ac_online           = tosa_power_ac_online,
71 +       .supplied_to            = tosa_ac_supplied_to,
72 +       .num_supplicants        = ARRAY_SIZE(tosa_ac_supplied_to),
73 +};
74 +
75 +static struct resource tosa_power_resource[] = {
76 +       {
77 +               .name           = "ac",
78 +               .start          = gpio_to_irq(TOSA_GPIO_AC_IN),
79 +               .end            = gpio_to_irq(TOSA_GPIO_AC_IN),
80 +               .flags          = IORESOURCE_IRQ |
81 +                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
82 +       },
83 +};
84 +
85 +static struct platform_device tosa_power_device = {
86 +       .name                   = "pda-power",
87 +       .id                     = -1,
88 +       .dev.platform_data      = &tosa_power_data,
89 +       .resource               = tosa_power_resource,
90 +       .num_resources          = ARRAY_SIZE(tosa_power_resource),
91 +};
92 +
93 +static int __init tosa_power_init(void)
94 +{
95 +       int ret = gpio_request(TOSA_GPIO_AC_IN, "ac");
96 +       if (ret)
97 +               goto err_gpio_req;
98 +
99 +       ret = gpio_direction_input(TOSA_GPIO_AC_IN);
100 +       if (ret)
101 +               goto err_gpio_in;
102 +
103 +       return platform_device_register(&tosa_power_device);
104 +
105 +err_gpio_in:
106 +       gpio_free(TOSA_GPIO_AC_IN);
107 +err_gpio_req:
108 +       return ret;
109 +}
110 +
111 +static void __exit tosa_power_exit(void)
112 +{
113 +       platform_device_unregister(&tosa_power_device);
114 +       gpio_free(TOSA_GPIO_AC_IN);
115 +}
116 +
117 +module_init(tosa_power_init);
118 +module_exit(tosa_power_exit);
119 diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c
120 index fb2416a..b4498b5 100644
121 --- a/drivers/leds/leds-tosa.c
122 +++ b/drivers/leds/leds-tosa.c
123 @@ -46,7 +46,7 @@ static void tosaled_green_set(struct led_classdev *led_cdev,
124  
125  static struct led_classdev tosa_amber_led = {
126         .name                   = "tosa:amber",
127 -       .default_trigger        = "sharpsl-charge",
128 +       .default_trigger        = "main-battery-charging",
129         .brightness_set         = tosaled_amber_set,
130  };
131  
132 diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
133 index 58c806e..e3a9c37 100644
134 --- a/drivers/power/Kconfig
135 +++ b/drivers/power/Kconfig
136 @@ -49,4 +49,11 @@ config BATTERY_OLPC
137         help
138           Say Y to enable support for the battery on the OLPC laptop.
139  
140 +config BATTERY_TOSA
141 +       tristate "Sharp SL-6000 (tosa) battery"
142 +       depends on MACH_TOSA && MFD_TC6393XB
143 +       help
144 +         Say Y to enable support for the battery on the Sharp Zaurus
145 +         SL-6000 (tosa) models.
146 +
147  endif # POWER_SUPPLY
148 diff --git a/drivers/power/Makefile b/drivers/power/Makefile
149 index 6413ded..1e408fa 100644
150 --- a/drivers/power/Makefile
151 +++ b/drivers/power/Makefile
152 @@ -20,3 +20,4 @@ obj-$(CONFIG_APM_POWER)               += apm_power.o
153  obj-$(CONFIG_BATTERY_DS2760)   += ds2760_battery.o
154  obj-$(CONFIG_BATTERY_PMU)      += pmu_battery.o
155  obj-$(CONFIG_BATTERY_OLPC)     += olpc_battery.o
156 +obj-$(CONFIG_BATTERY_TOSA)     += tosa_battery.o
157 diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
158 new file mode 100644
159 index 0000000..b0fd2f2
160 --- /dev/null
161 +++ b/drivers/power/tosa_battery.c
162 @@ -0,0 +1,458 @@
163 +/*
164 + * Battery and Power Management code for the Sharp SL-6000x
165 + *
166 + * Copyright (c) 2005 Dirk Opfer
167 + * Copyright (c) 2008 Dmitry Baryshkov
168 + *
169 + * This program is free software; you can redistribute it and/or modify
170 + * it under the terms of the GNU General Public License version 2 as
171 + * published by the Free Software Foundation.
172 + *
173 + */
174 +#include <linux/kernel.h>
175 +#include <linux/module.h>
176 +#include <linux/power_supply.h>
177 +#include <linux/wm97xx.h>
178 +#include <linux/delay.h>
179 +#include <linux/spinlock.h>
180 +#include <linux/interrupt.h>
181 +
182 +#include <asm/mach-types.h>
183 +#include <asm/gpio.h>
184 +#include <asm/arch/tosa.h>
185 +
186 +#define BAT_TO_VOLTS(v)                ((v) * 1000000 / 414)
187 +#define BU_TO_VOLTS(v)         ((v) * 1000000 / 1266)
188 +/*
189 + * It's pretty strange value, but that's roughly what I get from
190 + * zaurus maintainer menu
191 + */
192 +//#define BAT_TO_TEMP(t)               ((t) * 10000/2000)
193 +#define BAT_TO_TEMP(t)                 (t)
194 +
195 +static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
196 +static struct work_struct bat_work;
197 +
198 +struct tosa_bat {
199 +       int status;
200 +       struct power_supply psy;
201 +       int full_chrg;
202 +
203 +       struct mutex work_lock; /* protects data */
204 +       bool (*is_present)(struct tosa_bat *bat);
205 +       int gpio_full;
206 +       int gpio_charge_off;
207 +       int gpio_bat;
208 +       int adc_bat;
209 +       int gpio_temp;
210 +       int adc_temp;
211 +};
212 +
213 +static struct tosa_bat tosa_bat_main;
214 +static struct tosa_bat tosa_bat_jacket;
215 +
216 +static enum power_supply_property tosa_bat_main_props[] = {
217 +       POWER_SUPPLY_PROP_STATUS,
218 +       POWER_SUPPLY_PROP_TECHNOLOGY,
219 +       POWER_SUPPLY_PROP_VOLTAGE_NOW,
220 +       POWER_SUPPLY_PROP_VOLTAGE_MAX,
221 +       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
222 +       POWER_SUPPLY_PROP_TEMP,
223 +       POWER_SUPPLY_PROP_PRESENT,
224 +};
225 +
226 +static enum power_supply_property tosa_bat_bu_props[] = {
227 +       POWER_SUPPLY_PROP_STATUS,
228 +       POWER_SUPPLY_PROP_TECHNOLOGY,
229 +       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
230 +       POWER_SUPPLY_PROP_VOLTAGE_NOW,
231 +       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
232 +       POWER_SUPPLY_PROP_PRESENT,
233 +};
234 +
235 +static unsigned long tosa_read_bat(struct tosa_bat *bat)
236 +{
237 +       unsigned long value = 0;
238 +
239 +       if (bat->gpio_bat < 0 || bat->adc_bat < 0)
240 +               return 0;
241 +
242 +       mutex_lock(&bat_lock);
243 +       gpio_set_value(bat->gpio_bat, 1);
244 +       mdelay(5);
245 +       value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, bat->adc_bat);
246 +       gpio_set_value(bat->gpio_bat, 0);
247 +       mutex_unlock(&bat_lock);
248 +       return value;
249 +}
250 +
251 +static unsigned long tosa_read_temp(struct tosa_bat *bat)
252 +{
253 +       unsigned long value = 0;
254 +
255 +       if (bat->gpio_temp < 0 || bat->adc_temp < 0)
256 +               return 0;
257 +
258 +       mutex_lock(&bat_lock);
259 +       gpio_set_value(bat->gpio_temp, 1);
260 +       mdelay(5);
261 +       value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, bat->adc_temp);
262 +       gpio_set_value(bat->gpio_temp, 0);
263 +       mutex_unlock(&bat_lock);
264 +       return value;
265 +}
266 +
267 +static int tosa_bat_get_property(struct power_supply *psy,
268 +                           enum power_supply_property psp,
269 +                           union power_supply_propval *val)
270 +{
271 +       int ret = 0;
272 +       struct tosa_bat *bat = container_of(psy, struct tosa_bat, psy);
273 +
274 +       if (bat->is_present && !bat->is_present(bat)
275 +                       && psp != POWER_SUPPLY_PROP_PRESENT) {
276 +               return -ENODEV;
277 +       }
278 +
279 +       switch (psp) {
280 +       case POWER_SUPPLY_PROP_STATUS:
281 +               val->intval = bat->status;
282 +               break;
283 +       case POWER_SUPPLY_PROP_TECHNOLOGY:
284 +               val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
285 +               break;
286 +       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
287 +               val->intval = BAT_TO_VOLTS(tosa_read_bat(bat));
288 +               break;
289 +       case POWER_SUPPLY_PROP_VOLTAGE_MAX:
290 +               if (bat->full_chrg == -1)
291 +                       val->intval = -1;
292 +               else
293 +                       val->intval = BAT_TO_VOLTS(bat->full_chrg);
294 +               break;
295 +       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
296 +               val->intval = BAT_TO_VOLTS(1551);
297 +               break;
298 +       case POWER_SUPPLY_PROP_TEMP:
299 +               val->intval = BAT_TO_TEMP(tosa_read_temp(bat));
300 +               break;
301 +       case POWER_SUPPLY_PROP_PRESENT:
302 +               val->intval = bat->is_present ? bat->is_present(bat) : 1;
303 +               break;
304 +       default:
305 +               ret = -EINVAL;
306 +               break;
307 +       }
308 +       return ret;
309 +}
310 +
311 +static int tosa_bu_get_property(struct power_supply *psy,
312 +                           enum power_supply_property psp,
313 +                           union power_supply_propval *val)
314 +{
315 +       int ret = 0;
316 +       struct tosa_bat *bat = container_of(psy, struct tosa_bat, psy);
317 +
318 +       switch (psp) {
319 +       case POWER_SUPPLY_PROP_STATUS:
320 +               val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
321 +               break;
322 +       case POWER_SUPPLY_PROP_TECHNOLOGY:
323 +               val->intval = POWER_SUPPLY_TECHNOLOGY_LiMn;
324 +               break;
325 +       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
326 +               val->intval = 0;
327 +               break;
328 +       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
329 +               val->intval = 3 * 1000000; /* 3 V */
330 +               break;
331 +       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
332 +               /* I think so */
333 +               val->intval = BU_TO_VOLTS(tosa_read_bat(bat));
334 +               break;
335 +       case POWER_SUPPLY_PROP_PRESENT:
336 +               val->intval = 1;
337 +               break;
338 +       default:
339 +               ret = -EINVAL;
340 +               break;
341 +       }
342 +       return ret;
343 +}
344 +
345 +static bool tosa_jacket_bat_is_present(struct tosa_bat *bat) {
346 +       // FIXME
347 +       return 1;
348 +}
349 +
350 +static void tosa_bat_external_power_changed(struct power_supply *psy)
351 +{
352 +       schedule_work(&bat_work);
353 +}
354 +
355 +static irqreturn_t tosa_bat_full_isr(int irq, void *data)
356 +{
357 +       printk(KERN_ERR "bat_full irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
358 +       schedule_work(&bat_work);
359 +       return IRQ_HANDLED;
360 +}
361 +
362 +static void tosa_bat_update(struct tosa_bat *bat)
363 +{
364 +       int old = bat->status;
365 +       struct power_supply *psy = &bat->psy;
366 +
367 +       mutex_lock(&bat->work_lock);
368 +
369 +       if (bat->is_present && !bat->is_present(bat)) {
370 +               printk(KERN_DEBUG "%s not present\n", psy->name);
371 +               bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
372 +               bat->full_chrg = -1;
373 +       } else if (power_supply_am_i_supplied(psy)) {
374 +               if (gpio_get_value(bat->gpio_full)) {
375 +                       printk(KERN_DEBUG "%s full\n", psy->name);
376 +
377 +                       if (old == POWER_SUPPLY_STATUS_CHARGING || bat->full_chrg == -1)
378 +                               bat->full_chrg = tosa_read_bat(bat);
379 +
380 +                       gpio_set_value(bat->gpio_charge_off, 1);
381 +                       bat->status = POWER_SUPPLY_STATUS_FULL;
382 +               } else {
383 +                       printk(KERN_ERR "%s charge\n", psy->name);
384 +                       gpio_set_value(bat->gpio_charge_off, 0);
385 +                       bat->status = POWER_SUPPLY_STATUS_CHARGING;
386 +               }
387 +       } else {
388 +               printk(KERN_ERR "%s discharge\n", psy->name);
389 +               gpio_set_value(bat->gpio_charge_off, 1);
390 +               bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
391 +       }
392 +
393 +       if (old != bat->status)
394 +               power_supply_changed(psy);
395 +
396 +       mutex_unlock(&bat->work_lock);
397 +}
398 +
399 +static void tosa_bat_work(struct work_struct *work)
400 +{
401 +       tosa_bat_update(&tosa_bat_main);
402 +       tosa_bat_update(&tosa_bat_jacket);
403 +}
404 +
405 +
406 +static struct tosa_bat tosa_bat_main = {
407 +       .status = POWER_SUPPLY_STATUS_UNKNOWN,
408 +       .full_chrg = -1,
409 +       .psy = {
410 +               .name           = "main-battery",
411 +               .type           = POWER_SUPPLY_TYPE_BATTERY,
412 +               .properties     = tosa_bat_main_props,
413 +               .num_properties = ARRAY_SIZE(tosa_bat_main_props),
414 +               .get_property   = tosa_bat_get_property,
415 +               .external_power_changed = tosa_bat_external_power_changed,
416 +               .use_for_apm    = 1,
417 +       },
418 +
419 +       .gpio_full = TOSA_GPIO_BAT0_CRG,
420 +       .gpio_charge_off = TOSA_TC6393XB_CHARGE_OFF,
421 +       .gpio_bat = TOSA_TC6393XB_BAT0_V_ON,
422 +       .adc_bat = WM97XX_AUX_ID3,
423 +       .gpio_temp = TOSA_TC6393XB_BAT1_TH_ON,
424 +       .adc_temp = WM97XX_AUX_ID2,
425 +};
426 +
427 +static struct tosa_bat tosa_bat_jacket = {
428 +       .status = POWER_SUPPLY_STATUS_UNKNOWN,
429 +       .full_chrg = -1,
430 +       .psy = {
431 +               .name           = "jacket-battery",
432 +               .type           = POWER_SUPPLY_TYPE_BATTERY,
433 +               .properties     = tosa_bat_main_props,
434 +               .num_properties = ARRAY_SIZE(tosa_bat_main_props),
435 +               .get_property   = tosa_bat_get_property,
436 +               .external_power_changed = tosa_bat_external_power_changed,
437 +//             .use_for_apm    = 1,
438 +       },
439 +
440 +       .is_present = tosa_jacket_bat_is_present,
441 +       .gpio_full = TOSA_GPIO_BAT1_CRG,
442 +       .gpio_charge_off = TOSA_TC6393XB_CHARGE_OFF_JC,
443 +       .gpio_bat = TOSA_TC6393XB_BAT1_V_ON,
444 +       .adc_bat = WM97XX_AUX_ID3,
445 +       .gpio_temp = TOSA_TC6393XB_BAT0_TH_ON,
446 +       .adc_temp = WM97XX_AUX_ID2,
447 +};
448 +
449 +static struct tosa_bat tosa_bat_bu = {
450 +       .status = POWER_SUPPLY_STATUS_UNKNOWN,
451 +       .full_chrg = -1,
452 +
453 +       .psy = {
454 +               .name           = "backup-battery",
455 +               .type           = POWER_SUPPLY_TYPE_BATTERY,
456 +               .properties     = tosa_bat_bu_props,
457 +               .num_properties = ARRAY_SIZE(tosa_bat_bu_props),
458 +               .get_property   = tosa_bu_get_property,
459 +               .external_power_changed = tosa_bat_external_power_changed,
460 +       },
461 +
462 +       .gpio_full = -1,
463 +       .gpio_charge_off = -1,
464 +       .gpio_bat = TOSA_TC6393XB_BU_CHRG_ON,
465 +       .adc_bat = WM97XX_AUX_ID4,
466 +       .gpio_temp = -1,
467 +       .adc_temp = -1,
468 +};
469 +
470 +static struct {
471 +       int gpio;
472 +       char *name;
473 +       bool output;
474 +       int value;
475 +} gpios[] = {
476 +       { TOSA_TC6393XB_CHARGE_OFF,     "main charge off",      1, 1 },
477 +       { TOSA_TC6393XB_CHARGE_OFF_JC,  "jacket charge off",    1, 1 },
478 +       { TOSA_TC6393XB_BAT_SW_ON,      "battery switch",       1, 0 },
479 +       { TOSA_TC6393XB_BAT0_V_ON,      "main battery",         1, 0 },
480 +       { TOSA_TC6393XB_BAT1_V_ON,      "jacket battery",       1, 0 },
481 +       { TOSA_TC6393XB_BAT1_TH_ON,     "main battery temp",    1, 0 },
482 +       { TOSA_TC6393XB_BAT0_TH_ON,     "jacket battery temp",  1, 0 },
483 +       { TOSA_TC6393XB_BU_CHRG_ON,     "backup battery",       1, 0 },
484 +       { TOSA_GPIO_BAT0_CRG,           "main battery full",    0, 0 },
485 +       { TOSA_GPIO_BAT1_CRG,           "jacket battery full",  0, 0 },
486 +       { TOSA_GPIO_BAT0_LOW,           "main battery low",     0, 0 },
487 +       { TOSA_GPIO_BAT1_LOW,           "jacket battery low",   0, 0 },
488 +};
489 +
490 +#ifdef CONFIG_PM
491 +static int tosa_bat_suspend(struct device *dev, pm_message_t state)
492 +{
493 +       /* do nothing */
494 +       return 0;
495 +}
496 +
497 +static int tosa_bat_resume(struct device *dev)
498 +{
499 +       schedule_work(&bat_work);
500 +       return 0;
501 +}
502 +#else
503 +#define tosa_bat_suspend NULL
504 +#define tosa_bat_resume NULL
505 +#endif
506 +
507 +static int __devinit tosa_bat_probe(struct device *dev)
508 +{
509 +       int ret;
510 +       int i;
511 +
512 +       if (!machine_is_tosa())
513 +               return -ENODEV;
514 +
515 +       for (i = 0; i < ARRAY_SIZE(gpios); i++) {
516 +               ret = gpio_request(gpios[i].gpio, gpios[i].name);
517 +               if (ret) {
518 +                       i --;
519 +                       goto err_gpio;
520 +               }
521 +
522 +               if (gpios[i].output)
523 +                       ret = gpio_direction_output(gpios[i].gpio,
524 +                                       gpios[i].value);
525 +               else
526 +                       ret = gpio_direction_input(gpios[i].gpio);
527 +
528 +               if (ret)
529 +                       goto err_gpio;
530 +       }
531 +
532 +       mutex_init(&tosa_bat_main.work_lock);
533 +       mutex_init(&tosa_bat_jacket.work_lock);
534 +
535 +       INIT_WORK(&bat_work, tosa_bat_work);
536 +
537 +       ret = power_supply_register(dev, &tosa_bat_main.psy);
538 +       if (ret)
539 +               goto err_psy_reg_main;
540 +       ret = power_supply_register(dev, &tosa_bat_jacket.psy);
541 +       if (ret)
542 +               goto err_psy_reg_jacket;
543 +       ret = power_supply_register(dev, &tosa_bat_bu.psy);
544 +       if (ret)
545 +               goto err_psy_reg_bu;
546 +
547 +       ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG),
548 +                               tosa_bat_full_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
549 +                               "main full", &tosa_bat_main);
550 +       if (ret)
551 +               goto err_req_main;
552 +
553 +       ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG),
554 +                               tosa_bat_full_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
555 +                               "jacket full", &tosa_bat_jacket);
556 +       if (!ret) {
557 +               schedule_work(&bat_work);
558 +               return 0;
559 +       }
560 +
561 +       free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main);
562 +err_req_main:
563 +       power_supply_unregister(&tosa_bat_bu.psy);
564 +err_psy_reg_bu:
565 +       power_supply_unregister(&tosa_bat_jacket.psy);
566 +err_psy_reg_jacket:
567 +       power_supply_unregister(&tosa_bat_main.psy);
568 +err_psy_reg_main:
569 +
570 +       i --;
571 +err_gpio:
572 +       for (; i >= 0; i --)
573 +               gpio_free(gpios[i].gpio);
574 +
575 +       return ret;
576 +}
577 +
578 +static int __devexit tosa_bat_remove(struct device *dev)
579 +{
580 +       int i;
581 +
582 +       free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket);
583 +       free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main);
584 +
585 +       power_supply_unregister(&tosa_bat_bu.psy);
586 +       power_supply_unregister(&tosa_bat_jacket.psy);
587 +       power_supply_unregister(&tosa_bat_main.psy);
588 +
589 +       for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i --)
590 +               gpio_free(gpios[i].gpio);
591 +
592 +       return 0;
593 +}
594 +
595 +static struct device_driver tosa_bat_driver = {
596 +       .name           = "wm97xx-battery",
597 +       .bus            = &wm97xx_bus_type,
598 +       .owner          = THIS_MODULE,
599 +       .probe          = tosa_bat_probe,
600 +       .remove         = __devexit_p(tosa_bat_remove),
601 +       .suspend        = tosa_bat_suspend,
602 +       .resume         = tosa_bat_resume,
603 +};
604 +
605 +static int __init tosa_bat_init(void)
606 +{
607 +       return driver_register(&tosa_bat_driver);
608 +}
609 +
610 +static void __exit tosa_bat_exit(void)
611 +{
612 +       driver_unregister(&tosa_bat_driver);
613 +}
614 +
615 +module_init(tosa_bat_init);
616 +module_exit(tosa_bat_exit);
617 +
618 +MODULE_LICENSE("GPL");
619 +MODULE_AUTHOR("Dmitry Baryshkov");
620 +MODULE_DESCRIPTION("Tosa battery driver");
621 -- 
622 1.5.3.8
623