3f6262a357beea647349eca9491561513ab3db68
[openwrt.git] / target / linux / omap24xx / patches-2.6.37 / 900-n810-battery-management.patch
1 ---
2  arch/arm/mach-omap2/board-n8x0.c |   13 +
3  drivers/cbus/Kconfig             |   12 +
4  drivers/cbus/Makefile            |    3 
5  drivers/cbus/lipocharge.c        |   63 ++++++
6  drivers/cbus/lipocharge.h        |   50 ++++
7  drivers/cbus/n810bm_main.c       |  397 +++++++++++++++++++++++++++++++++++++++
8  drivers/cbus/retu.c              |    4 
9  drivers/cbus/retu.h              |    3 
10  drivers/cbus/tahvo.h             |    6 
11  9 files changed, 548 insertions(+), 3 deletions(-)
12
13 Index: linux-2.6.37/drivers/cbus/Kconfig
14 ===================================================================
15 --- linux-2.6.37.orig/drivers/cbus/Kconfig      2011-01-28 22:33:39.703215389 +0100
16 +++ linux-2.6.37/drivers/cbus/Kconfig   2011-01-28 23:41:57.094298060 +0100
17 @@ -94,4 +94,12 @@
18           to Retu/Vilma. Detection state and events are exposed through
19           sysfs.
20  
21 +config N810BM
22 +       depends on CBUS_RETU && CBUS_TAHVO
23 +       tristate "Nokia n810 battery management"
24 +       ---help---
25 +         Nokia n810 device battery management.
26 +
27 +         If unsure, say N.
28 +
29  endmenu
30 Index: linux-2.6.37/drivers/cbus/Makefile
31 ===================================================================
32 --- linux-2.6.37.orig/drivers/cbus/Makefile     2011-01-28 22:33:39.694216931 +0100
33 +++ linux-2.6.37/drivers/cbus/Makefile  2011-01-28 22:33:39.754206648 +0100
34 @@ -12,3 +12,6 @@
35  obj-$(CONFIG_CBUS_TAHVO_USER)  += tahvo-user.o
36  obj-$(CONFIG_CBUS_RETU_USER)   += retu-user.o
37  obj-$(CONFIG_CBUS_RETU_HEADSET)        += retu-headset.o
38 +n810bm-y                       += n810bm_main.o
39 +n810bm-y                       += lipocharge.o
40 +obj-$(CONFIG_N810BM)           += n810bm.o
41 Index: linux-2.6.37/drivers/cbus/n810bm_main.c
42 ===================================================================
43 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
44 +++ linux-2.6.37/drivers/cbus/n810bm_main.c     2011-01-28 23:41:23.510064352 +0100
45 @@ -0,0 +1,562 @@
46 +/*
47 + *   Nokia n810 battery management
48 + *
49 + *   WARNING: This driver is based on unconfirmed documentation.
50 + *            It is possibly dangerous to use this software.
51 + *            Use this software at your own risk!
52 + *
53 + *   Copyright (c) 2010-2011 Michael Buesch <mb@bu3sch.de>
54 + *
55 + *   This program is free software; you can redistribute it and/or
56 + *   modify it under the terms of the GNU General Public License
57 + *   as published by the Free Software Foundation; either version 2
58 + *   of the License, or (at your option) any later version.
59 + *
60 + *   This program is distributed in the hope that it will be useful,
61 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
62 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
63 + *   GNU General Public License for more details.
64 + */
65 +
66 +#include <linux/module.h>
67 +#include <linux/device.h>
68 +#include <linux/platform_device.h>
69 +#include <linux/slab.h>
70 +#include <linux/spinlock.h>
71 +#include <linux/timer.h>
72 +#include <linux/reboot.h>
73 +
74 +#include "retu.h"
75 +#include "tahvo.h"
76 +#include "lipocharge.h"
77 +
78 +
79 +#define N810BM_CHECK_INTERVAL          (HZ * 5)
80 +#define N810BM_MIN_VOLTAGE_THRES       3300 /* Absolute minimum voltage threshold */
81 +
82 +
83 +/* RETU_ADC_BSI
84 + * The battery size indicator ADC measures the resistance between
85 + * the battery BSI pin and ground. This is used to detect the battery
86 + * capacity, as the BSI resistor is related to capacity.
87 + *
88 + * Manually measured lookup table.
89 + * Hard to measure, thus not very accurate.
90 + *
91 + * Resistance  |  ADC value
92 + * ========================
93 + * 120k        |  0x3AC
94 + * 110k        |  0x37C
95 + * 100k        |  0x351
96 + *  90k        |  0x329
97 + */
98 +
99 +/* RETU_ADC_BATTVOLT
100 + * Manually measured lookup table.
101 + * Hard to measure, thus not very accurate.
102 + *
103 + * Voltage  |  ADC value
104 + * =====================
105 + * 2.80V    |  0x037
106 + * 2.90V    |  0x05E
107 + * 3.00V    |  0x090
108 + * 3.10V    |  0x0A4
109 + * 3.20V    |  0x0CC
110 + * 3.30V    |  0x0EF
111 + * 3.40V    |  0x115
112 + * 3.50V    |  0x136
113 + * 3.60V    |  0x15C
114 + * 3.70V    |  0x187
115 + * 3.80V    |  0x1A5
116 + * 3.90V    |  0x1C9
117 + * 4.00V    |  0x1ED
118 + * 4.10V    |  0x212
119 + * 4.20V    |  0x236
120 + */
121 +
122 +
123 +enum n810bm_capacity {
124 +       N810BM_CAP_UNKNOWN      = 0,
125 +       N810BM_CAP_1500MAH      = 1500, /* 1500 mAh battery */
126 +};
127 +
128 +struct n810bm {
129 +       struct platform_device *pdev;
130 +
131 +       enum n810bm_capacity capacity;
132 +       struct timer_list check_timer;
133 +
134 +       struct lipocharge *charger;
135 +
136 +       spinlock_t lock;
137 +};
138 +
139 +
140 +static NORET_TYPE void n810bm_emergency(struct n810bm *bm, const char *message) ATTRIB_NORET;
141 +static void n810bm_emergency(struct n810bm *bm, const char *message)
142 +{
143 +       printk(KERN_EMERG "n810 battery management fatal fault: %s\n", message);
144 +       /* Force a hard shutdown. */
145 +       machine_power_off();
146 +       panic("n810bm: Failed to halt machine in emergency state\n");
147 +}
148 +
149 +#if 0
150 +static u16 retu_read(struct n810bm *bm, unsigned int reg)
151 +{
152 +       int ret;
153 +       unsigned long flags;
154 +
155 +       spin_lock_irqsave(&retu_lock, flags);
156 +       ret = retu_read_reg(reg);
157 +       spin_unlock_irqrestore(&retu_lock, flags);
158 +       if (ret < 0 || ret > 0xFFFF)
159 +               n810bm_emergency(bm, "retu_read");
160 +
161 +       return ret;
162 +}
163 +#endif
164 +
165 +static void retu_maskset(struct n810bm *bm, unsigned int reg, u16 mask, u16 set)
166 +{
167 +       int ret;
168 +       unsigned long flags;
169 +       u16 value;
170 +
171 +       spin_lock_irqsave(&retu_lock, flags);
172 +       if (~mask) {
173 +               ret = retu_read_reg(reg);
174 +               if (ret < 0 || ret > 0xFFFF)
175 +                       goto fatal_unlock;
176 +               value = ret;
177 +       } else
178 +               value = 0;
179 +       value &= ~mask;
180 +       value |= set;
181 +       ret = retu_write_reg(reg, value);
182 +       if (ret)
183 +               goto fatal_unlock;
184 +       spin_unlock_irqrestore(&retu_lock, flags);
185 +
186 +       return;
187 +
188 +fatal_unlock:
189 +       spin_unlock_irqrestore(&retu_lock, flags);
190 +       n810bm_emergency(bm, "retu_maskset");
191 +}
192 +
193 +static inline void retu_write(struct n810bm *bm, unsigned int reg, u16 value)
194 +{
195 +       return retu_maskset(bm, reg, 0xFFFF, value);
196 +}
197 +
198 +static int retu_adc_average(struct n810bm *bm, unsigned int chan,
199 +                           unsigned int nr_passes)
200 +{
201 +       unsigned int i, value = 0;
202 +       int ret;
203 +
204 +       if (WARN_ON(!nr_passes))
205 +               return 0;
206 +       for (i = 0; i < nr_passes; i++) {
207 +               ret = retu_read_adc(chan);
208 +               if (ret < 0)
209 +                       return ret;
210 +               value += ret;
211 +       }
212 +       value /= nr_passes;
213 +
214 +       return value;
215 +}
216 +
217 +static int adc_sanity_check(struct n810bm *bm, unsigned int channel)
218 +{
219 +       int value;
220 +
221 +       value = retu_read_adc(channel);
222 +       if (value < 0) {
223 +               dev_err(&bm->pdev->dev, "Failed to read GND ADC channel %u",
224 +                       channel);
225 +               return -EIO;
226 +       }
227 +       dev_info(&bm->pdev->dev,
228 +                "GND ADC channel %u sanity check got value: %d",
229 +                channel, value);
230 +       if (value > 5) {
231 +               n810bm_emergency(bm, "GND ADC sanity check failed");
232 +               return -EIO;
233 +       }
234 +
235 +       return 0;
236 +}
237 +
238 +static int n810bm_check_adc_sanity(struct n810bm *bm)
239 +{
240 +       int err;
241 +
242 +       /* Discard one conversion */
243 +       retu_write(bm, RETU_REG_ADCSCR, 0);
244 +       retu_read_adc(RETU_ADC_GND2);
245 +
246 +       err = adc_sanity_check(bm, RETU_ADC_GND2);
247 +       if (err)
248 +               return err;
249 +
250 +       return 0;
251 +}
252 +
253 +/* Measure the battery voltage. Returns the value in mV (or negative value on error). */
254 +static int n810bm_measure_batt_voltage(struct n810bm *bm)
255 +{
256 +       int adc;
257 +       unsigned int mv;
258 +       const unsigned int scale = 1000;
259 +
260 +       adc = retu_adc_average(bm, RETU_ADC_BATTVOLT, 5);
261 +       if (adc < 0)
262 +               return adc;
263 +       if (adc <= 0x37)
264 +               return 2800;
265 +       mv = 2800 + ((adc - 0x37) * (((4200 - 2800) * scale) / (0x236 - 0x37))) / scale;
266 +
267 +       return mv;
268 +}
269 +
270 +/* Measure the charger voltage. Returns the value in mV (or negative value on error). */
271 +static int n810bm_measure_charger_voltage(struct n810bm *bm)
272 +{
273 +       int adc;
274 +       unsigned int mv;
275 +
276 +       adc = retu_adc_average(bm, RETU_ADC_CHGVOLT, 5);
277 +       if (adc < 0)
278 +               return adc;
279 +       //TODO convert to mV
280 +       mv = adc;
281 +
282 +       return mv;
283 +}
284 +
285 +/* Measure backup battery voltage. Returns the value in mV (or negative value on error). */
286 +static int n810bm_measure_backup_batt_voltage(struct n810bm *bm)
287 +{
288 +       int adc;
289 +       unsigned int mv;
290 +
291 +       adc = retu_adc_average(bm, RETU_ADC_BKUPVOLT, 3);
292 +       if (adc < 0)
293 +               return adc;
294 +       //TODO convert to mV
295 +       mv = adc;
296 +
297 +       return mv;
298 +}
299 +
300 +/* Measure the battery temperature. Returns the value in K (or negative value on error). */
301 +static int n810bm_measure_batt_temp(struct n810bm *bm)
302 +{
303 +       int adc;
304 +       unsigned int k;
305 +
306 +       adc = retu_adc_average(bm, RETU_ADC_BATTEMP, 3);
307 +       if (adc < 0)
308 +               return adc;
309 +       //TODO convert to K
310 +       k = adc;
311 +
312 +       return k;
313 +}
314 +
315 +/* Read the battery capacity via BSI pin. */
316 +static enum n810bm_capacity n810bm_read_batt_capacity(struct n810bm *bm)
317 +{
318 +       int adc;
319 +       const unsigned int hyst = 20;
320 +
321 +       adc = retu_adc_average(bm, RETU_ADC_BSI, 5);
322 +       if (adc < 0) {
323 +               dev_err(&bm->pdev->dev, "Failed to read BSI ADC");
324 +               return N810BM_CAP_UNKNOWN;
325 +       }
326 +
327 +       if (adc >= 0x3B5 - hyst && adc <= 0x3B5 + hyst)
328 +               return N810BM_CAP_1500MAH;
329 +
330 +       dev_err(&bm->pdev->dev, "Capacity indicator 0x%X unknown", adc);
331 +
332 +       return N810BM_CAP_UNKNOWN;
333 +}
334 +
335 +/* Convert a battery voltage (in mV) to percentage. */
336 +static unsigned int n810bm_mvolt2percent(unsigned int mv)
337 +{
338 +       const unsigned int minv = 3700;
339 +       const unsigned int maxv = 4150;
340 +       unsigned int percent;
341 +
342 +       mv = clamp(mv, minv, maxv);
343 +       percent = (mv - minv) * 100 / (maxv - minv);
344 +
345 +       return percent;
346 +}
347 +
348 +static void n810bm_check_timer(unsigned long data)
349 +{
350 +       struct n810bm *bm = (struct n810bm *)data;
351 +       unsigned long flags;
352 +       int mv;
353 +
354 +       spin_lock_irqsave(&bm->lock, flags);
355 +
356 +       mv = n810bm_measure_batt_voltage(bm);
357 +       if (mv < 0)
358 +               n810bm_emergency(bm, "check timer: Failed to measure");
359 +       if (mv < N810BM_MIN_VOLTAGE_THRES)
360 +               n810bm_emergency(bm, "check timer: Minimum voltage threshold reached");
361 +
362 +       mod_timer(&bm->check_timer, round_jiffies(jiffies + N810BM_CHECK_INTERVAL));
363 +       spin_unlock_irqrestore(&bm->lock, flags);
364 +
365 +       return;
366 +}
367 +
368 +static void n810bm_adc_irq_handler(unsigned long data)
369 +{
370 +//     struct n810bm *bm = (struct n810bm *)data;
371 +
372 +       retu_ack_irq(RETU_INT_ADCS);
373 +       //TODO
374 +printk("n810bm: ADC timer triggered\n");
375 +}
376 +
377 +static ssize_t n810bm_attr_charge_show(struct device *dev,
378 +                                      struct device_attribute *attr,
379 +                                      char *buf)
380 +{
381 +       struct platform_device *pdev = to_platform_device(dev);
382 +       struct n810bm *bm = platform_get_drvdata(pdev);
383 +       int err = -ENODEV;
384 +       ssize_t count = 0;
385 +       int millivolt;
386 +
387 +       spin_lock_irq(&bm->lock);
388 +       millivolt = n810bm_measure_batt_voltage(bm);
389 +       if (millivolt >= 0) {
390 +               count = snprintf(buf, PAGE_SIZE, "%u\n",
391 +                                n810bm_mvolt2percent(millivolt));
392 +               err = 0;
393 +       }
394 +       spin_unlock_irq(&bm->lock);
395 +
396 +       return err ? err : count;
397 +}
398 +static DEVICE_ATTR(batt_charge, 0444, n810bm_attr_charge_show, NULL);
399 +
400 +static ssize_t n810bm_attr_capacity_show(struct device *dev,
401 +                                        struct device_attribute *attr,
402 +                                        char *buf)
403 +{
404 +       struct platform_device *pdev = to_platform_device(dev);
405 +       struct n810bm *bm = platform_get_drvdata(pdev);
406 +       ssize_t count;
407 +
408 +       spin_lock_irq(&bm->lock);
409 +       count = snprintf(buf, PAGE_SIZE, "%u\n",
410 +                        (unsigned int)bm->capacity);
411 +       spin_unlock_irq(&bm->lock);
412 +
413 +       return count;
414 +}
415 +static DEVICE_ATTR(batt_capacity, 0444, n810bm_attr_capacity_show, NULL);
416 +
417 +static ssize_t n810bm_attr_battemp_show(struct device *dev,
418 +                                       struct device_attribute *attr,
419 +                                       char *buf)
420 +{
421 +       struct platform_device *pdev = to_platform_device(dev);
422 +       struct n810bm *bm = platform_get_drvdata(pdev);
423 +       ssize_t count = 0;
424 +       int k, err = -ENODEV;
425 +
426 +       spin_lock_irq(&bm->lock);
427 +       k = n810bm_measure_batt_temp(bm);
428 +       if (k >= 0) {
429 +               count = snprintf(buf, PAGE_SIZE, "%d\n", k);
430 +               err = 0;
431 +       }
432 +       spin_unlock_irq(&bm->lock);
433 +
434 +       return err ? err : count;
435 +}
436 +static DEVICE_ATTR(batt_temp, 0444, n810bm_attr_battemp_show, NULL);
437 +
438 +static ssize_t n810bm_attr_charger_voltage(struct device *dev,
439 +                                          struct device_attribute *attr,
440 +                                          char *buf)
441 +{
442 +       struct platform_device *pdev = to_platform_device(dev);
443 +       struct n810bm *bm = platform_get_drvdata(pdev);
444 +       ssize_t count = 0;
445 +       int mv, err = -ENODEV;
446 +
447 +       spin_lock_irq(&bm->lock);
448 +       mv = n810bm_measure_charger_voltage(bm);
449 +       if (mv >= 0) {
450 +               count = snprintf(buf, PAGE_SIZE, "%d\n", mv);
451 +               err = 0;
452 +       }
453 +       spin_unlock_irq(&bm->lock);
454 +
455 +       return err ? err : count;
456 +}
457 +static DEVICE_ATTR(charger_voltage, 0444, n810bm_attr_charger_voltage, NULL);
458 +
459 +static ssize_t n810bm_attr_backup_batt_voltage(struct device *dev,
460 +                                              struct device_attribute *attr,
461 +                                              char *buf)
462 +{
463 +       struct platform_device *pdev = to_platform_device(dev);
464 +       struct n810bm *bm = platform_get_drvdata(pdev);
465 +       ssize_t count = 0;
466 +       int mv, err = -ENODEV;
467 +
468 +       spin_lock_irq(&bm->lock);
469 +       mv = n810bm_measure_backup_batt_voltage(bm);
470 +       if (mv >= 0) {
471 +               count = snprintf(buf, PAGE_SIZE, "%d\n", mv);
472 +               err = 0;
473 +       }
474 +       spin_unlock_irq(&bm->lock);
475 +
476 +       return err ? err : count;
477 +}
478 +static DEVICE_ATTR(backup_batt_voltage, 0444, n810bm_attr_backup_batt_voltage, NULL);
479 +
480 +static void n810bm_hw_exit(struct n810bm *bm)
481 +{
482 +       retu_write(bm, RETU_REG_ADCSCR, 0);
483 +}
484 +
485 +static int n810bm_hw_init(struct n810bm *bm)
486 +{
487 +       int err;
488 +
489 +       err = n810bm_check_adc_sanity(bm);
490 +       if (err)
491 +               goto error;
492 +       bm->capacity = n810bm_read_batt_capacity(bm);
493 +       if (bm->capacity == N810BM_CAP_UNKNOWN) {
494 +               dev_err(&bm->pdev->dev, "Unknown battery detected");
495 +               err = -ENODEV;
496 +               goto error;
497 +       }
498 +       dev_info(&bm->pdev->dev, "Detected %u mAh battery\n",
499 +                (unsigned int)bm->capacity);
500 +
501 +       return 0;
502 +
503 +error:
504 +       return err;
505 +}
506 +
507 +static int __devinit n810bm_probe(struct platform_device *pdev)
508 +{
509 +       struct n810bm *bm;
510 +       int err;
511 +
512 +       bm = kzalloc(sizeof(*bm), GFP_KERNEL);
513 +       if (!bm)
514 +               return -ENOMEM;
515 +       bm->pdev = pdev;
516 +       platform_set_drvdata(pdev, bm);
517 +       spin_lock_init(&bm->lock);
518 +       setup_timer(&bm->check_timer, n810bm_check_timer, (unsigned long)bm);
519 +
520 +       err = n810bm_hw_init(bm);
521 +       if (err)
522 +               goto err_free;
523 +       err = device_create_file(&pdev->dev, &dev_attr_batt_charge);
524 +       if (err)
525 +               goto err_exit;
526 +       err = device_create_file(&pdev->dev, &dev_attr_batt_capacity);
527 +       if (err)
528 +               goto err_rem_charge;
529 +       err = device_create_file(&pdev->dev, &dev_attr_batt_temp);
530 +       if (err)
531 +               goto err_rem_capa;
532 +       err = device_create_file(&pdev->dev, &dev_attr_charger_voltage);
533 +       if (err)
534 +               goto err_rem_temp;
535 +       err = device_create_file(&pdev->dev, &dev_attr_backup_batt_voltage);
536 +       if (err)
537 +               goto err_rem_chg;
538 +       err = retu_request_irq(RETU_INT_ADCS, n810bm_adc_irq_handler,
539 +                              (unsigned long)bm, "n810bm");
540 +       if (err)
541 +               goto err_rem_bkup;
542 +
543 +       mod_timer(&bm->check_timer, round_jiffies(jiffies + N810BM_CHECK_INTERVAL));
544 +
545 +       dev_info(&pdev->dev, "Battery management initialized");
546 +
547 +       return 0;
548 +
549 +err_rem_bkup:
550 +       device_remove_file(&pdev->dev, &dev_attr_backup_batt_voltage);
551 +err_rem_chg:
552 +       device_remove_file(&pdev->dev, &dev_attr_charger_voltage);
553 +err_rem_temp:
554 +       device_remove_file(&pdev->dev, &dev_attr_batt_temp);
555 +err_rem_capa:
556 +       device_remove_file(&pdev->dev, &dev_attr_batt_capacity);
557 +err_rem_charge:
558 +       device_remove_file(&pdev->dev, &dev_attr_batt_charge);
559 +err_exit:
560 +       n810bm_hw_exit(bm);
561 +err_free:
562 +       kfree(bm);
563 +       platform_set_drvdata(pdev, NULL);
564 +       return err;
565 +}
566 +
567 +static int __devexit n810bm_remove(struct platform_device *pdev)
568 +{
569 +       struct n810bm *bm = platform_get_drvdata(pdev);
570 +
571 +       retu_free_irq(RETU_INT_ADCS);
572 +       del_timer_sync(&bm->check_timer);
573 +       device_remove_file(&pdev->dev, &dev_attr_backup_batt_voltage);
574 +       device_remove_file(&pdev->dev, &dev_attr_charger_voltage);
575 +       device_remove_file(&pdev->dev, &dev_attr_batt_temp);
576 +       device_remove_file(&pdev->dev, &dev_attr_batt_capacity);
577 +       device_remove_file(&pdev->dev, &dev_attr_batt_charge);
578 +       n810bm_hw_exit(bm);
579 +
580 +       kfree(bm);
581 +       platform_set_drvdata(pdev, NULL);
582 +
583 +       return 0;
584 +}
585 +
586 +static struct platform_driver n810bm_driver = {
587 +       .remove         = __devexit_p(n810bm_remove),
588 +       .driver         = {
589 +               .name   = "n810bm",
590 +       }
591 +};
592 +
593 +static int __init n810bm_modinit(void)
594 +{
595 +       return platform_driver_probe(&n810bm_driver, n810bm_probe);
596 +}
597 +module_init(n810bm_modinit);
598 +
599 +static void __exit n810bm_modexit(void)
600 +{
601 +       platform_driver_unregister(&n810bm_driver);
602 +}
603 +module_exit(n810bm_modexit);
604 +
605 +MODULE_DESCRIPTION("Nokia n810 battery management");
606 +MODULE_LICENSE("GPL");
607 +MODULE_AUTHOR("Michael Buesch");
608 Index: linux-2.6.37/drivers/cbus/retu.c
609 ===================================================================
610 --- linux-2.6.37.orig/drivers/cbus/retu.c       2011-01-28 22:33:39.695216760 +0100
611 +++ linux-2.6.37/drivers/cbus/retu.c    2011-01-28 22:33:39.754206648 +0100
612 @@ -85,10 +85,10 @@
613   *
614   * This function writes a value to the specified register
615   */
616 -void retu_write_reg(int reg, u16 val)
617 +int retu_write_reg(int reg, u16 val)
618  {
619         BUG_ON(!retu_initialized);
620 -       cbus_write_reg(cbus_host, RETU_ID, reg, val);
621 +       return cbus_write_reg(cbus_host, RETU_ID, reg, val);
622  }
623  
624  void retu_set_clear_reg_bits(int reg, u16 set, u16 clear)
625 Index: linux-2.6.37/drivers/cbus/retu.h
626 ===================================================================
627 --- linux-2.6.37.orig/drivers/cbus/retu.h       2011-01-28 22:33:39.695216760 +0100
628 +++ linux-2.6.37/drivers/cbus/retu.h    2011-01-28 22:40:55.380584650 +0100
629 @@ -39,6 +39,7 @@
630  #define RETU_REG_CC2           0x0e    /* Common control register 2 */
631  #define RETU_REG_CTRL_CLR      0x0f    /* Regulator clear register */
632  #define RETU_REG_CTRL_SET      0x10    /* Regulator set register */
633 +#define RETU_REG_UNK1          0x14    /* 0x1000 is set when charger is plugged in */
634  #define RETU_REG_STATUS                0x16    /* Status register */
635  #define RETU_REG_WATCHDOG      0x17    /* Watchdog register */
636  #define RETU_REG_AUDTXR                0x18    /* Audio Codec Tx register */
637 @@ -57,8 +58,25 @@
638  
639  #define        MAX_RETU_IRQ_HANDLERS   16
640  
641 +/* ADC channels */
642 +#define RETU_ADC_GND           0x00 /* Ground */
643 +#define RETU_ADC_BSI           0x01 /* Battery Size Indicator */
644 +#define RETU_ADC_BATTEMP       0x02 /* Battery temperature */
645 +#define RETU_ADC_CHGVOLT       0x03 /* Charger voltage */
646 +#define RETU_ADC_HEADSET       0x04 /* Headset detection */
647 +#define RETU_ADC_HOOKDET       0x05 /* Hook detection */
648 +#define RETU_ADC_RFGP          0x06 /* RF GP */
649 +#define RETU_ADC_WBTX          0x07 /* Wideband Tx detection */
650 +#define RETU_ADC_BATTVOLT      0x08 /* Battery voltage measurement */
651 +#define RETU_ADC_GND2          0x09 /* Ground */
652 +#define RETU_ADC_LIGHTSENS     0x0A /* Light sensor */
653 +#define RETU_ADC_LIGHTTEMP     0x0B /* Light sensor temperature */
654 +#define RETU_ADC_BKUPVOLT      0x0C /* Backup battery voltage */
655 +#define RETU_ADC_TEMP          0x0D /* RETU temperature */
656 +
657 +
658  int retu_read_reg(int reg);
659 -void retu_write_reg(int reg, u16 val);
660 +int retu_write_reg(int reg, u16 val);
661  void retu_set_clear_reg_bits(int reg, u16 set, u16 clear);
662  int retu_read_adc(int channel);
663  int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name);
664 Index: linux-2.6.37/arch/arm/mach-omap2/board-n8x0.c
665 ===================================================================
666 --- linux-2.6.37.orig/arch/arm/mach-omap2/board-n8x0.c  2011-01-28 22:33:39.679219500 +0100
667 +++ linux-2.6.37/arch/arm/mach-omap2/board-n8x0.c       2011-01-28 22:33:39.754206648 +0100
668 @@ -907,6 +907,17 @@
669                                     ARRAY_SIZE(n8x0_gpio_switches));
670  }
671  
672 +static struct platform_device n810_bm_device = {
673 +       .name           = "n810bm",
674 +       .id             = -1,
675 +};
676 +
677 +static void __init n810_bm_init(void)
678 +{
679 +       if (platform_device_register(&n810_bm_device))
680 +               BUG();
681 +}
682 +
683  static void __init n8x0_init_machine(void)
684  {
685         omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC);
686 @@ -933,6 +944,8 @@
687         n8x0_onenand_init();
688         n8x0_mmc_init();
689         n8x0_usb_init();
690 +
691 +       n810_bm_init();
692  }
693  
694  MACHINE_START(NOKIA_N800, "Nokia N800")
695 Index: linux-2.6.37/drivers/cbus/lipocharge.c
696 ===================================================================
697 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
698 +++ linux-2.6.37/drivers/cbus/lipocharge.c      2011-01-28 22:33:39.755206476 +0100
699 @@ -0,0 +1,63 @@
700 +/*
701 + *   Generic LIPO battery charger
702 + *
703 + *   Copyright (c) 2010 Michael Buesch <mb@bu3sch.de>
704 + *
705 + *   This program is free software; you can redistribute it and/or
706 + *   modify it under the terms of the GNU General Public License
707 + *   as published by the Free Software Foundation; either version 2
708 + *   of the License, or (at your option) any later version.
709 + *
710 + *   This program is distributed in the hope that it will be useful,
711 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
712 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
713 + *   GNU General Public License for more details.
714 + */
715 +
716 +#include "lipocharge.h"
717 +
718 +#include <linux/slab.h>
719 +
720 +
721 +static void lipocharge_timer(unsigned long data)
722 +{
723 +       struct lipocharge *c = (struct lipocharge *)data;
724 +
725 +       spin_lock(&c->lock);
726 +       //TODO
727 +       spin_unlock(&c->lock);
728 +}
729 +
730 +struct lipocharge * lipocharge_alloc(gfp_t gfp)
731 +{
732 +       struct lipocharge *c;
733 +
734 +       c = kzalloc(sizeof(*c), gfp);
735 +       if (!c)
736 +               return NULL;
737 +       spin_lock_init(&c->lock);
738 +       setup_timer(&c->timer, lipocharge_timer, (unsigned long)c);
739 +
740 +       return c;
741 +}
742 +
743 +void lipocharge_free(struct lipocharge *c)
744 +{
745 +       kfree(c);
746 +}
747 +
748 +int lipocharge_start(struct lipocharge *c)
749 +{
750 +       if (!c->set_current || !c->get_voltage ||
751 +           !c->finished || !c->emergency)
752 +               return -EINVAL;
753 +       if (!c->top_voltage || c->top_voltage > 4200)
754 +               return -EINVAL;
755 +       //TODO
756 +}
757 +
758 +void lipocharge_stop(struct lipocharge *c)
759 +{
760 +       del_timer_sync(&c->timer);
761 +       //TODO
762 +}
763 Index: linux-2.6.37/drivers/cbus/lipocharge.h
764 ===================================================================
765 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
766 +++ linux-2.6.37/drivers/cbus/lipocharge.h      2011-01-28 22:33:39.755206476 +0100
767 @@ -0,0 +1,50 @@
768 +#ifndef LIPOCHARGE_H_
769 +#define LIPOCHARGE_H_
770 +
771 +#include <linux/timer.h>
772 +#include <linux/spinlock.h>
773 +
774 +
775 +#define LIPORATE(a,b)  (((a) * 1000) + (b))
776 +#define LIPORATE_1C    LIPORATE(1,0)   /* 1C */
777 +#define LIPORATE_p8C   LIPORATE(0,8)   /* 0.8C */
778 +
779 +/** struct lipocharge - A generic LIPO charger
780 + *
781 + * @capacity: Battery capacity in mAh.
782 + * @rate: Charge rate.
783 + * @top_voltage: Fully charged voltage, in mV.
784 + *
785 + * @set_current: Set the charge current, in mA.
786 + * @get_voltage: Get the battery voltage, in mV.
787 + *
788 + * @emergency: Something went wrong. Force shutdown.
789 + *
790 + * @priv: opaque pointer.
791 + */
792 +struct lipocharge
793 +{
794 +       unsigned int capacity;
795 +       unsigned int rate;
796 +       unsigned int top_voltage;
797 +
798 +       int (*set_current)(struct lipocharge *c, unsigned int ma);
799 +       int (*get_voltage)(struct lipocharge *c, unsigned int *mv);
800 +
801 +       void (*finished)(struct lipocharge *c);
802 +       void (*emergency)(struct lipocharge *c);
803 +
804 +       void *priv;
805 +
806 +       /* internal */
807 +       spinlock_t lock;
808 +       struct timer_list timer;
809 +};
810 +
811 +struct lipocharge * lipocharge_alloc(gfp_t gfp);
812 +void lipocharge_free(struct lipocharge *c);
813 +
814 +int lipocharge_start(struct lipocharge *c);
815 +void lipocharge_stop(struct lipocharge *c);
816 +
817 +#endif /* LIPOCHARGE_H_ */
818 Index: linux-2.6.37/drivers/cbus/tahvo.h
819 ===================================================================
820 --- linux-2.6.37.orig/drivers/cbus/tahvo.h      2011-01-28 22:33:39.696216589 +0100
821 +++ linux-2.6.37/drivers/cbus/tahvo.h   2011-01-28 22:33:39.755206476 +0100
822 @@ -30,8 +30,14 @@
823  #define TAHVO_REG_IDR          0x01    /* Interrupt ID */
824  #define TAHVO_REG_IDSR         0x02    /* Interrupt status */
825  #define TAHVO_REG_IMR          0x03    /* Interrupt mask */
826 +#define TAHVO_REG_CHGCURR      0x04    /* Charge current control (8-bit) */
827  #define TAHVO_REG_LEDPWMR      0x05    /* LED PWM */
828  #define TAHVO_REG_USBR         0x06    /* USB control */
829 +#define TAHVO_REG_CHGCTL       0x08    /* Charge control register */
830 +#define  TAHVO_REG_CHGCTL_EN   0x0001  /* Global charge enable */
831 +#define TAHVO_REG_CHGCTL2      0x0c    /* Charge control register 2 */
832 +#define TAHVO_REG_BATCURR      0x0d    /* Battery (dis)charge current (signed 16-bit) */
833 +
834  #define TAHVO_REG_MAX          0x0d
835  
836  /* Interrupt sources */