omap24xx: Fix n810 boot
[openwrt.git] / target / linux / omap24xx / patches-2.6.38 / 900-n810-battery-management.patch
1 --- a/drivers/cbus/Kconfig
2 +++ b/drivers/cbus/Kconfig
3 @@ -72,4 +72,12 @@ config CBUS_RETU_HEADSET
4           to Retu/Vilma. Detection state and events are exposed through
5           sysfs.
6  
7 +config N810BM
8 +       depends on CBUS_RETU && CBUS_TAHVO
9 +       tristate "Nokia n810 battery management"
10 +       ---help---
11 +         Nokia n810 device battery management.
12 +
13 +         If unsure, say N.
14 +
15  endmenu
16 --- a/drivers/cbus/Makefile
17 +++ b/drivers/cbus/Makefile
18 @@ -11,3 +11,6 @@ obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += r
19  obj-$(CONFIG_CBUS_RETU_RTC)    += retu-rtc.o
20  obj-$(CONFIG_CBUS_RETU_WDT)    += retu-wdt.o
21  obj-$(CONFIG_CBUS_RETU_HEADSET)        += retu-headset.o
22 +n810bm-y                       += n810bm_main.o
23 +n810bm-y                       += lipocharge.o
24 +obj-$(CONFIG_N810BM)           += n810bm.o
25 --- /dev/null
26 +++ b/drivers/cbus/n810bm_main.c
27 @@ -0,0 +1,1586 @@
28 +/*
29 + *   Nokia n810 battery management
30 + *
31 + *   WARNING: This driver is based on unconfirmed documentation.
32 + *            It is possibly dangerous to use this software.
33 + *            Use this software at your own risk!
34 + *
35 + *   Copyright (c) 2010-2011 Michael Buesch <mb@bu3sch.de>
36 + *
37 + *   This program is free software; you can redistribute it and/or
38 + *   modify it under the terms of the GNU General Public License
39 + *   as published by the Free Software Foundation; either version 2
40 + *   of the License, or (at your option) any later version.
41 + *
42 + *   This program is distributed in the hope that it will be useful,
43 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
44 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45 + *   GNU General Public License for more details.
46 + */
47 +
48 +#define DEBUG
49 +
50 +#include <linux/module.h>
51 +#include <linux/device.h>
52 +#include <linux/platform_device.h>
53 +#include <linux/slab.h>
54 +#include <linux/mutex.h>
55 +#include <linux/timer.h>
56 +#include <linux/firmware.h>
57 +#include <linux/bitops.h>
58 +#include <linux/workqueue.h>
59 +#include <linux/delay.h>
60 +
61 +#include "cbus.h"
62 +#include "retu.h"
63 +#include "tahvo.h"
64 +#include "lipocharge.h"
65 +
66 +
67 +#define N810BM_PMM_BLOCK_FILENAME      "n810-cal-bme-pmm.fw"
68 +#define N810BM_PMM_BLOCK_SIZE          0x600
69 +#define N810BM_PMM_GROUP_SIZE          0x200
70 +#define N810BM_PMM_ELEM_SIZE           0x10
71 +
72 +#define N810BM_CHECK_INTERVAL          (HZ * 2)
73 +#define N810BM_MIN_VOLTAGE_THRES       3200 /* Absolute minimum voltage threshold */
74 +
75 +
76 +/* RETU_ADC_BSI
77 + * The battery size indicator ADC measures the resistance between
78 + * the battery BSI pin and ground. This is used to detect the battery
79 + * capacity, as the BSI resistor is related to capacity.
80 + *
81 + * Manually measured lookup table.
82 + * Hard to measure, thus not very accurate.
83 + *
84 + * Resistance  |  ADC value
85 + * ========================
86 + * 120k        |  0x3AC
87 + * 110k        |  0x37C
88 + * 100k        |  0x351
89 + *  90k        |  0x329
90 + */
91 +
92 +/* RETU_ADC_BATTVOLT
93 + * Manually measured lookup table.
94 + * Hard to measure, thus not very accurate.
95 + *
96 + * Voltage  |  ADC value
97 + * =====================
98 + * 2.80V    |  0x037
99 + * 2.90V    |  0x05E
100 + * 3.00V    |  0x090
101 + * 3.10V    |  0x0A4
102 + * 3.20V    |  0x0CC
103 + * 3.30V    |  0x0EF
104 + * 3.40V    |  0x115
105 + * 3.50V    |  0x136
106 + * 3.60V    |  0x15C
107 + * 3.70V    |  0x187
108 + * 3.80V    |  0x1A5
109 + * 3.90V    |  0x1C9
110 + * 4.00V    |  0x1ED
111 + * 4.10V    |  0x212
112 + * 4.20V    |  0x236
113 + */
114 +
115 +
116 +/* PMM block ADC IDs */
117 +enum n810bm_pmm_adc_id {
118 +       N810BM_PMM_ADC_BATVOLT          = 0x01, /* Battery voltage */
119 +       N810BM_PMM_ADC_CHGVOLT          = 0x02, /* Charger voltage */
120 +       N810BM_PMM_ADC_GND2             = 0x03, /* Ground 0V */
121 +       N810BM_PMM_ADC_BSI              = 0x04, /* Battery size indicator */
122 +       N810BM_PMM_ADC_BATTEMP          = 0x05, /* Battery temperature */
123 +       N810BM_PMM_ADC_HEADSET          = 0x06, /* Headset detection */
124 +       N810BM_PMM_ADC_HOOKDET          = 0x07, /* Hook detection */
125 +       N810BM_PMM_ADC_LIGHTSENS        = 0x08, /* Light sensor */
126 +       N810BM_PMM_ADC_BATCURR          = 0x0E, /* Battery current */
127 +       N810BM_PMM_ADC_BKUPVOLT         = 0x13, /* Backup battery voltage */
128 +       N810BM_PMM_ADC_LIGHTTEMP        = 0x14, /* Light sensor temperature */
129 +       N810BM_PMM_ADC_RFGP             = 0x15, /* RF GP */
130 +       N810BM_PMM_ADC_WBTX             = 0x16, /* Wideband TX detection */
131 +       N810BM_PMM_ADC_RETUTEMP         = 0x17, /* RETU chip temperature */
132 +       N810BM_PMM_ADC_0xFE             = 0xFE,
133 +};
134 +
135 +struct n810bm_adc_calib {
136 +       enum n810bm_pmm_adc_id id;
137 +       u8 flags;
138 +       u8 adc_groupnr;
139 +       u32 field1;
140 +       u32 field2;
141 +       u16 field3;
142 +       u16 field4;
143 +};
144 +
145 +struct n810bm_calib {
146 +       struct n810bm_adc_calib adc[25];
147 +};
148 +
149 +enum n810bm_capacity {
150 +       N810BM_CAP_UNKNOWN      = -1,
151 +       N810BM_CAP_NONE         = 0,
152 +       N810BM_CAP_1500MAH      = 1500, /* 1500 mAh battery */
153 +};
154 +
155 +enum n810bm_notify_flags {
156 +       N810BM_NOTIFY_charger_present,
157 +       N810BM_NOTIFY_charger_state,
158 +       N810BM_NOTIFY_charger_pwm,
159 +};
160 +
161 +struct n810bm {
162 +       bool battery_present;                   /* A battery is inserted */
163 +       bool charger_present;                   /* The charger is connected */
164 +       enum n810bm_capacity capacity;          /* The capacity of the inserted battery (if any) */
165 +
166 +       bool charger_enabled;                   /* Want to charge? */
167 +       struct lipocharge charger;              /* Charger subsystem */
168 +       unsigned int active_current_pwm;        /* Active value of TAHVO_REG_CHGCURR */
169 +       int current_measure_enabled;            /* Current measure enable refcount */
170 +
171 +       struct platform_device *pdev;
172 +       struct n810bm_calib calib;              /* Calibration data */
173 +
174 +       bool verbose_charge_log;                /* Verbose charge logging */
175 +
176 +       unsigned long notify_flags;
177 +       struct work_struct notify_work;
178 +       struct work_struct currmeas_irq_work;
179 +       struct delayed_work periodic_check_work;
180 +
181 +       bool initialized;                       /* The hardware was initialized */
182 +       struct mutex mutex;
183 +};
184 +
185 +static void n810bm_notify_charger_present(struct n810bm *bm);
186 +static void n810bm_notify_charger_state(struct n810bm *bm);
187 +static void n810bm_notify_charger_pwm(struct n810bm *bm);
188 +
189 +
190 +static struct platform_device *n810bm_retu_device;
191 +static struct platform_device *n810bm_tahvo_device;
192 +
193 +
194 +static inline struct n810bm * device_to_n810bm(struct device *dev)
195 +{
196 +       struct platform_device *pdev = to_platform_device(dev);
197 +       struct n810bm *bm = platform_get_drvdata(pdev);
198 +
199 +       return bm;
200 +}
201 +
202 +static inline bool n810bm_known_battery_present(struct n810bm *bm)
203 +{
204 +       return bm->battery_present &&
205 +              bm->capacity != N810BM_CAP_UNKNOWN &&
206 +              bm->capacity != N810BM_CAP_NONE;
207 +}
208 +
209 +static NORET_TYPE void n810bm_emergency(struct n810bm *bm, const char *message) ATTRIB_NORET;
210 +static void n810bm_emergency(struct n810bm *bm, const char *message)
211 +{
212 +       printk(KERN_EMERG "n810 battery management fatal fault: %s\n", message);
213 +       cbus_emergency();
214 +}
215 +
216 +static u16 tahvo_read(struct n810bm *bm, unsigned int reg)
217 +{
218 +       return tahvo_read_reg(reg);
219 +}
220 +
221 +static void tahvo_maskset(struct n810bm *bm, unsigned int reg, u16 mask, u16 set)
222 +{
223 +       tahvo_set_clear_reg_bits(reg, set, mask);
224 +}
225 +
226 +static inline void tahvo_write(struct n810bm *bm, unsigned int reg, u16 value)
227 +{
228 +       unsigned long flags;
229 +
230 +       spin_lock_irqsave(&tahvo_lock, flags);
231 +       tahvo_write_reg(reg, value);
232 +       spin_unlock_irqrestore(&tahvo_lock, flags);
233 +}
234 +
235 +static inline void tahvo_set(struct n810bm *bm, unsigned int reg, u16 mask)
236 +{
237 +       tahvo_set_clear_reg_bits(reg, mask, mask);
238 +}
239 +
240 +static inline void tahvo_clear(struct n810bm *bm, unsigned int reg, u16 mask)
241 +{
242 +       tahvo_set_clear_reg_bits(reg, 0, mask);
243 +}
244 +
245 +static u16 retu_read(struct n810bm *bm, unsigned int reg)
246 +{
247 +       return retu_read_reg(&n810bm_retu_device->dev, reg);
248 +}
249 +
250 +static void retu_maskset(struct n810bm *bm, unsigned int reg, u16 mask, u16 set)
251 +{
252 +       retu_set_clear_reg_bits(&n810bm_retu_device->dev, reg, set, mask);
253 +}
254 +
255 +static inline void retu_write(struct n810bm *bm, unsigned int reg, u16 value)
256 +{
257 +       retu_write_reg(&n810bm_retu_device->dev, reg, value);
258 +}
259 +
260 +static int retu_adc_average(struct n810bm *bm, unsigned int chan,
261 +                           unsigned int nr_passes)
262 +{
263 +       unsigned int i, value = 0;
264 +       int ret;
265 +
266 +       if (WARN_ON(!nr_passes))
267 +               return 0;
268 +       for (i = 0; i < nr_passes; i++) {
269 +               ret = retu_read_adc(&n810bm_retu_device->dev, chan);
270 +               if (ret < 0)
271 +                       return ret;
272 +               value += ret;
273 +       }
274 +       value /= nr_passes;
275 +
276 +       return value;
277 +}
278 +
279 +static struct n810bm_adc_calib * n810bm_get_adc_calib(struct n810bm *bm,
280 +                                               enum n810bm_pmm_adc_id id)
281 +{
282 +       unsigned int index = 0;
283 +       struct n810bm_adc_calib *cal;
284 +
285 +       if (id != N810BM_PMM_ADC_0xFE)
286 +               index = (unsigned int)id + 1;
287 +       if (index >= ARRAY_SIZE(bm->calib.adc))
288 +               return NULL;
289 +
290 +       cal = &bm->calib.adc[index];
291 +       WARN_ON(cal->id && cal->id != id);
292 +
293 +       return cal;
294 +}
295 +
296 +static int pmm_record_get(struct n810bm *bm,
297 +                         const struct firmware *pmm_block,
298 +                         void *buffer, size_t length,
299 +                         unsigned int group, unsigned int element, unsigned int offset)
300 +{
301 +       const u8 *pmm_area = pmm_block->data;
302 +       u8 active_group_mask;
303 +
304 +       if (pmm_block->size != N810BM_PMM_BLOCK_SIZE)
305 +               return -EINVAL;
306 +       if (group >= N810BM_PMM_BLOCK_SIZE / N810BM_PMM_GROUP_SIZE)
307 +               return -EINVAL;
308 +       if (element >= N810BM_PMM_GROUP_SIZE / N810BM_PMM_ELEM_SIZE)
309 +               return -EINVAL;
310 +       if (offset >= N810BM_PMM_ELEM_SIZE || length > N810BM_PMM_ELEM_SIZE ||
311 +           length + offset > N810BM_PMM_ELEM_SIZE)
312 +               return -EINVAL;
313 +
314 +       active_group_mask = pmm_area[16];
315 +       if (!(active_group_mask & (1 << group))) {
316 +               dev_dbg(&bm->pdev->dev, "pwm_record_get: Requested group %u, "
317 +                       "but group is not active", group);
318 +               return -ENOENT;
319 +       }
320 +
321 +       memcpy(buffer,
322 +              pmm_area + group * N810BM_PMM_GROUP_SIZE
323 +                       + element * N810BM_PMM_ELEM_SIZE
324 +                       + offset,
325 +              length);
326 +
327 +       return 0;
328 +}
329 +
330 +/* PMM block group 1 element */
331 +struct group1_element {
332 +       u8 id;
333 +       u8 flags;
334 +       u8 adc_groupnr;
335 +       u8 _padding;
336 +       __le32 field1;
337 +       __le32 field2;
338 +} __packed;
339 +
340 +static int extract_group1_elem(struct n810bm *bm,
341 +                              const struct firmware *pmm_block,
342 +                              const enum n810bm_pmm_adc_id *pmm_adc_ids, size_t nr_pmm_adc_ids,
343 +                              u32 field1_mask, u32 field2_mask)
344 +{
345 +       struct group1_element elem;
346 +       int err;
347 +       unsigned int i, element_nr;
348 +       struct n810bm_adc_calib *adc_calib;
349 +
350 +       for (i = 0; i < nr_pmm_adc_ids; i++) {
351 +               element_nr = (unsigned int)(pmm_adc_ids[i]) + 3;
352 +
353 +               err = pmm_record_get(bm, pmm_block, &elem, sizeof(elem),
354 +                                    1, element_nr, 0);
355 +               if (err)
356 +                       continue;
357 +               adc_calib = n810bm_get_adc_calib(bm, elem.id);
358 +               if (!adc_calib) {
359 +                       dev_err(&bm->pdev->dev, "extract_group1_elem: "
360 +                               "Could not get calib element for 0x%02X",
361 +                               elem.id);
362 +                       return -EINVAL;
363 +               }
364 +
365 +               if (adc_calib->flags == elem.flags) {
366 +                       adc_calib->field1 = le32_to_cpu(elem.field1) & field1_mask;
367 +                       adc_calib->field2 = le32_to_cpu(elem.field2) & field2_mask;
368 +               } else {
369 +                       dev_dbg(&bm->pdev->dev, "extract_group1_elem: "
370 +                               "Not extracting fields due to flags mismatch: "
371 +                               "0x%02X vs 0x%02X",
372 +                               adc_calib->flags, elem.flags);
373 +               }
374 +       }
375 +
376 +       return 0;
377 +}
378 +
379 +static int n810bm_parse_pmm_group1(struct n810bm *bm,
380 +                                  const struct firmware *pmm_block)
381 +{
382 +       struct n810bm_adc_calib *adc_calib;
383 +       struct group1_element elem;
384 +       int err;
385 +
386 +       static const enum n810bm_pmm_adc_id pmm_adc_ids_1[] = {
387 +               N810BM_PMM_ADC_BATVOLT,
388 +               N810BM_PMM_ADC_CHGVOLT,
389 +               N810BM_PMM_ADC_BKUPVOLT,
390 +               N810BM_PMM_ADC_BATCURR,
391 +       };
392 +       static const enum n810bm_pmm_adc_id pmm_adc_ids_2[] = {
393 +               N810BM_PMM_ADC_BSI,
394 +       };
395 +       static const enum n810bm_pmm_adc_id pmm_adc_ids_3[] = {
396 +               N810BM_PMM_ADC_BATTEMP,
397 +       };
398 +
399 +       /* Parse element 2 */
400 +       err = pmm_record_get(bm, pmm_block, &elem, sizeof(elem),
401 +                            1, 2, 0);
402 +       if (err) {
403 +               dev_err(&bm->pdev->dev,
404 +                       "PMM: Failed to get group 1 / element 2");
405 +               return err;
406 +       }
407 +       if (elem.id == N810BM_PMM_ADC_0xFE && elem.flags == 0x05) {
408 +               adc_calib = n810bm_get_adc_calib(bm, elem.id);
409 +               if (!adc_calib) {
410 +                       dev_err(&bm->pdev->dev,
411 +                               "calib extract: Failed to get 0xFE calib");
412 +                       return -EINVAL;
413 +               }
414 +               adc_calib->id = elem.id;
415 +               adc_calib->flags = elem.flags;
416 +               adc_calib->field1 = le32_to_cpu(elem.field1);
417 +               adc_calib->field2 = le32_to_cpu(elem.field2);
418 +       }
419 +
420 +       err = extract_group1_elem(bm, pmm_block,
421 +                                 pmm_adc_ids_1, ARRAY_SIZE(pmm_adc_ids_1),
422 +                                 0xFFFFFFFF, 0xFFFFFFFF);
423 +       if (err)
424 +               return err;
425 +       err = extract_group1_elem(bm, pmm_block,
426 +                                 pmm_adc_ids_2, ARRAY_SIZE(pmm_adc_ids_2),
427 +                                 0xFFFFFFFF, 0);
428 +       if (err)
429 +               return err;
430 +       err = extract_group1_elem(bm, pmm_block,
431 +                                 pmm_adc_ids_3, ARRAY_SIZE(pmm_adc_ids_3),
432 +                                 0xFFFFFFFF, 0x0000FFFF);
433 +       if (err)
434 +               return err;
435 +
436 +       return 0;
437 +}
438 +
439 +static int n810bm_parse_pmm_group2(struct n810bm *bm,
440 +                                  const struct firmware *pmm_block)
441 +{
442 +       dev_err(&bm->pdev->dev, "TODO: CAL BME PMM group 2 parser not implemented, yet");
443 +       return -EOPNOTSUPP;
444 +}
445 +
446 +static void n810bm_adc_calib_set_defaults(struct n810bm *bm)
447 +{
448 +       struct n810bm_adc_calib *adc_calib;
449 +       unsigned int i;
450 +
451 +       static const struct n810bm_adc_calib defaults[] = {
452 +               /* ADC group-nr 0 */
453 +               {
454 +                       .id             = N810BM_PMM_ADC_HEADSET,
455 +                       .flags          = 0x00,
456 +                       .adc_groupnr    = 0,
457 +               }, {
458 +                       .id             = N810BM_PMM_ADC_HOOKDET,
459 +                       .flags          = 0x00,
460 +                       .adc_groupnr    = 0,
461 +               }, {
462 +                       .id             = N810BM_PMM_ADC_RFGP,
463 +                       .flags          = 0x00,
464 +                       .adc_groupnr    = 0,
465 +               }, {
466 +                       .id             = N810BM_PMM_ADC_LIGHTSENS,
467 +                       .flags          = 0x00,
468 +                       .adc_groupnr    = 0,
469 +               }, {
470 +                       .id             = N810BM_PMM_ADC_WBTX,
471 +                       .flags          = 0x00,
472 +                       .adc_groupnr    = 0,
473 +               }, {
474 +                       .id             = N810BM_PMM_ADC_RETUTEMP,
475 +                       .flags          = 0x00,
476 +                       .adc_groupnr    = 0,
477 +               }, {
478 +                       .id             = N810BM_PMM_ADC_GND2,
479 +                       .flags          = 0x00,
480 +                       .adc_groupnr    = 0,
481 +               },
482 +               /* ADC group-nr 1 */
483 +               {
484 +                       .id             = N810BM_PMM_ADC_0xFE,
485 +                       .flags          = 0x05,
486 +                       .adc_groupnr    = 1,
487 +                       .field1         = (u32)-2,
488 +                       .field2         = 13189,
489 +               }, {
490 +                       .id             = N810BM_PMM_ADC_BATVOLT,
491 +                       .flags          = 0x01,
492 +                       .adc_groupnr    = 1,
493 +                       .field1         = 2527,
494 +                       .field2         = 21373,
495 +               }, {
496 +                       .id             = N810BM_PMM_ADC_CHGVOLT,
497 +                       .flags          = 0x01,
498 +                       .adc_groupnr    = 1,
499 +                       .field1         = 0,
500 +                       .field2         = 129848,
501 +               }, {
502 +                       .id             = N810BM_PMM_ADC_BKUPVOLT,
503 +                       .flags          = 0x01,
504 +                       .adc_groupnr    = 1,
505 +                       .field1         = 0,
506 +                       .field2         = 20000,
507 +               }, {
508 +                       .id             = N810BM_PMM_ADC_BATCURR,
509 +                       .flags          = 0x06,
510 +                       .adc_groupnr    = 1,
511 +                       .field1         = 0,
512 +                       .field2         = 9660,
513 +               },
514 +               /* ADC group-nr 2 */
515 +               {
516 +                       .id             = N810BM_PMM_ADC_BSI,
517 +                       .flags          = 0x02,
518 +                       .adc_groupnr    = 2,
519 +                       .field1         = 1169,
520 +                       .field2         = 0,
521 +               },
522 +               /* ADC group-nr 3 */
523 +               {
524 +                       .id             = N810BM_PMM_ADC_BATTEMP,
525 +                       .flags          = 0x03,
526 +                       .adc_groupnr    = 3,
527 +                       .field1         = 265423000,
528 +                       .field2         = 298,
529 +               },
530 +               /* ADC group-nr 4 */
531 +               {
532 +                       .id             = N810BM_PMM_ADC_LIGHTTEMP,
533 +                       .flags          = 0x04,
534 +                       .adc_groupnr    = 4,
535 +                       .field1         = 19533778,
536 +                       .field2         = 308019670,
537 +                       .field3         = 4700,
538 +                       .field4         = 2500,
539 +               },
540 +       };
541 +
542 +       /* Clear the array */
543 +       memset(&bm->calib.adc, 0, sizeof(bm->calib.adc));
544 +       for (i = 0; i < ARRAY_SIZE(bm->calib.adc); i++)
545 +               bm->calib.adc[i].flags = 0xFF;
546 +
547 +       /* Copy the defaults */
548 +       for (i = 0; i < ARRAY_SIZE(defaults); i++) {
549 +               adc_calib = n810bm_get_adc_calib(bm, defaults[i].id);
550 +               if (WARN_ON(!adc_calib))
551 +                       continue;
552 +               *adc_calib = defaults[i];
553 +       }
554 +}
555 +
556 +static int n810bm_parse_pmm_block(struct n810bm *bm,
557 +                                 const struct firmware *pmm_block)
558 +{
559 +       u8 byte;
560 +       int err;
561 +       unsigned int i, count;
562 +       struct n810bm_adc_calib *adc_calib;
563 +
564 +       /* Initialize to defaults */
565 +       n810bm_adc_calib_set_defaults(bm);
566 +
567 +       /* Parse the PMM data */
568 +       err = pmm_record_get(bm, pmm_block, &byte, sizeof(byte),
569 +                            1, 0, 0); /* group 1 / element 0 */
570 +       err |= (byte != 0x01);
571 +       err |= pmm_record_get(bm, pmm_block, &byte, sizeof(byte),
572 +                             1, 1, 0); /* group 1 / element 1 */
573 +       err |= (byte != 0x01);
574 +       if (err)
575 +               err = n810bm_parse_pmm_group2(bm, pmm_block);
576 +       else
577 +               err = n810bm_parse_pmm_group1(bm, pmm_block);
578 +       if (err)
579 +               return err;
580 +
581 +       /* Sanity checks */
582 +       for (i = 0, count = 0; i < ARRAY_SIZE(bm->calib.adc); i++) {
583 +               adc_calib = &bm->calib.adc[i];
584 +               if (adc_calib->flags == 0xFF)
585 +                       continue;
586 +               switch (adc_calib->id) {
587 +               case N810BM_PMM_ADC_BATVOLT:
588 +                       if (adc_calib->field1 < 2400 ||
589 +                           adc_calib->field1 > 2700)
590 +                               goto value_check_fail;
591 +                       if (adc_calib->field2 < 20000 ||
592 +                           adc_calib->field2 > 23000)
593 +                               goto value_check_fail;
594 +                       count++;
595 +                       break;
596 +               case N810BM_PMM_ADC_BSI:
597 +                       if (adc_calib->field1 < 1100 ||
598 +                           adc_calib->field1 > 1300)
599 +                               goto value_check_fail;
600 +                       count++;
601 +                       break;
602 +               case N810BM_PMM_ADC_BATCURR:
603 +                       if (adc_calib->field2 < 7000 ||
604 +                           adc_calib->field2 > 12000)
605 +                               goto value_check_fail;
606 +                       count++;
607 +                       break;
608 +               case N810BM_PMM_ADC_0xFE:
609 +                       if ((s32)adc_calib->field1 > 14 ||
610 +                           (s32)adc_calib->field1 < -14)
611 +                               goto value_check_fail;
612 +                       if (adc_calib->field2 < 13000 ||
613 +                           adc_calib->field2 > 13350)
614 +                               goto value_check_fail;
615 +                       count++;
616 +                       break;
617 +               case N810BM_PMM_ADC_CHGVOLT:
618 +               case N810BM_PMM_ADC_BATTEMP:
619 +               case N810BM_PMM_ADC_BKUPVOLT:
620 +                       count++;
621 +                       break;
622 +               case N810BM_PMM_ADC_GND2:
623 +               case N810BM_PMM_ADC_HOOKDET:
624 +               case N810BM_PMM_ADC_LIGHTSENS:
625 +               case N810BM_PMM_ADC_HEADSET:
626 +               case N810BM_PMM_ADC_LIGHTTEMP:
627 +               case N810BM_PMM_ADC_RFGP:
628 +               case N810BM_PMM_ADC_WBTX:
629 +               case N810BM_PMM_ADC_RETUTEMP:
630 +                       break;
631 +               }
632 +               dev_dbg(&bm->pdev->dev,
633 +                       "ADC 0x%02X calib: 0x%02X 0x%02X 0x%08X 0x%08X 0x%04X 0x%04X",
634 +                       adc_calib->id, adc_calib->flags, adc_calib->adc_groupnr,
635 +                       adc_calib->field1, adc_calib->field2,
636 +                       adc_calib->field3, adc_calib->field4);
637 +       }
638 +       if (count != 7) {
639 +               dev_err(&bm->pdev->dev, "PMM sanity check: Did not find "
640 +                       "all required values (count=%u)", count);
641 +               goto check_fail;
642 +       }
643 +
644 +       return 0;
645 +
646 +value_check_fail:
647 +       dev_err(&bm->pdev->dev, "PMM image sanity check failed "
648 +               "(id=%02X, field1=%08X, field2=%08X)",
649 +               adc_calib->id, adc_calib->field1, adc_calib->field2);
650 +check_fail:
651 +       return -EILSEQ;
652 +}
653 +
654 +/* Set the current measure timer that triggers on Tahvo IRQ 7
655 + * An interval of zero disables the timer. */
656 +static void n810bm_set_current_measure_timer(struct n810bm *bm,
657 +                                            u16 millisec_interval)
658 +{
659 +       u16 value = millisec_interval;
660 +
661 +       if (value <= 0xF905) {
662 +               value = ((u64)0x10624DD3 * (u64)(value + 0xF9)) >> 32;
663 +               value /= 16;
664 +       } else
665 +               value = 0xFF;
666 +
667 +       tahvo_write(bm, TAHVO_REG_BATCURRTIMER, value & 0xFF);
668 +
669 +       tahvo_set(bm, TAHVO_REG_CHGCTL,
670 +                 TAHVO_REG_CHGCTL_CURTIMRST);
671 +       tahvo_clear(bm, TAHVO_REG_CHGCTL,
672 +                   TAHVO_REG_CHGCTL_CURTIMRST);
673 +
674 +       if (millisec_interval)
675 +               tahvo_enable_irq(TAHVO_INT_BATCURR);
676 +       else
677 +               tahvo_disable_irq(TAHVO_INT_BATCURR);
678 +
679 +       //TODO also do a software timer for safety.
680 +}
681 +
682 +static void n810bm_enable_current_measure(struct n810bm *bm)
683 +{
684 +       WARN_ON(bm->current_measure_enabled < 0);
685 +       if (!bm->current_measure_enabled) {
686 +               /* Enable the current measurement circuitry */
687 +               tahvo_set(bm, TAHVO_REG_CHGCTL,
688 +                         TAHVO_REG_CHGCTL_CURMEAS);
689 +               dev_dbg(&bm->pdev->dev,
690 +                       "Current measurement circuitry enabled");
691 +       }
692 +       bm->current_measure_enabled++;
693 +}
694 +
695 +static void n810bm_disable_current_measure(struct n810bm *bm)
696 +{
697 +       bm->current_measure_enabled--;
698 +       WARN_ON(bm->current_measure_enabled < 0);
699 +       if (!bm->current_measure_enabled) {
700 +               /* Disable the current measurement circuitry */
701 +               tahvo_clear(bm, TAHVO_REG_CHGCTL,
702 +                           TAHVO_REG_CHGCTL_CURMEAS);
703 +               dev_dbg(&bm->pdev->dev,
704 +                       "Current measurement circuitry disabled");
705 +       }
706 +}
707 +
708 +/* Measure the actual battery current. Returns a signed value in mA.
709 + * Does only work, if current measurement was enabled. */
710 +static int n810bm_measure_batt_current(struct n810bm *bm)
711 +{
712 +       u16 retval;
713 +       int adc = 0, ma, i;
714 +
715 +       if (WARN_ON(bm->current_measure_enabled <= 0))
716 +               return 0;
717 +       for (i = 0; i < 3; i++) {
718 +               retval = tahvo_read(bm, TAHVO_REG_BATCURR);
719 +               adc += (s16)retval; /* Value is signed */
720 +       }
721 +       adc /= 3;
722 +
723 +       //TODO convert to mA
724 +       ma = adc;
725 +
726 +       return ma;
727 +}
728 +
729 +/* Requires bm->mutex locked */
730 +static int n810bm_measure_batt_current_async(struct n810bm *bm)
731 +{
732 +       int ma;
733 +       bool charging = lipocharge_is_charging(&bm->charger);
734 +
735 +       n810bm_enable_current_measure(bm);
736 +       if (!charging)
737 +               WARN_ON(bm->active_current_pwm != 0);
738 +       tahvo_maskset(bm, TAHVO_REG_CHGCTL,
739 +                     TAHVO_REG_CHGCTL_EN |
740 +                     TAHVO_REG_CHGCTL_PWMOVR |
741 +                     TAHVO_REG_CHGCTL_PWMOVRZERO,
742 +                     TAHVO_REG_CHGCTL_EN |
743 +                     TAHVO_REG_CHGCTL_PWMOVR |
744 +                     (charging ? 0 : TAHVO_REG_CHGCTL_PWMOVRZERO));
745 +       ma = n810bm_measure_batt_current(bm);
746 +       tahvo_maskset(bm, TAHVO_REG_CHGCTL,
747 +                     TAHVO_REG_CHGCTL_EN |
748 +                     TAHVO_REG_CHGCTL_PWMOVR |
749 +                     TAHVO_REG_CHGCTL_PWMOVRZERO,
750 +                     (charging ? TAHVO_REG_CHGCTL_EN : 0));
751 +       n810bm_disable_current_measure(bm);
752 +
753 +       return ma;
754 +}
755 +
756 +static int adc_sanity_check(struct n810bm *bm, unsigned int channel)
757 +{
758 +       int value;
759 +
760 +       value = retu_read_adc(&n810bm_retu_device->dev, channel);
761 +       if (value < 0) {
762 +               dev_err(&bm->pdev->dev, "Failed to read GND ADC channel %u",
763 +                       channel);
764 +               return -EIO;
765 +       }
766 +       dev_dbg(&bm->pdev->dev,
767 +               "GND ADC channel %u sanity check got value: %d",
768 +               channel, value);
769 +       if (value > 5) {
770 +               n810bm_emergency(bm, "GND ADC sanity check failed");
771 +               return -EIO;
772 +       }
773 +
774 +       return 0;
775 +}
776 +
777 +static int n810bm_check_adc_sanity(struct n810bm *bm)
778 +{
779 +       int err;
780 +
781 +       /* Discard one conversion */
782 +       retu_write(bm, RETU_REG_ADCSCR, 0);
783 +       retu_read_adc(&n810bm_retu_device->dev, RETU_ADC_GND2);
784 +
785 +       err = adc_sanity_check(bm, RETU_ADC_GND2);
786 +       if (err)
787 +               return err;
788 +
789 +       return 0;
790 +}
791 +
792 +/* Measure the battery voltage. Returns the value in mV (or negative value on error). */
793 +static int n810bm_measure_batt_voltage(struct n810bm *bm)
794 +{
795 +       int adc;
796 +       unsigned int mv;
797 +       const unsigned int scale = 1000;
798 +
799 +       adc = retu_adc_average(bm, RETU_ADC_BATTVOLT, 5);
800 +       if (adc < 0)
801 +               return adc;
802 +       if (adc <= 0x37)
803 +               return 2800;
804 +       mv = 2800 + ((adc - 0x37) * (((4200 - 2800) * scale) / (0x236 - 0x37))) / scale;
805 +
806 +       //TODO compensate for power consumption
807 +       //TODO honor calibration values
808 +
809 +       return mv;
810 +}
811 +
812 +/* Measure the charger voltage. Returns the value in mV (or negative value on error). */
813 +static int n810bm_measure_charger_voltage(struct n810bm *bm)
814 +{
815 +       int adc;
816 +       unsigned int mv;
817 +
818 +       adc = retu_adc_average(bm, RETU_ADC_CHGVOLT, 5);
819 +       if (adc < 0)
820 +               return adc;
821 +       //TODO convert to mV
822 +       mv = adc;
823 +
824 +       return mv;
825 +}
826 +
827 +/* Measure backup battery voltage. Returns the value in mV (or negative value on error). */
828 +static int n810bm_measure_backup_batt_voltage(struct n810bm *bm)
829 +{
830 +       int adc;
831 +       unsigned int mv;
832 +
833 +       adc = retu_adc_average(bm, RETU_ADC_BKUPVOLT, 3);
834 +       if (adc < 0)
835 +               return adc;
836 +       //TODO convert to mV
837 +       mv = adc;
838 +
839 +       return mv;
840 +}
841 +
842 +/* Measure the battery temperature. Returns the value in K (or negative value on error). */
843 +static int n810bm_measure_batt_temp(struct n810bm *bm)
844 +{
845 +       int adc;
846 +       unsigned int k;
847 +
848 +       adc = retu_adc_average(bm, RETU_ADC_BATTEMP, 3);
849 +       if (adc < 0)
850 +               return adc;
851 +       //TODO convert to K
852 +       k = adc;
853 +
854 +       return k;
855 +}
856 +
857 +/* Read the battery capacity via BSI pin. */
858 +static enum n810bm_capacity n810bm_read_batt_capacity(struct n810bm *bm)
859 +{
860 +       int adc;
861 +       const unsigned int hyst = 20;
862 +
863 +       adc = retu_adc_average(bm, RETU_ADC_BSI, 5);
864 +       if (adc < 0) {
865 +               dev_err(&bm->pdev->dev, "Failed to read BSI ADC");
866 +               return N810BM_CAP_UNKNOWN;
867 +       }
868 +
869 +       if (adc >= 0x3B5 - hyst && adc <= 0x3B5 + hyst)
870 +               return N810BM_CAP_1500MAH;
871 +
872 +       dev_err(&bm->pdev->dev, "Capacity indicator 0x%X unknown", adc);
873 +
874 +       return N810BM_CAP_UNKNOWN;
875 +}
876 +
877 +/* Convert a battery voltage (in mV) to percentage. */
878 +static unsigned int n810bm_mvolt2percent(unsigned int mv)
879 +{
880 +       const unsigned int minv = 3700;
881 +       const unsigned int maxv = 4150;
882 +       unsigned int percent;
883 +
884 +       mv = clamp(mv, minv, maxv);
885 +       percent = (mv - minv) * 100 / (maxv - minv);
886 +
887 +       return percent;
888 +}
889 +
890 +static void n810bm_start_charge(struct n810bm *bm)
891 +{
892 +       int err;
893 +
894 +       WARN_ON(!bm->battery_present);
895 +       WARN_ON(!bm->charger_present);
896 +
897 +       /* Set PWM to zero */
898 +       bm->active_current_pwm = 0;
899 +       tahvo_write(bm, TAHVO_REG_CHGCURR, bm->active_current_pwm);
900 +
901 +       /* Charge global enable */
902 +       tahvo_maskset(bm, TAHVO_REG_CHGCTL,
903 +                     TAHVO_REG_CHGCTL_EN |
904 +                     TAHVO_REG_CHGCTL_PWMOVR |
905 +                     TAHVO_REG_CHGCTL_PWMOVRZERO,
906 +                     TAHVO_REG_CHGCTL_EN);
907 +
908 +       WARN_ON((int)bm->capacity <= 0);
909 +       bm->charger.capacity = bm->capacity;
910 +       err = lipocharge_start(&bm->charger);
911 +       WARN_ON(err);
912 +
913 +       /* Initialize current measurement circuitry */
914 +       n810bm_enable_current_measure(bm);
915 +       n810bm_set_current_measure_timer(bm, 250);
916 +
917 +       dev_info(&bm->pdev->dev, "Charging battery");
918 +       n810bm_notify_charger_state(bm);
919 +       n810bm_notify_charger_pwm(bm);
920 +}
921 +
922 +static void n810bm_stop_charge(struct n810bm *bm)
923 +{
924 +       if (lipocharge_is_charging(&bm->charger)) {
925 +               n810bm_set_current_measure_timer(bm, 0);
926 +               n810bm_disable_current_measure(bm);
927 +       }
928 +       lipocharge_stop(&bm->charger);
929 +
930 +       /* Set PWM to zero */
931 +       bm->active_current_pwm = 0;
932 +       tahvo_write(bm, TAHVO_REG_CHGCURR, bm->active_current_pwm);
933 +
934 +       /* Charge global disable */
935 +       tahvo_maskset(bm, TAHVO_REG_CHGCTL,
936 +                     TAHVO_REG_CHGCTL_EN |
937 +                     TAHVO_REG_CHGCTL_PWMOVR |
938 +                     TAHVO_REG_CHGCTL_PWMOVRZERO,
939 +                     0);
940 +
941 +       dev_info(&bm->pdev->dev, "Not charging battery");
942 +       n810bm_notify_charger_state(bm);
943 +       n810bm_notify_charger_pwm(bm);
944 +}
945 +
946 +/* Periodic check */
947 +static void n810bm_periodic_check_work(struct work_struct *work)
948 +{
949 +       struct n810bm *bm = container_of(to_delayed_work(work),
950 +                                        struct n810bm, periodic_check_work);
951 +       u16 status;
952 +       bool battery_was_present, charger_was_present;
953 +       int mv;
954 +
955 +       mutex_lock(&bm->mutex);
956 +
957 +       status = retu_read(bm, RETU_REG_STATUS);
958 +       battery_was_present = bm->battery_present;
959 +       charger_was_present = bm->charger_present;
960 +       bm->battery_present = !!(status & RETU_REG_STATUS_BATAVAIL);
961 +       bm->charger_present = !!(status & RETU_REG_STATUS_CHGPLUG);
962 +
963 +       if (bm->battery_present != battery_was_present) {
964 +               /* Battery state changed */
965 +               if (bm->battery_present) {
966 +                       bm->capacity = n810bm_read_batt_capacity(bm);
967 +                       if (bm->capacity == N810BM_CAP_UNKNOWN) {
968 +                               dev_err(&bm->pdev->dev, "Unknown battery detected");
969 +                       } else {
970 +                               dev_info(&bm->pdev->dev, "Detected %u mAh battery",
971 +                                        (unsigned int)bm->capacity);
972 +                       }
973 +               } else {
974 +                       bm->capacity = N810BM_CAP_NONE;
975 +                       dev_info(&bm->pdev->dev, "The main battery was removed");
976 +                       //TODO disable charging
977 +               }
978 +       }
979 +
980 +       if (bm->charger_present != charger_was_present) {
981 +               /* Charger state changed */
982 +               dev_info(&bm->pdev->dev, "The charger was %s",
983 +                        bm->charger_present ? "plugged in" : "removed");
984 +               n810bm_notify_charger_present(bm);
985 +       }
986 +
987 +       if ((bm->battery_present && !bm->charger_present) ||
988 +           !n810bm_known_battery_present(bm)){
989 +               /* We're draining the battery */
990 +               mv = n810bm_measure_batt_voltage(bm);
991 +               if (mv < 0) {
992 +                       n810bm_emergency(bm,
993 +                               "check: Failed to measure voltage");
994 +               }
995 +               if (mv < N810BM_MIN_VOLTAGE_THRES) {
996 +                       n810bm_emergency(bm,
997 +                               "check: Minimum voltage threshold reached");
998 +               }
999 +       }
1000 +
1001 +       if (bm->charger_present && n810bm_known_battery_present(bm)) {
1002 +               /* Known battery and charger are connected */
1003 +               if (bm->charger_enabled) {
1004 +                       /* Charger is enabled */
1005 +                       if (!lipocharge_is_charging(&bm->charger)) {
1006 +                               //TODO start charging, if battery is below some threshold
1007 +                               n810bm_start_charge(bm);
1008 +                       }
1009 +               }
1010 +       }
1011 +
1012 +       if (lipocharge_is_charging(&bm->charger) && !bm->charger_present) {
1013 +               /* Charger was unplugged. */
1014 +               n810bm_stop_charge(bm);
1015 +       }
1016 +
1017 +       mutex_unlock(&bm->mutex);
1018 +       schedule_delayed_work(&bm->periodic_check_work,
1019 +                             round_jiffies_relative(N810BM_CHECK_INTERVAL));
1020 +}
1021 +
1022 +/*XXX
1023 +static void n810bm_adc_irq_handler(unsigned long data)
1024 +{
1025 +       struct n810bm *bm = (struct n810bm *)data;
1026 +
1027 +       retu_ack_irq(RETU_INT_ADCS);
1028 +       //TODO
1029 +dev_info(&bm->pdev->dev, "ADC interrupt triggered\n");
1030 +}
1031 +*/
1032 +
1033 +static void n810bm_tahvo_current_measure_work(struct work_struct *work)
1034 +{
1035 +       struct n810bm *bm = container_of(work, struct n810bm, currmeas_irq_work);
1036 +       int res, ma, mv, temp;
1037 +
1038 +       mutex_lock(&bm->mutex);
1039 +       if (!lipocharge_is_charging(&bm->charger))
1040 +               goto out_unlock;
1041 +
1042 +       tahvo_maskset(bm, TAHVO_REG_CHGCTL,
1043 +                     TAHVO_REG_CHGCTL_PWMOVR |
1044 +                     TAHVO_REG_CHGCTL_PWMOVRZERO,
1045 +                     TAHVO_REG_CHGCTL_PWMOVR);
1046 +       ma = n810bm_measure_batt_current(bm);
1047 +       tahvo_maskset(bm, TAHVO_REG_CHGCTL,
1048 +                     TAHVO_REG_CHGCTL_PWMOVR |
1049 +                     TAHVO_REG_CHGCTL_PWMOVRZERO,
1050 +                     TAHVO_REG_CHGCTL_PWMOVR |
1051 +                     TAHVO_REG_CHGCTL_PWMOVRZERO);
1052 +       msleep(10);
1053 +       mv = n810bm_measure_batt_voltage(bm);
1054 +       tahvo_maskset(bm, TAHVO_REG_CHGCTL,
1055 +                     TAHVO_REG_CHGCTL_PWMOVR |
1056 +                     TAHVO_REG_CHGCTL_PWMOVRZERO,
1057 +                     0);
1058 +       temp = n810bm_measure_batt_temp(bm);
1059 +       if (WARN_ON(mv < 0))
1060 +               goto out_unlock;
1061 +       if (WARN_ON(temp < 0))
1062 +               goto out_unlock;
1063 +
1064 +       if (bm->verbose_charge_log) {
1065 +               dev_info(&bm->pdev->dev,
1066 +                        "Battery charge state: %d mV, %d mA (%s)",
1067 +                        mv, ma,
1068 +                        (ma <= 0) ? "discharging" : "charging");
1069 +       }
1070 +       res = lipocharge_update_state(&bm->charger, mv, ma, temp);
1071 +       if (res) {
1072 +               if (res > 0)
1073 +                       dev_info(&bm->pdev->dev, "Battery fully charged");
1074 +               n810bm_stop_charge(bm);
1075 +       }
1076 +out_unlock:
1077 +       mutex_unlock(&bm->mutex);
1078 +}
1079 +
1080 +static void n810bm_tahvo_current_measure_irq_handler(unsigned long data)
1081 +{
1082 +       struct n810bm *bm = (struct n810bm *)data;
1083 +
1084 +       tahvo_ack_irq(TAHVO_INT_BATCURR);
1085 +       schedule_work(&bm->currmeas_irq_work);
1086 +}
1087 +
1088 +#define DEFINE_ATTR_NOTIFY(attr_name)                                          \
1089 +       void n810bm_notify_##attr_name(struct n810bm *bm)                       \
1090 +       {                                                                       \
1091 +               set_bit(N810BM_NOTIFY_##attr_name, &bm->notify_flags);          \
1092 +               wmb();                                                          \
1093 +               schedule_work(&bm->notify_work);                                \
1094 +       }
1095 +
1096 +#define DEFINE_SHOW_INT_FUNC(name, member)                                     \
1097 +       static ssize_t n810bm_attr_##name##_show(struct device *dev,            \
1098 +                                                struct device_attribute *attr, \
1099 +                                                char *buf)                     \
1100 +       {                                                                       \
1101 +               struct n810bm *bm = device_to_n810bm(dev);                      \
1102 +               ssize_t count;                                                  \
1103 +                                                                               \
1104 +               mutex_lock(&bm->mutex);                                         \
1105 +               count = snprintf(buf, PAGE_SIZE, "%d\n", (int)(bm->member));    \
1106 +               mutex_unlock(&bm->mutex);                                       \
1107 +                                                                               \
1108 +               return count;                                                   \
1109 +       }
1110 +
1111 +#define DEFINE_STORE_INT_FUNC(name, member)                                    \
1112 +       static ssize_t n810bm_attr_##name##_store(struct device *dev,           \
1113 +                                                 struct device_attribute *attr,\
1114 +                                                 const char *buf, size_t count)\
1115 +       {                                                                       \
1116 +               struct n810bm *bm = device_to_n810bm(dev);                      \
1117 +               long val;                                                       \
1118 +               int err;                                                        \
1119 +                                                                               \
1120 +               mutex_lock(&bm->mutex);                                         \
1121 +               err = strict_strtol(buf, 0, &val);                              \
1122 +               if (!err)                                                       \
1123 +                       bm->member = (typeof(bm->member))val;                   \
1124 +               mutex_unlock(&bm->mutex);                                       \
1125 +                                                                               \
1126 +               return err ? err : count;                                       \
1127 +       }
1128 +
1129 +#define DEFINE_ATTR_SHOW_INT(name, member)                                     \
1130 +       DEFINE_SHOW_INT_FUNC(name, member)                                      \
1131 +       static DEVICE_ATTR(name, S_IRUGO,                                       \
1132 +                          n810bm_attr_##name##_show, NULL);
1133 +
1134 +#define DEFINE_ATTR_SHOW_STORE_INT(name, member)                               \
1135 +       DEFINE_SHOW_INT_FUNC(name, member)                                      \
1136 +       DEFINE_STORE_INT_FUNC(name, member)                                     \
1137 +       static DEVICE_ATTR(name, S_IRUGO | S_IWUSR,                             \
1138 +                          n810bm_attr_##name##_show,                           \
1139 +                          n810bm_attr_##name##_store);
1140 +
1141 +DEFINE_ATTR_SHOW_INT(battery_present, battery_present);
1142 +DEFINE_ATTR_SHOW_INT(charger_present, charger_present);
1143 +static DEFINE_ATTR_NOTIFY(charger_present);
1144 +DEFINE_ATTR_SHOW_INT(charger_state, charger.state);
1145 +static DEFINE_ATTR_NOTIFY(charger_state);
1146 +DEFINE_ATTR_SHOW_INT(charger_pwm, active_current_pwm);
1147 +static DEFINE_ATTR_NOTIFY(charger_pwm);
1148 +DEFINE_ATTR_SHOW_STORE_INT(charger_enable, charger_enabled);
1149 +DEFINE_ATTR_SHOW_STORE_INT(charger_verbose, verbose_charge_log);
1150 +
1151 +static ssize_t n810bm_attr_battery_level_show(struct device *dev,
1152 +                                             struct device_attribute *attr,
1153 +                                             char *buf)
1154 +{
1155 +       struct n810bm *bm = device_to_n810bm(dev);
1156 +       ssize_t count = -ENODEV;
1157 +       int millivolt;
1158 +
1159 +       mutex_lock(&bm->mutex);
1160 +       if (!bm->battery_present || lipocharge_is_charging(&bm->charger))
1161 +               millivolt = 0;
1162 +       else
1163 +               millivolt = n810bm_measure_batt_voltage(bm);
1164 +       if (millivolt >= 0) {
1165 +               count = snprintf(buf, PAGE_SIZE, "%u\n",
1166 +                                n810bm_mvolt2percent(millivolt));
1167 +       }
1168 +       mutex_unlock(&bm->mutex);
1169 +
1170 +       return count;
1171 +}
1172 +static DEVICE_ATTR(battery_level, S_IRUGO,
1173 +                  n810bm_attr_battery_level_show, NULL);
1174 +
1175 +static ssize_t n810bm_attr_battery_capacity_show(struct device *dev,
1176 +                                                struct device_attribute *attr,
1177 +                                                char *buf)
1178 +{
1179 +       struct n810bm *bm = device_to_n810bm(dev);
1180 +       ssize_t count;
1181 +       int capacity = 0;
1182 +
1183 +       mutex_lock(&bm->mutex);
1184 +       if (n810bm_known_battery_present(bm))
1185 +               capacity = (int)bm->capacity;
1186 +       count = snprintf(buf, PAGE_SIZE, "%d\n", capacity);
1187 +       mutex_unlock(&bm->mutex);
1188 +
1189 +       return count;
1190 +}
1191 +static DEVICE_ATTR(battery_capacity, S_IRUGO,
1192 +                  n810bm_attr_battery_capacity_show, NULL);
1193 +
1194 +static ssize_t n810bm_attr_battery_temp_show(struct device *dev,
1195 +                                            struct device_attribute *attr,
1196 +                                            char *buf)
1197 +{
1198 +       struct n810bm *bm = device_to_n810bm(dev);
1199 +       ssize_t count = -ENODEV;
1200 +       int k;
1201 +
1202 +       mutex_lock(&bm->mutex);
1203 +       k = n810bm_measure_batt_temp(bm);
1204 +       if (k >= 0)
1205 +               count = snprintf(buf, PAGE_SIZE, "%d\n", k);
1206 +       mutex_unlock(&bm->mutex);
1207 +
1208 +       return count;
1209 +}
1210 +static DEVICE_ATTR(battery_temp, S_IRUGO,
1211 +                  n810bm_attr_battery_temp_show, NULL);
1212 +
1213 +static ssize_t n810bm_attr_charger_voltage_show(struct device *dev,
1214 +                                               struct device_attribute *attr,
1215 +                                               char *buf)
1216 +{
1217 +       struct n810bm *bm = device_to_n810bm(dev);
1218 +       ssize_t count = -ENODEV;
1219 +       int mv = 0;
1220 +
1221 +       mutex_lock(&bm->mutex);
1222 +       if (bm->charger_present)
1223 +               mv = n810bm_measure_charger_voltage(bm);
1224 +       if (mv >= 0)
1225 +               count = snprintf(buf, PAGE_SIZE, "%d\n", mv);
1226 +       mutex_unlock(&bm->mutex);
1227 +
1228 +       return count;
1229 +}
1230 +static DEVICE_ATTR(charger_voltage, S_IRUGO,
1231 +                  n810bm_attr_charger_voltage_show, NULL);
1232 +
1233 +static ssize_t n810bm_attr_backup_battery_voltage_show(struct device *dev,
1234 +                                                      struct device_attribute *attr,
1235 +                                                      char *buf)
1236 +{
1237 +       struct n810bm *bm = device_to_n810bm(dev);
1238 +       ssize_t count = -ENODEV;
1239 +       int mv;
1240 +
1241 +       mutex_lock(&bm->mutex);
1242 +       mv = n810bm_measure_backup_batt_voltage(bm);
1243 +       if (mv >= 0)
1244 +               count = snprintf(buf, PAGE_SIZE, "%d\n", mv);
1245 +       mutex_unlock(&bm->mutex);
1246 +
1247 +       return count;
1248 +}
1249 +static DEVICE_ATTR(backup_battery_voltage, S_IRUGO,
1250 +                  n810bm_attr_backup_battery_voltage_show, NULL);
1251 +
1252 +static ssize_t n810bm_attr_battery_current_show(struct device *dev,
1253 +                                               struct device_attribute *attr,
1254 +                                               char *buf)
1255 +{
1256 +       struct n810bm *bm = device_to_n810bm(dev);
1257 +       ssize_t count = -ENODEV;
1258 +       int ma = 0;
1259 +
1260 +       mutex_lock(&bm->mutex);
1261 +       if (bm->battery_present)
1262 +               ma = n810bm_measure_batt_current_async(bm);
1263 +       count = snprintf(buf, PAGE_SIZE, "%d\n", ma);
1264 +       mutex_unlock(&bm->mutex);
1265 +
1266 +       return count;
1267 +}
1268 +static DEVICE_ATTR(battery_current, S_IRUGO,
1269 +                  n810bm_attr_battery_current_show, NULL);
1270 +
1271 +static const struct device_attribute *n810bm_attrs[] = {
1272 +       &dev_attr_battery_present,
1273 +       &dev_attr_battery_level,
1274 +       &dev_attr_battery_current,
1275 +       &dev_attr_battery_capacity,
1276 +       &dev_attr_battery_temp,
1277 +       &dev_attr_backup_battery_voltage,
1278 +       &dev_attr_charger_present,
1279 +       &dev_attr_charger_state,
1280 +       &dev_attr_charger_verbose,
1281 +       &dev_attr_charger_voltage,
1282 +       &dev_attr_charger_enable,
1283 +       &dev_attr_charger_pwm,
1284 +};
1285 +
1286 +static void n810bm_notify_work(struct work_struct *work)
1287 +{
1288 +       struct n810bm *bm = container_of(work, struct n810bm, notify_work);
1289 +       unsigned long notify_flags;
1290 +
1291 +       notify_flags = xchg(&bm->notify_flags, 0);
1292 +       mb();
1293 +
1294 +#define do_notify(attr_name)                                           \
1295 +       do {                                                            \
1296 +               if (notify_flags & (1 << N810BM_NOTIFY_##attr_name)) {  \
1297 +                       sysfs_notify(&bm->pdev->dev.kobj, NULL,         \
1298 +                                    dev_attr_##attr_name.attr.name);   \
1299 +               }                                                       \
1300 +       } while (0)
1301 +
1302 +       do_notify(charger_present);
1303 +       do_notify(charger_state);
1304 +       do_notify(charger_pwm);
1305 +}
1306 +
1307 +static int n810bm_charger_set_current_pwm(struct lipocharge *c,
1308 +                                         unsigned int duty_cycle)
1309 +{
1310 +       struct n810bm *bm = container_of(c, struct n810bm, charger);
1311 +       int err = -EINVAL;
1312 +
1313 +       WARN_ON(!mutex_is_locked(&bm->mutex));
1314 +       if (WARN_ON(duty_cycle > 0xFF))
1315 +               goto out;
1316 +       if (WARN_ON(!bm->charger_enabled))
1317 +               goto out;
1318 +       if (WARN_ON(!bm->battery_present || !bm->charger_present))
1319 +               goto out;
1320 +
1321 +       if (duty_cycle != bm->active_current_pwm) {
1322 +               bm->active_current_pwm = duty_cycle;
1323 +               tahvo_write(bm, TAHVO_REG_CHGCURR, duty_cycle);
1324 +               n810bm_notify_charger_pwm(bm);
1325 +       }
1326 +
1327 +       err = 0;
1328 +out:
1329 +
1330 +       return err;
1331 +}
1332 +
1333 +static void n810bm_charger_emergency(struct lipocharge *c)
1334 +{
1335 +       struct n810bm *bm = container_of(c, struct n810bm, charger);
1336 +
1337 +       n810bm_emergency(bm, "Battery charger fault");
1338 +}
1339 +
1340 +static void n810bm_hw_exit(struct n810bm *bm)
1341 +{
1342 +       n810bm_stop_charge(bm);
1343 +       retu_write(bm, RETU_REG_ADCSCR, 0);
1344 +}
1345 +
1346 +static int n810bm_hw_init(struct n810bm *bm)
1347 +{
1348 +       int err;
1349 +
1350 +       err = n810bm_check_adc_sanity(bm);
1351 +       if (err)
1352 +               return err;
1353 +
1354 +       n810bm_stop_charge(bm);
1355 +
1356 +       return 0;
1357 +}
1358 +
1359 +static void n810bm_cancel_and_flush_work(struct n810bm *bm)
1360 +{
1361 +       cancel_delayed_work_sync(&bm->periodic_check_work);
1362 +       cancel_work_sync(&bm->notify_work);
1363 +       cancel_work_sync(&bm->currmeas_irq_work);
1364 +       flush_scheduled_work();
1365 +}
1366 +
1367 +static int n810bm_device_init(struct n810bm *bm)
1368 +{
1369 +       int attr_index;
1370 +       int err;
1371 +
1372 +       bm->charger.rate = LIPORATE_p6C;
1373 +       bm->charger.top_voltage = 4100;
1374 +       bm->charger.duty_cycle_max = 0xFF;
1375 +       bm->charger.set_current_pwm = n810bm_charger_set_current_pwm;
1376 +       bm->charger.emergency = n810bm_charger_emergency;
1377 +       lipocharge_init(&bm->charger, &bm->pdev->dev);
1378 +
1379 +       err = n810bm_hw_init(bm);
1380 +       if (err)
1381 +               goto error;
1382 +       for (attr_index = 0; attr_index < ARRAY_SIZE(n810bm_attrs); attr_index++) {
1383 +               err = device_create_file(&bm->pdev->dev, n810bm_attrs[attr_index]);
1384 +               if (err)
1385 +                       goto err_unwind_attrs;
1386 +       }
1387 +/*XXX
1388 +       err = retu_request_irq(RETU_INT_ADCS,
1389 +                              n810bm_adc_irq_handler,
1390 +                              (unsigned long)bm, "n810bm");
1391 +       if (err)
1392 +               goto err_unwind_attrs;
1393 +*/
1394 +       err = tahvo_request_irq(TAHVO_INT_BATCURR,
1395 +                               n810bm_tahvo_current_measure_irq_handler,
1396 +                               (unsigned long)bm, "n810bm");
1397 +       if (err)
1398 +               goto err_free_retu_irq;
1399 +       tahvo_disable_irq(TAHVO_INT_BATCURR);
1400 +
1401 +       schedule_delayed_work(&bm->periodic_check_work,
1402 +                             round_jiffies_relative(N810BM_CHECK_INTERVAL));
1403 +
1404 +       bm->initialized = 1;
1405 +       dev_info(&bm->pdev->dev, "Battery management initialized");
1406 +
1407 +       return 0;
1408 +
1409 +err_free_retu_irq:
1410 +//XXX  retu_free_irq(RETU_INT_ADCS);
1411 +err_unwind_attrs:
1412 +       for (attr_index--; attr_index >= 0; attr_index--)
1413 +               device_remove_file(&bm->pdev->dev, n810bm_attrs[attr_index]);
1414 +/*err_exit:*/
1415 +       n810bm_hw_exit(bm);
1416 +error:
1417 +       n810bm_cancel_and_flush_work(bm);
1418 +
1419 +       return err;
1420 +}
1421 +
1422 +static void n810bm_device_exit(struct n810bm *bm)
1423 +{
1424 +       int i;
1425 +
1426 +       if (!bm->initialized)
1427 +               return;
1428 +
1429 +       lipocharge_exit(&bm->charger);
1430 +       tahvo_free_irq(TAHVO_INT_BATCURR);
1431 +//XXX  retu_free_irq(RETU_INT_ADCS);
1432 +       for (i = 0; i < ARRAY_SIZE(n810bm_attrs); i++)
1433 +               device_remove_file(&bm->pdev->dev, n810bm_attrs[i]);
1434 +
1435 +       n810bm_cancel_and_flush_work(bm);
1436 +
1437 +       n810bm_hw_exit(bm);
1438 +
1439 +       bm->initialized = 0;
1440 +}
1441 +
1442 +static void n810bm_pmm_block_found(const struct firmware *fw, void *context)
1443 +{
1444 +       struct n810bm *bm = context;
1445 +       int err;
1446 +
1447 +       if (!fw) {
1448 +               dev_err(&bm->pdev->dev,
1449 +                       "CAL PMM block image file not found");
1450 +               goto err_release;
1451 +       }
1452 +       if (fw->size != N810BM_PMM_BLOCK_SIZE ||
1453 +           memcmp(fw->data, "BME-PMM-BLOCK01", 15) != 0) {
1454 +               dev_err(&bm->pdev->dev,
1455 +                       "CAL PMM block image file has an invalid format");
1456 +               goto err_release;
1457 +       }
1458 +
1459 +       err = n810bm_parse_pmm_block(bm, fw);
1460 +       if (err)
1461 +               goto err_release;
1462 +       release_firmware(fw);
1463 +
1464 +       err = n810bm_device_init(bm);
1465 +       if (err) {
1466 +               dev_err(&bm->pdev->dev,
1467 +                       "Failed to initialized battery management (%d)", err);
1468 +               goto error;
1469 +       }
1470 +
1471 +       return;
1472 +err_release:
1473 +       release_firmware(fw);
1474 +error:
1475 +       return;
1476 +}
1477 +
1478 +static int __devinit n810bm_probe(void)
1479 +{
1480 +       struct n810bm *bm;
1481 +       int err;
1482 +
1483 +       if (!n810bm_retu_device || !n810bm_tahvo_device)
1484 +               return 0;
1485 +
1486 +       bm = kzalloc(sizeof(*bm), GFP_KERNEL);
1487 +       if (!bm)
1488 +               return -ENOMEM;
1489 +       bm->pdev = n810bm_retu_device;
1490 +       platform_set_drvdata(n810bm_retu_device, bm);
1491 +       platform_set_drvdata(n810bm_tahvo_device, bm);
1492 +       mutex_init(&bm->mutex);
1493 +       INIT_DELAYED_WORK(&bm->periodic_check_work, n810bm_periodic_check_work);
1494 +       INIT_WORK(&bm->notify_work, n810bm_notify_work);
1495 +       INIT_WORK(&bm->currmeas_irq_work, n810bm_tahvo_current_measure_work);
1496 +
1497 +       dev_info(&bm->pdev->dev, "Requesting CAL BME PMM block firmware file "
1498 +                N810BM_PMM_BLOCK_FILENAME);
1499 +       err = request_firmware_nowait(THIS_MODULE, 1,
1500 +                                     N810BM_PMM_BLOCK_FILENAME,
1501 +                                     &bm->pdev->dev, GFP_KERNEL,
1502 +                                     bm, n810bm_pmm_block_found);
1503 +       if (err) {
1504 +               dev_err(&bm->pdev->dev,
1505 +                       "Failed to request CAL PMM block image file (%d)", err);
1506 +               goto err_free;
1507 +       }
1508 +
1509 +       return 0;
1510 +
1511 +err_free:
1512 +       kfree(bm);
1513 +
1514 +       return err;
1515 +}
1516 +
1517 +static void __devexit n810bm_remove(void)
1518 +{
1519 +       struct n810bm *bm;
1520 +
1521 +       if (!n810bm_retu_device || !n810bm_tahvo_device)
1522 +               return;
1523 +       bm = platform_get_drvdata(n810bm_retu_device);
1524 +
1525 +       n810bm_device_exit(bm);
1526 +
1527 +       kfree(bm);
1528 +       platform_set_drvdata(n810bm_retu_device, NULL);
1529 +       platform_set_drvdata(n810bm_tahvo_device, NULL);
1530 +}
1531 +
1532 +static int __devinit n810bm_retu_probe(struct platform_device *pdev)
1533 +{
1534 +       n810bm_retu_device = pdev;
1535 +       return n810bm_probe();
1536 +}
1537 +
1538 +static int __devexit n810bm_retu_remove(struct platform_device *pdev)
1539 +{
1540 +       n810bm_remove();
1541 +       n810bm_retu_device = NULL;
1542 +       return 0;
1543 +}
1544 +
1545 +static int __devinit n810bm_tahvo_probe(struct platform_device *pdev)
1546 +{
1547 +       n810bm_tahvo_device = pdev;
1548 +       return n810bm_probe();
1549 +}
1550 +
1551 +static int __devexit n810bm_tahvo_remove(struct platform_device *pdev)
1552 +{
1553 +       n810bm_remove();
1554 +       n810bm_tahvo_device = NULL;
1555 +       return 0;
1556 +}
1557 +
1558 +static struct platform_driver n810bm_retu_driver = {
1559 +       .remove         = __devexit_p(n810bm_retu_remove),
1560 +       .driver         = {
1561 +               .name   = "retu-n810bm",
1562 +       }
1563 +};
1564 +
1565 +static struct platform_driver n810bm_tahvo_driver = {
1566 +       .remove         = __devexit_p(n810bm_tahvo_remove),
1567 +       .driver         = {
1568 +               .name   = "tahvo-n810bm",
1569 +       }
1570 +};
1571 +
1572 +/* FIXME: for now alloc the device here... */
1573 +static struct platform_device n810bm_tahvo_dev = {
1574 +       .name   = "tahvo-n810bm",
1575 +       .id     = -1,
1576 +};
1577 +
1578 +static int __init n810bm_modinit(void)
1579 +{
1580 +       int err;
1581 +
1582 +       //FIXME
1583 +       err = platform_device_register(&n810bm_tahvo_dev);
1584 +       if (err)
1585 +               return err;
1586 +
1587 +       err = platform_driver_probe(&n810bm_retu_driver, n810bm_retu_probe);
1588 +       if (err)
1589 +               return err;
1590 +       err = platform_driver_probe(&n810bm_tahvo_driver, n810bm_tahvo_probe);
1591 +       if (err) {
1592 +               platform_driver_unregister(&n810bm_retu_driver);
1593 +               return err;
1594 +       }
1595 +
1596 +       return 0;
1597 +}
1598 +module_init(n810bm_modinit);
1599 +
1600 +static void __exit n810bm_modexit(void)
1601 +{
1602 +       //FIXME
1603 +       platform_device_unregister(&n810bm_tahvo_dev);
1604 +
1605 +       platform_driver_unregister(&n810bm_tahvo_driver);
1606 +       platform_driver_unregister(&n810bm_retu_driver);
1607 +}
1608 +module_exit(n810bm_modexit);
1609 +
1610 +MODULE_DESCRIPTION("Nokia n810 battery management");
1611 +MODULE_FIRMWARE(N810BM_PMM_BLOCK_FILENAME);
1612 +MODULE_LICENSE("GPL");
1613 +MODULE_AUTHOR("Michael Buesch");
1614 --- /dev/null
1615 +++ b/drivers/cbus/lipocharge.c
1616 @@ -0,0 +1,183 @@
1617 +/*
1618 + *   Generic LIPO battery charger
1619 + *
1620 + *   Copyright (c) 2010-2011 Michael Buesch <mb@bu3sch.de>
1621 + *
1622 + *   This program is free software; you can redistribute it and/or
1623 + *   modify it under the terms of the GNU General Public License
1624 + *   as published by the Free Software Foundation; either version 2
1625 + *   of the License, or (at your option) any later version.
1626 + *
1627 + *   This program is distributed in the hope that it will be useful,
1628 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
1629 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1630 + *   GNU General Public License for more details.
1631 + */
1632 +
1633 +#define DEBUG
1634 +
1635 +#include "lipocharge.h"
1636 +
1637 +#include <linux/slab.h>
1638 +
1639 +
1640 +/* Hysteresis constants */
1641 +#define CURRENT_HYST           30 /* mA */
1642 +#define VOLTAGE_HYST           10 /* mV */
1643 +
1644 +/* Threshold constants */
1645 +#define FINISH_CURRENT_PERCENT 3
1646 +
1647 +
1648 +/* Returns the requested first-stage charge current in mA */
1649 +static inline unsigned int get_stage1_charge_current(struct lipocharge *c)
1650 +{
1651 +       /* current = (capacity * C) */
1652 +       return c->capacity * c->rate / 1000;
1653 +}
1654 +
1655 +void lipocharge_init(struct lipocharge *c, struct device *dev)
1656 +{
1657 +       c->dev = dev;
1658 +       c->state = LIPO_IDLE;
1659 +}
1660 +
1661 +void lipocharge_exit(struct lipocharge *c)
1662 +{
1663 +       c->state = LIPO_IDLE;
1664 +}
1665 +
1666 +int lipocharge_start(struct lipocharge *c)
1667 +{
1668 +       int err;
1669 +
1670 +       if (c->state != LIPO_IDLE)
1671 +               return -EBUSY;
1672 +       if (!c->set_current_pwm || !c->emergency)
1673 +               return -EINVAL;
1674 +       if (!c->top_voltage || c->top_voltage > 4200)
1675 +               return -EINVAL;
1676 +
1677 +       c->active_duty_cycle = 0;
1678 +       err = c->set_current_pwm(c, c->active_duty_cycle);
1679 +       if (err)
1680 +               return err;
1681 +       c->state = LIPO_FIRST_STAGE;
1682 +
1683 +       return 0;
1684 +}
1685 +
1686 +void lipocharge_stop(struct lipocharge *c)
1687 +{
1688 +       if (c->state == LIPO_IDLE)
1689 +               return;
1690 +       c->state = LIPO_IDLE;
1691 +}
1692 +
1693 +static int lipocharge_increase_current(struct lipocharge *c,
1694 +                                      unsigned int inc_permille)
1695 +{
1696 +       int old_pwm, new_pwm;
1697 +
1698 +       if (c->active_duty_cycle >= c->duty_cycle_max)
1699 +               return 0;
1700 +
1701 +       old_pwm = c->active_duty_cycle;
1702 +       new_pwm = old_pwm + (c->duty_cycle_max * inc_permille / 1000);
1703 +       new_pwm = min(new_pwm, (int)c->duty_cycle_max);
1704 +       c->active_duty_cycle = new_pwm;
1705 +
1706 +       dev_dbg(c->dev, "lipo: Increasing duty_cycle by "
1707 +               "%u permille (0x%02X -> 0x%02X)",
1708 +               inc_permille, old_pwm, new_pwm);
1709 +
1710 +       return c->set_current_pwm(c, c->active_duty_cycle);
1711 +}
1712 +
1713 +static int lipocharge_decrease_current(struct lipocharge *c,
1714 +                                      unsigned int dec_permille)
1715 +{
1716 +       int old_pwm, new_pwm;
1717 +
1718 +       if (c->active_duty_cycle <= 0)
1719 +               return 0;
1720 +
1721 +       old_pwm = c->active_duty_cycle;
1722 +       new_pwm = old_pwm - (c->duty_cycle_max * dec_permille / 1000);
1723 +       new_pwm = max(0, new_pwm);
1724 +       c->active_duty_cycle = new_pwm;
1725 +
1726 +       dev_dbg(c->dev, "lipo: Decreasing duty_cycle by "
1727 +               "%u permille (0x%02X -> 0x%02X)",
1728 +               dec_permille, old_pwm, new_pwm);
1729 +
1730 +       return c->set_current_pwm(c, c->active_duty_cycle);
1731 +}
1732 +
1733 +/** lipocharge_update_state - Update the charge state
1734 + * @c: The context.
1735 + * @voltage_mV: The measured battery voltage.
1736 + * @current_mA: The measured charge current.
1737 + *             negative -> drain.
1738 + *             positive -> charge.
1739 + * @temp_K: Battery temperature in K.
1740 + *
1741 + * Returns 0 on success, -1 on error.
1742 + * Returns 1, if the charging process is finished.
1743 + */
1744 +int lipocharge_update_state(struct lipocharge *c,
1745 +                           unsigned int voltage_mV,
1746 +                           int current_mA,
1747 +                           unsigned int temp_K)
1748 +{
1749 +       int requested_current, current_diff;
1750 +       int err;
1751 +       unsigned int permille;
1752 +
1753 +       //TODO temp
1754 +
1755 +restart:
1756 +       switch (c->state) {
1757 +       case LIPO_IDLE:
1758 +               dev_err(c->dev, "%s: called while idle", __func__);
1759 +               return -EINVAL;
1760 +       case LIPO_FIRST_STAGE:  /* Constant current */
1761 +//printk("GOT %u %d %u\n", voltage_mV, current_mA, temp_K);
1762 +               if (voltage_mV >= c->top_voltage) {
1763 +                       /* Float voltage reached.
1764 +                        * Switch charger mode to "constant current" */
1765 +                       c->state = LIPO_SECOND_STAGE;
1766 +                       dev_dbg(c->dev, "Switched to second charging stage.");
1767 +                       goto restart;
1768 +               }
1769 +               /* Float voltage not reached, yet.
1770 +                * Try to get the requested constant current. */
1771 +               requested_current = get_stage1_charge_current(c);
1772 +               if (current_mA < 0)
1773 +                       current_mA = 0;
1774 +               current_diff = requested_current - current_mA;
1775 +               if (abs(requested_current - current_mA) > CURRENT_HYST) {
1776 +                       if (current_diff > 0) {
1777 +                               /* Increase current */
1778 +                               permille = current_diff * 1000 / requested_current;
1779 +                               permille /= 2;
1780 +                               err = lipocharge_increase_current(c, permille);
1781 +                               if (err)
1782 +                                       return err;
1783 +                       } else {
1784 +                               /* Decrease current */
1785 +                               permille = (-current_diff) * 1000 / requested_current;
1786 +                               permille /= 2;
1787 +                               err = lipocharge_decrease_current(c, permille);
1788 +                               if (err)
1789 +                                       return err;
1790 +                       }
1791 +               }
1792 +               break;
1793 +       case LIPO_SECOND_STAGE: /* Constant voltage */
1794 +               //TODO
1795 +               break;
1796 +       }
1797 +
1798 +       return 0;
1799 +}
1800 --- /dev/null
1801 +++ b/drivers/cbus/lipocharge.h
1802 @@ -0,0 +1,60 @@
1803 +#ifndef LIPOCHARGE_H_
1804 +#define LIPOCHARGE_H_
1805 +
1806 +#include <linux/types.h>
1807 +#include <linux/device.h>
1808 +
1809 +
1810 +#define LIPORATE(a,b)  (((a) * 1000) + ((b) * 100))
1811 +#define LIPORATE_p6C   LIPORATE(0,6)   /* 0.6C */
1812 +
1813 +enum lipocharge_state {
1814 +       LIPO_IDLE = 0,          /* Not charging */
1815 +       LIPO_FIRST_STAGE,       /* Charging: constant current */
1816 +       LIPO_SECOND_STAGE,      /* Charging: constant voltage */
1817 +};
1818 +
1819 +/** struct lipocharge - A generic LIPO charger
1820 + *
1821 + * @capacity: Battery capacity in mAh.
1822 + * @rate: Charge rate.
1823 + * @top_voltage: Fully charged voltage, in mV.
1824 + * @duty_cycle_max: Max value for duty_cycle.
1825 + *
1826 + * @set_charge_current: Set the charge current PWM duty cycle.
1827 + * @emergency: Something went wrong. Force shutdown.
1828 + */
1829 +struct lipocharge {
1830 +       unsigned int capacity;
1831 +       unsigned int rate;
1832 +       unsigned int top_voltage;
1833 +       unsigned int duty_cycle_max;
1834 +
1835 +       int (*set_current_pwm)(struct lipocharge *c, unsigned int duty_cycle);
1836 +       void (*emergency)(struct lipocharge *c);
1837 +
1838 +       /* internal */
1839 +       struct device *dev;
1840 +       enum lipocharge_state state;
1841 +       unsigned int active_duty_cycle;
1842 +
1843 +       //TODO implement timer to cut power after maximum charge time.
1844 +};
1845 +
1846 +void lipocharge_init(struct lipocharge *c, struct device *dev);
1847 +void lipocharge_exit(struct lipocharge *c);
1848 +
1849 +int lipocharge_start(struct lipocharge *c);
1850 +void lipocharge_stop(struct lipocharge *c);
1851 +
1852 +int lipocharge_update_state(struct lipocharge *c,
1853 +                           unsigned int voltage_mV,
1854 +                           int current_mA,
1855 +                           unsigned int temp_K);
1856 +
1857 +static inline bool lipocharge_is_charging(struct lipocharge *c)
1858 +{
1859 +       return (c->state != LIPO_IDLE);
1860 +}
1861 +
1862 +#endif /* LIPOCHARGE_H_ */
1863 --- a/drivers/cbus/cbus.c
1864 +++ b/drivers/cbus/cbus.c
1865 @@ -35,6 +35,7 @@
1866  #include <linux/platform_device.h>
1867  
1868  #include <plat/cbus.h>
1869 +#include <linux/reboot.h>
1870  
1871  #include "cbus.h"
1872  
1873 @@ -323,6 +324,13 @@ static void __exit cbus_bus_exit(void)
1874  }
1875  module_exit(cbus_bus_exit);
1876  
1877 +void cbus_emergency(void)
1878 +{
1879 +       machine_power_off();
1880 +       panic("cbus: Failed to halt machine in emergency state\n");
1881 +}
1882 +EXPORT_SYMBOL(cbus_emergency);
1883 +
1884  MODULE_DESCRIPTION("CBUS serial protocol");
1885  MODULE_LICENSE("GPL");
1886  MODULE_AUTHOR("Juha Yrjölä");
1887 --- a/drivers/cbus/cbus.h
1888 +++ b/drivers/cbus/cbus.h
1889 @@ -26,4 +26,6 @@
1890  extern int cbus_read_reg(unsigned dev, unsigned reg);
1891  extern int cbus_write_reg(unsigned dev, unsigned reg, unsigned val);
1892  
1893 +NORET_TYPE void cbus_emergency(void) ATTRIB_NORET;
1894 +
1895  #endif /* __DRIVERS_CBUS_CBUS_H */
1896 --- a/drivers/cbus/retu.c
1897 +++ b/drivers/cbus/retu.c
1898 @@ -425,6 +425,11 @@ static int retu_allocate_children(struct
1899         if (!child)
1900                 return -ENOMEM;
1901  
1902 +       child = retu_allocate_child("retu-n810bm", parent, irq_base,
1903 +                       RETU_INT_ADCS, -1, 1);
1904 +       if (!child)
1905 +               return -ENOMEM;
1906 +
1907         return 0;
1908  }
1909  
1910 --- a/drivers/cbus/tahvo.c
1911 +++ b/drivers/cbus/tahvo.c
1912 @@ -54,6 +54,7 @@ static int tahvo_is_betty;
1913  
1914  static struct tasklet_struct tahvo_tasklet;
1915  spinlock_t tahvo_lock = SPIN_LOCK_UNLOCKED;
1916 +EXPORT_SYMBOL(tahvo_lock);
1917  
1918  struct tahvo_irq_handler_desc {
1919         int (*func)(unsigned long);
1920 @@ -115,6 +116,7 @@ void tahvo_set_clear_reg_bits(unsigned r
1921         tahvo_write_reg(reg, w);
1922         spin_unlock_irqrestore(&tahvo_lock, flags);
1923  }
1924 +EXPORT_SYMBOL(tahvo_set_clear_reg_bits);
1925  
1926  /*
1927   * Disable given TAHVO interrupt