1b8316b2202cbfc565a94221f4d3ddef149c06d1
[openwrt/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-rc1/drivers/cbus/Kconfig
14 ===================================================================
15 --- linux-2.6.37-rc1.orig/drivers/cbus/Kconfig 2010-11-05 17:38:14.843000000 +0100
16 +++ linux-2.6.37-rc1/drivers/cbus/Kconfig 2010-11-05 17:38:14.894000001 +0100
17 @@ -94,4 +94,16 @@
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 + WARNING: This driver is based on reverse engineered information.
28 + It is possibly dangerous to use this software.
29 + Use this software at your own risk!
30 +
31 + If unsure, say N.
32 +
33 endmenu
34 Index: linux-2.6.37-rc1/drivers/cbus/Makefile
35 ===================================================================
36 --- linux-2.6.37-rc1.orig/drivers/cbus/Makefile 2010-11-05 17:38:14.834000050 +0100
37 +++ linux-2.6.37-rc1/drivers/cbus/Makefile 2010-11-05 17:38:14.894000001 +0100
38 @@ -12,3 +12,6 @@
39 obj-$(CONFIG_CBUS_TAHVO_USER) += tahvo-user.o
40 obj-$(CONFIG_CBUS_RETU_USER) += retu-user.o
41 obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o
42 +n810bm-y += n810bm_main.o
43 +n810bm-y += lipocharge.o
44 +obj-$(CONFIG_N810BM) += n810bm.o
45 Index: linux-2.6.37-rc1/drivers/cbus/n810bm_main.c
46 ===================================================================
47 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
48 +++ linux-2.6.37-rc1/drivers/cbus/n810bm_main.c 2010-11-05 17:38:14.894000001 +0100
49 @@ -0,0 +1,397 @@
50 +/*
51 + * Nokia n810 battery management
52 + *
53 + * WARNING: This driver is based on reverse engineered information.
54 + * It is possibly dangerous to use this software.
55 + * Use this software at your own risk!
56 + *
57 + * Copyright (c) 2010 Michael Buesch <mb@bu3sch.de>
58 + *
59 + * This program is free software; you can redistribute it and/or
60 + * modify it under the terms of the GNU General Public License
61 + * as published by the Free Software Foundation; either version 2
62 + * of the License, or (at your option) any later version.
63 + *
64 + * This program is distributed in the hope that it will be useful,
65 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
66 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
67 + * GNU General Public License for more details.
68 + */
69 +
70 +#include <linux/module.h>
71 +#include <linux/device.h>
72 +#include <linux/platform_device.h>
73 +#include <linux/slab.h>
74 +#include <linux/spinlock.h>
75 +#include <linux/timer.h>
76 +#include <linux/reboot.h>
77 +
78 +#include "retu.h"
79 +#include "tahvo.h"
80 +#include "lipocharge.h"
81 +
82 +
83 +#define N810BM_CHECK_INTERVAL (HZ * 5)
84 +#define N810BM_MIN_VOLTAGE_THRES 3300 /* Absolute minimum voltage threshold */
85 +
86 +
87 +/* Battery related retu ADC channels */
88 +#define RETU_ADC_BSI 0x01 /* Battery Size Indicator */
89 +#define RETU_ADC_BATTVOLT 0x08 /* Battery voltage measurement */
90 +
91 +/* RETU_ADC_BSI
92 + * The battery size indicator ADC measures the resistance between
93 + * the battery BSI pin and ground. This is used to detect the battery
94 + * capacity, as the BSI resistor is related to capacity.
95 + *
96 + * Manually measured lookup table.
97 + * Hard to measure, thus not very accurate.
98 + *
99 + * Resistance | ADC value
100 + * ========================
101 + * 120k | 0x3AC
102 + * 110k | 0x37C
103 + * 100k | 0x351
104 + * 90k | 0x329
105 + */
106 +
107 +/* RETU_ADC_BATTVOLT
108 + * Manually measured lookup table.
109 + * Hard to measure, thus not very accurate.
110 + *
111 + * Voltage | ADC value
112 + * =====================
113 + * 2.80V | 0x037
114 + * 2.90V | 0x05E
115 + * 3.00V | 0x090
116 + * 3.10V | 0x0A4
117 + * 3.20V | 0x0CC
118 + * 3.30V | 0x0EF
119 + * 3.40V | 0x115
120 + * 3.50V | 0x136
121 + * 3.60V | 0x15C
122 + * 3.70V | 0x187
123 + * 3.80V | 0x1A5
124 + * 3.90V | 0x1C9
125 + * 4.00V | 0x1ED
126 + * 4.10V | 0x212
127 + * 4.20V | 0x236
128 + */
129 +
130 +
131 +enum n810bm_capacity {
132 + N810BM_CAP_UNKNOWN = 0,
133 + N810BM_CAP_1500MAH = 1500, /* 1500 mAh battery */
134 +};
135 +
136 +struct n810bm {
137 + struct platform_device *pdev;
138 +
139 + enum n810bm_capacity capacity;
140 + struct timer_list check_timer;
141 +
142 + struct lipocharge *charger;
143 +
144 + spinlock_t lock;
145 +};
146 +
147 +
148 +static NORET_TYPE void n810bm_emergency(struct n810bm *bm, const char *message) ATTRIB_NORET;
149 +static void n810bm_emergency(struct n810bm *bm, const char *message)
150 +{
151 + printk(KERN_EMERG "n810 battery management fatal fault: %s\n", message);
152 + /* Force a hard shutdown. */
153 + machine_power_off();
154 + panic("n810bm: Failed to halt machine in emergency state\n");
155 +}
156 +
157 +#if 0
158 +static u16 retu_read(struct n810bm *bm, unsigned int reg)
159 +{
160 + int ret;
161 + unsigned long flags;
162 +
163 + spin_lock_irqsave(&retu_lock, flags);
164 + ret = retu_read_reg(reg);
165 + spin_unlock_irqrestore(&retu_lock, flags);
166 + if (ret < 0 || ret > 0xFFFF)
167 + n810bm_emergency(bm, "retu_read");
168 +
169 + return ret;
170 +}
171 +#endif
172 +
173 +static void retu_maskset(struct n810bm *bm, unsigned int reg, u16 mask, u16 set)
174 +{
175 + int ret;
176 + unsigned long flags;
177 + u16 value;
178 +
179 + spin_lock_irqsave(&retu_lock, flags);
180 + if (~mask) {
181 + ret = retu_read_reg(reg);
182 + if (ret < 0 || ret > 0xFFFF)
183 + goto fatal_unlock;
184 + value = ret;
185 + } else
186 + value = 0;
187 + value &= ~mask;
188 + value |= set;
189 + ret = retu_write_reg(reg, value);
190 + if (ret)
191 + goto fatal_unlock;
192 + spin_unlock_irqrestore(&retu_lock, flags);
193 +
194 + return;
195 +
196 +fatal_unlock:
197 + spin_unlock_irqrestore(&retu_lock, flags);
198 + n810bm_emergency(bm, "retu_maskset");
199 +}
200 +
201 +static inline void retu_write(struct n810bm *bm, unsigned int reg, u16 value)
202 +{
203 + return retu_maskset(bm, reg, 0xFFFF, value);
204 +}
205 +
206 +static int retu_adc_average(struct n810bm *bm, unsigned int chan,
207 + unsigned int nr_passes)
208 +{
209 + unsigned int i, value = 0;
210 + int ret;
211 +
212 + if (WARN_ON(!nr_passes))
213 + return 0;
214 + for (i = 0; i < nr_passes; i++) {
215 + ret = retu_read_adc(chan);
216 + if (ret < 0)
217 + return ret;
218 + value += ret;
219 + }
220 + value /= nr_passes;
221 +
222 + return value;
223 +}
224 +
225 +/* Measure the battery voltage. Returns the value in mV (or negative value on error). */
226 +static int n810bm_measure_batt_voltage(struct n810bm *bm)
227 +{
228 + int adc;
229 + unsigned int mv;
230 + const unsigned int scale = 1000;
231 +
232 + adc = retu_adc_average(bm, RETU_ADC_BATTVOLT, 5);
233 + if (adc < 0)
234 + return adc;
235 + if (adc <= 0x37)
236 + return 2800;
237 + mv = 2800 + ((adc - 0x37) * (((4200 - 2800) * scale) / (0x236 - 0x37))) / scale;
238 +
239 + return mv;
240 +}
241 +
242 +/* Read the battery capacity via BSI pin. */
243 +static enum n810bm_capacity n810bm_read_batt_capacity(struct n810bm *bm)
244 +{
245 + int adc;
246 + const unsigned int hyst = 20;
247 +
248 + adc = retu_adc_average(bm, RETU_ADC_BSI, 5);
249 + if (adc < 0) {
250 + dev_err(&bm->pdev->dev, "Failed to read BSI ADC");
251 + return N810BM_CAP_UNKNOWN;
252 + }
253 +
254 + if (adc >= 0x3B5 - hyst && adc <= 0x3B5 + hyst)
255 + return N810BM_CAP_1500MAH;
256 +
257 + dev_err(&bm->pdev->dev, "Capacity indicator 0x%X unknown", adc);
258 +
259 + return N810BM_CAP_UNKNOWN;
260 +}
261 +
262 +/* Convert a battery voltage (in mV) to percentage. */
263 +static unsigned int n810bm_mvolt2percent(unsigned int mv)
264 +{
265 + const unsigned int minv = 3700;
266 + const unsigned int maxv = 4150;
267 + unsigned int percent;
268 +
269 + mv = clamp(mv, minv, maxv);
270 + percent = (mv - minv) * 100 / (maxv - minv);
271 +
272 + return percent;
273 +}
274 +
275 +static void n810bm_check_timer(unsigned long data)
276 +{
277 + struct n810bm *bm = (struct n810bm *)data;
278 + unsigned long flags;
279 + int mv;
280 +
281 + spin_lock_irqsave(&bm->lock, flags);
282 +
283 + mv = n810bm_measure_batt_voltage(bm);
284 + if (mv < 0)
285 + n810bm_emergency(bm, "check timer: Failed to measure");
286 + if (mv < N810BM_MIN_VOLTAGE_THRES)
287 + n810bm_emergency(bm, "check timer: Minimum voltage threshold reached");
288 +
289 + mod_timer(&bm->check_timer, round_jiffies(jiffies + N810BM_CHECK_INTERVAL));
290 + spin_unlock_irqrestore(&bm->lock, flags);
291 +
292 + return;
293 +}
294 +
295 +static void n810bm_adc_irq_handler(unsigned long data)
296 +{
297 + struct n810bm *bm = (struct n810bm *)data;
298 +
299 + retu_ack_irq(RETU_INT_ADCS);
300 + //TODO
301 +printk("n810bm: ADC timer triggered\n");
302 +}
303 +
304 +static ssize_t n810bm_attr_charge_show(struct device *dev,
305 + struct device_attribute *attr,
306 + char *buf)
307 +{
308 + struct platform_device *pdev = to_platform_device(dev);
309 + struct n810bm *bm = platform_get_drvdata(pdev);
310 + int err = -ENODEV;
311 + ssize_t count = 0;
312 + int millivolt;
313 +
314 + spin_lock_irq(&bm->lock);
315 + millivolt = n810bm_measure_batt_voltage(bm);
316 + if (millivolt >= 0) {
317 + count = snprintf(buf, PAGE_SIZE, "%u\n",
318 + n810bm_mvolt2percent(millivolt));
319 + err = 0;
320 + }
321 + spin_unlock_irq(&bm->lock);
322 +
323 + return err ? err : count;
324 +}
325 +static DEVICE_ATTR(batt_charge, 0444, n810bm_attr_charge_show, NULL);
326 +
327 +static ssize_t n810bm_attr_capacity_show(struct device *dev,
328 + struct device_attribute *attr,
329 + char *buf)
330 +{
331 + struct platform_device *pdev = to_platform_device(dev);
332 + struct n810bm *bm = platform_get_drvdata(pdev);
333 + ssize_t count;
334 +
335 + spin_lock_irq(&bm->lock);
336 + count = snprintf(buf, PAGE_SIZE, "%u\n",
337 + (unsigned int)bm->capacity);
338 + spin_unlock_irq(&bm->lock);
339 +
340 + return count;
341 +}
342 +static DEVICE_ATTR(batt_capacity, 0444, n810bm_attr_capacity_show, NULL);
343 +
344 +static void n810bm_hw_exit(struct n810bm *bm)
345 +{
346 + retu_write(bm, RETU_REG_ADCSCR, 0);
347 +}
348 +
349 +static int n810bm_hw_init(struct n810bm *bm)
350 +{
351 + retu_write(bm, RETU_REG_ADCSCR, 0);
352 +
353 + bm->capacity = n810bm_read_batt_capacity(bm);
354 + if (bm->capacity == N810BM_CAP_UNKNOWN) {
355 + dev_err(&bm->pdev->dev, "Unknown battery detected");
356 + return -ENODEV;
357 + }
358 + dev_info(&bm->pdev->dev, "Detected %u mAh battery\n",
359 + (unsigned int)bm->capacity);
360 +
361 + return 0;
362 +}
363 +
364 +static int __devinit n810bm_probe(struct platform_device *pdev)
365 +{
366 + struct n810bm *bm;
367 + int err;
368 +
369 + bm = kzalloc(sizeof(*bm), GFP_KERNEL);
370 + if (!bm)
371 + return -ENOMEM;
372 + bm->pdev = pdev;
373 + platform_set_drvdata(pdev, bm);
374 + spin_lock_init(&bm->lock);
375 + setup_timer(&bm->check_timer, n810bm_check_timer, (unsigned long)bm);
376 +
377 + err = n810bm_hw_init(bm);
378 + if (err)
379 + goto err_free;
380 + err = device_create_file(&pdev->dev, &dev_attr_batt_charge);
381 + if (err)
382 + goto err_exit;
383 + err = device_create_file(&pdev->dev, &dev_attr_batt_capacity);
384 + if (err)
385 + goto err_rem_charge;
386 + err = retu_request_irq(RETU_INT_ADCS, n810bm_adc_irq_handler,
387 + (unsigned long)bm, "n810bm");
388 + if (err)
389 + goto err_rem_capa;
390 +
391 + mod_timer(&bm->check_timer, round_jiffies(jiffies + N810BM_CHECK_INTERVAL));
392 +
393 + dev_info(&pdev->dev, "Battery management initialized");
394 +
395 + return 0;
396 +
397 +err_rem_capa:
398 + device_remove_file(&pdev->dev, &dev_attr_batt_capacity);
399 +err_rem_charge:
400 + device_remove_file(&pdev->dev, &dev_attr_batt_charge);
401 +err_exit:
402 + n810bm_hw_exit(bm);
403 +err_free:
404 + kfree(bm);
405 + platform_set_drvdata(pdev, NULL);
406 + return err;
407 +}
408 +
409 +static int __devexit n810bm_remove(struct platform_device *pdev)
410 +{
411 + struct n810bm *bm = platform_get_drvdata(pdev);
412 +
413 + retu_free_irq(RETU_INT_ADCS);
414 + del_timer_sync(&bm->check_timer);
415 + device_remove_file(&pdev->dev, &dev_attr_batt_capacity);
416 + device_remove_file(&pdev->dev, &dev_attr_batt_charge);
417 + n810bm_hw_exit(bm);
418 +
419 + kfree(bm);
420 + platform_set_drvdata(pdev, NULL);
421 +
422 + return 0;
423 +}
424 +
425 +static struct platform_driver n810bm_driver = {
426 + .remove = __devexit_p(n810bm_remove),
427 + .driver = {
428 + .name = "n810bm",
429 + }
430 +};
431 +
432 +static int __init n810bm_modinit(void)
433 +{
434 + return platform_driver_probe(&n810bm_driver, n810bm_probe);
435 +}
436 +module_init(n810bm_modinit);
437 +
438 +static void __exit n810bm_modexit(void)
439 +{
440 + platform_driver_unregister(&n810bm_driver);
441 +}
442 +module_exit(n810bm_modexit);
443 +
444 +MODULE_DESCRIPTION("Nokia n810 battery management");
445 +MODULE_LICENSE("GPL");
446 +MODULE_AUTHOR("Michael Buesch");
447 Index: linux-2.6.37-rc1/drivers/cbus/retu.c
448 ===================================================================
449 --- linux-2.6.37-rc1.orig/drivers/cbus/retu.c 2010-11-05 17:38:14.834000050 +0100
450 +++ linux-2.6.37-rc1/drivers/cbus/retu.c 2010-11-05 17:38:14.895000001 +0100
451 @@ -85,10 +85,10 @@
452 *
453 * This function writes a value to the specified register
454 */
455 -void retu_write_reg(int reg, u16 val)
456 +int retu_write_reg(int reg, u16 val)
457 {
458 BUG_ON(!retu_initialized);
459 - cbus_write_reg(cbus_host, RETU_ID, reg, val);
460 + return cbus_write_reg(cbus_host, RETU_ID, reg, val);
461 }
462
463 void retu_set_clear_reg_bits(int reg, u16 set, u16 clear)
464 Index: linux-2.6.37-rc1/drivers/cbus/retu.h
465 ===================================================================
466 --- linux-2.6.37-rc1.orig/drivers/cbus/retu.h 2010-11-05 17:38:14.834000050 +0100
467 +++ linux-2.6.37-rc1/drivers/cbus/retu.h 2010-11-05 17:38:14.895000001 +0100
468 @@ -39,6 +39,7 @@
469 #define RETU_REG_CC2 0x0e /* Common control register 2 */
470 #define RETU_REG_CTRL_CLR 0x0f /* Regulator clear register */
471 #define RETU_REG_CTRL_SET 0x10 /* Regulator set register */
472 +#define RETU_REG_UNK1 0x14 /* 0x1000 is set when charger is plugged in */
473 #define RETU_REG_STATUS 0x16 /* Status register */
474 #define RETU_REG_WATCHDOG 0x17 /* Watchdog register */
475 #define RETU_REG_AUDTXR 0x18 /* Audio Codec Tx register */
476 @@ -58,7 +59,7 @@
477 #define MAX_RETU_IRQ_HANDLERS 16
478
479 int retu_read_reg(int reg);
480 -void retu_write_reg(int reg, u16 val);
481 +int retu_write_reg(int reg, u16 val);
482 void retu_set_clear_reg_bits(int reg, u16 set, u16 clear);
483 int retu_read_adc(int channel);
484 int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name);
485 Index: linux-2.6.37-rc1/arch/arm/mach-omap2/board-n8x0.c
486 ===================================================================
487 --- linux-2.6.37-rc1.orig/arch/arm/mach-omap2/board-n8x0.c 2010-11-05 17:38:14.819000329 +0100
488 +++ linux-2.6.37-rc1/arch/arm/mach-omap2/board-n8x0.c 2010-11-05 17:38:14.895000001 +0100
489 @@ -908,6 +908,17 @@
490 ARRAY_SIZE(n8x0_gpio_switches));
491 }
492
493 +static struct platform_device n810_bm_device = {
494 + .name = "n810bm",
495 + .id = -1,
496 +};
497 +
498 +static void __init n810_bm_init(void)
499 +{
500 + if (platform_device_register(&n810_bm_device))
501 + BUG();
502 +}
503 +
504 static void __init n8x0_init_machine(void)
505 {
506 omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC);
507 @@ -930,6 +941,8 @@
508 n8x0_onenand_init();
509 n8x0_mmc_init();
510 n8x0_usb_init();
511 +
512 + n810_bm_init();
513 }
514
515 MACHINE_START(NOKIA_N800, "Nokia N800")
516 Index: linux-2.6.37-rc1/drivers/cbus/lipocharge.c
517 ===================================================================
518 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
519 +++ linux-2.6.37-rc1/drivers/cbus/lipocharge.c 2010-11-05 17:38:14.895000001 +0100
520 @@ -0,0 +1,63 @@
521 +/*
522 + * Generic LIPO battery charger
523 + *
524 + * Copyright (c) 2010 Michael Buesch <mb@bu3sch.de>
525 + *
526 + * This program is free software; you can redistribute it and/or
527 + * modify it under the terms of the GNU General Public License
528 + * as published by the Free Software Foundation; either version 2
529 + * of the License, or (at your option) any later version.
530 + *
531 + * This program is distributed in the hope that it will be useful,
532 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
533 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
534 + * GNU General Public License for more details.
535 + */
536 +
537 +#include "lipocharge.h"
538 +
539 +#include <linux/slab.h>
540 +
541 +
542 +static void lipocharge_timer(unsigned long data)
543 +{
544 + struct lipocharge *c = (struct lipocharge *)data;
545 +
546 + spin_lock(&c->lock);
547 + //TODO
548 + spin_unlock(&c->lock);
549 +}
550 +
551 +struct lipocharge * lipocharge_alloc(gfp_t gfp)
552 +{
553 + struct lipocharge *c;
554 +
555 + c = kzalloc(sizeof(*c), gfp);
556 + if (!c)
557 + return NULL;
558 + spin_lock_init(&c->lock);
559 + setup_timer(&c->timer, lipocharge_timer, (unsigned long)c);
560 +
561 + return c;
562 +}
563 +
564 +void lipocharge_free(struct lipocharge *c)
565 +{
566 + kfree(c);
567 +}
568 +
569 +int lipocharge_start(struct lipocharge *c)
570 +{
571 + if (!c->set_current || !c->get_voltage ||
572 + !c->finished || !c->emergency)
573 + return -EINVAL;
574 + if (!c->top_voltage || c->top_voltage > 4200)
575 + return -EINVAL;
576 + //TODO
577 +}
578 +
579 +void lipocharge_stop(struct lipocharge *c)
580 +{
581 + del_timer_sync(&c->timer);
582 + //TODO
583 +}
584 Index: linux-2.6.37-rc1/drivers/cbus/lipocharge.h
585 ===================================================================
586 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
587 +++ linux-2.6.37-rc1/drivers/cbus/lipocharge.h 2010-11-05 17:38:14.895000001 +0100
588 @@ -0,0 +1,50 @@
589 +#ifndef LIPOCHARGE_H_
590 +#define LIPOCHARGE_H_
591 +
592 +#include <linux/timer.h>
593 +#include <linux/spinlock.h>
594 +
595 +
596 +#define LIPORATE(a,b) (((a) * 1000) + (b))
597 +#define LIPORATE_1C LIPORATE(1,0) /* 1C */
598 +#define LIPORATE_p8C LIPORATE(0,8) /* 0.8C */
599 +
600 +/** struct lipocharge - A generic LIPO charger
601 + *
602 + * @capacity: Battery capacity in mAh.
603 + * @rate: Charge rate.
604 + * @top_voltage: Fully charged voltage, in mV.
605 + *
606 + * @set_current: Set the charge current, in mA.
607 + * @get_voltage: Get the battery voltage, in mV.
608 + *
609 + * @emergency: Something went wrong. Force shutdown.
610 + *
611 + * @priv: opaque pointer.
612 + */
613 +struct lipocharge
614 +{
615 + unsigned int capacity;
616 + unsigned int rate;
617 + unsigned int top_voltage;
618 +
619 + int (*set_current)(struct lipocharge *c, unsigned int ma);
620 + int (*get_voltage)(struct lipocharge *c, unsigned int *mv);
621 +
622 + void (*finished)(struct lipocharge *c);
623 + void (*emergency)(struct lipocharge *c);
624 +
625 + void *priv;
626 +
627 + /* internal */
628 + spinlock_t lock;
629 + struct timer_list timer;
630 +};
631 +
632 +struct lipocharge * lipocharge_alloc(gfp_t gfp);
633 +void lipocharge_free(struct lipocharge *c);
634 +
635 +int lipocharge_start(struct lipocharge *c);
636 +void lipocharge_stop(struct lipocharge *c);
637 +
638 +#endif /* LIPOCHARGE_H_ */
639 Index: linux-2.6.37-rc1/drivers/cbus/tahvo.h
640 ===================================================================
641 --- linux-2.6.37-rc1.orig/drivers/cbus/tahvo.h 2010-11-05 17:38:14.835000037 +0100
642 +++ linux-2.6.37-rc1/drivers/cbus/tahvo.h 2010-11-05 17:38:14.895000001 +0100
643 @@ -30,8 +30,14 @@
644 #define TAHVO_REG_IDR 0x01 /* Interrupt ID */
645 #define TAHVO_REG_IDSR 0x02 /* Interrupt status */
646 #define TAHVO_REG_IMR 0x03 /* Interrupt mask */
647 +#define TAHVO_REG_CHGCURR 0x04 /* Charge current control (8-bit) */
648 #define TAHVO_REG_LEDPWMR 0x05 /* LED PWM */
649 #define TAHVO_REG_USBR 0x06 /* USB control */
650 +#define TAHVO_REG_CHGCTL 0x08 /* Charge control register */
651 +#define TAHVO_REG_CHGCTL_EN 0x0001 /* Global charge enable */
652 +#define TAHVO_REG_CHGCTL2 0x0c /* Charge control register 2 */
653 +#define TAHVO_REG_BATCURR 0x0d /* Battery (dis)charge current (signed 16-bit) */
654 +
655 #define TAHVO_REG_MAX 0x0d
656
657 /* Interrupt sources */