summaryrefslogtreecommitdiffstats
path: root/extras/recipes-kernel/linux/linux-omap-psp-2.6.32/omap3-touchbook/0015-Forward-port-TWL4030-BCI-driver-from-2.6.29-to-2.6.3.patch
diff options
context:
space:
mode:
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap-psp-2.6.32/omap3-touchbook/0015-Forward-port-TWL4030-BCI-driver-from-2.6.29-to-2.6.3.patch')
-rw-r--r--extras/recipes-kernel/linux/linux-omap-psp-2.6.32/omap3-touchbook/0015-Forward-port-TWL4030-BCI-driver-from-2.6.29-to-2.6.3.patch1367
1 files changed, 1367 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap-psp-2.6.32/omap3-touchbook/0015-Forward-port-TWL4030-BCI-driver-from-2.6.29-to-2.6.3.patch b/extras/recipes-kernel/linux/linux-omap-psp-2.6.32/omap3-touchbook/0015-Forward-port-TWL4030-BCI-driver-from-2.6.29-to-2.6.3.patch
new file mode 100644
index 00000000..562c459e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap-psp-2.6.32/omap3-touchbook/0015-Forward-port-TWL4030-BCI-driver-from-2.6.29-to-2.6.3.patch
@@ -0,0 +1,1367 @@
1From c3a08f3d696866508ef2b5e2fd065b8295b3e1a8 Mon Sep 17 00:00:00 2001
2From: Tim Yamin <plasm@roo.me.uk>
3Date: Sun, 9 May 2010 10:14:23 +0200
4Subject: [PATCH 15/17] Forward port TWL4030 BCI driver from 2.6.29 to 2.6.31 with AI enhancements.
5
6Signed-off-by: Tim Yamin <plasm@roo.me.uk>
7---
8 drivers/power/Kconfig | 7 +
9 drivers/power/Makefile | 1 +
10 drivers/power/twl4030_bci_battery.c | 1307 +++++++++++++++++++++++++++++++++++
11 include/linux/i2c/twl.h | 1 +
12 4 files changed, 1316 insertions(+), 0 deletions(-)
13 create mode 100644 drivers/power/twl4030_bci_battery.c
14
15diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
16index d4b3d67..8345b3f 100644
17--- a/drivers/power/Kconfig
18+++ b/drivers/power/Kconfig
19@@ -124,4 +124,11 @@ config CHARGER_PCF50633
20 help
21 Say Y to include support for NXP PCF50633 Main Battery Charger.
22
23+config TWL4030_BCI_BATTERY
24+ tristate "OMAP TWL4030 BCI Battery driver"
25+ depends on TWL4030_CORE && TWL4030_MADC
26+ help
27+ Support for OMAP TWL4030 BCI Battery driver.
28+ This driver can give support for TWL4030 Battery Charge Interface.
29+
30 endif # POWER_SUPPLY
31diff --git a/drivers/power/Makefile b/drivers/power/Makefile
32index 573597c..7801da7 100644
33--- a/drivers/power/Makefile
34+++ b/drivers/power/Makefile
35@@ -31,3 +31,4 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
36 obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
37 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
38 obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
39+obj-$(CONFIG_TWL4030_BCI_BATTERY) += twl4030_bci_battery.o
40diff --git a/drivers/power/twl4030_bci_battery.c b/drivers/power/twl4030_bci_battery.c
41new file mode 100644
42index 0000000..0876fc3
43--- /dev/null
44+++ b/drivers/power/twl4030_bci_battery.c
45@@ -0,0 +1,1307 @@
46+/*
47+ * linux/drivers/power/twl4030_bci_battery.c
48+ *
49+ * OMAP2430/3430 BCI battery driver for Linux
50+ *
51+ * Copyright (C) 2008 Texas Instruments, Inc.
52+ * Author: Texas Instruments, Inc.
53+ *
54+ * Copyright (C) 2010 Always Innovating
55+ * Author: Tim Yamin <plasm@roo.me.uk>
56+ *
57+ * This package is free software; you can redistribute it and/or modify
58+ * it under the terms of the GNU General Public License version 2 as
59+ * published by the Free Software Foundation.
60+ *
61+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
62+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
63+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
64+ */
65+
66+/* Boot with automatic charge */
67+#define CHARGE_MODE 1
68+
69+#include <linux/init.h>
70+#include <linux/module.h>
71+#include <linux/device.h>
72+#include <linux/interrupt.h>
73+#include <linux/delay.h>
74+#include <linux/platform_device.h>
75+#include <linux/i2c/twl.h>
76+#include <linux/power_supply.h>
77+#include <linux/i2c/twl4030-madc.h>
78+
79+#define T2_BATTERY_VOLT 0x04
80+#define T2_BATTERY_TEMP 0x06
81+#define T2_BATTERY_CUR 0x08
82+
83+/* charger constants */
84+#define NO_PW_CONN 0
85+#define AC_PW_CONN 0x01
86+#define USB_PW_CONN 0x02
87+
88+/* TWL4030_MODULE_USB */
89+#define REG_POWER_CTRL 0x0AC
90+#define OTG_EN 0x020
91+#define REG_PHY_CLK_CTRL 0x0FE
92+#define REG_PHY_CLK_CTRL_STS 0x0FF
93+#define PHY_DPLL_CLK 0x01
94+
95+#define REG_BCICTL1 0x023
96+#define REG_BCICTL2 0x024
97+#define CGAIN 0x020
98+#define ITHEN 0x010
99+#define ITHSENS 0x007
100+
101+/* Boot BCI flag bits */
102+#define BCIAUTOWEN 0x020
103+#define CONFIG_DONE 0x010
104+#define CVENAC 0x004
105+#define BCIAUTOUSB 0x002
106+#define BCIAUTOAC 0x001
107+#define BCIMSTAT_MASK 0x03F
108+
109+/* Boot BCI register */
110+#define REG_BOOT_BCI 0x007
111+#define REG_CTRL1 0x00
112+#define REG_SW1SELECT_MSB 0x07
113+#define SW1_CH9_SEL 0x02
114+#define REG_CTRL_SW1 0x012
115+#define SW1_TRIGGER 0x020
116+#define EOC_SW1 0x002
117+#define REG_GPCH9 0x049
118+#define REG_STS_HW_CONDITIONS 0x0F
119+#define STS_VBUS 0x080
120+#define STS_CHG 0x02
121+#define REG_BCIMSTATEC 0x02
122+#define REG_BCIMFSTS4 0x010
123+#define REG_BCIMFSTS2 0x00E
124+#define REG_BCIMFSTS3 0x00F
125+#define REG_BCIMFSTS1 0x001
126+#define USBFASTMCHG 0x004
127+#define BATSTSPCHG 0x004
128+#define BATSTSMCHG 0x040
129+#define VBATOV4 0x020
130+#define VBATOV3 0x010
131+#define VBATOV2 0x008
132+#define VBATOV1 0x004
133+#define REG_BB_CFG 0x012
134+#define BBCHEN 0x010
135+
136+/* GPBR */
137+#define REG_GPBR1 0x0c
138+#define MADC_HFCLK_EN 0x80
139+#define DEFAULT_MADC_CLK_EN 0x10
140+
141+/* Power supply charge interrupt */
142+#define REG_PWR_ISR1 0x00
143+#define REG_PWR_IMR1 0x01
144+#define REG_PWR_EDR1 0x05
145+#define REG_PWR_SIH_CTRL 0x007
146+
147+#define USB_PRES 0x004
148+#define CHG_PRES 0x002
149+
150+#define USB_PRES_RISING 0x020
151+#define USB_PRES_FALLING 0x010
152+#define CHG_PRES_RISING 0x008
153+#define CHG_PRES_FALLING 0x004
154+#define AC_STATEC 0x20
155+#define COR 0x004
156+
157+/* interrupt status registers */
158+#define REG_BCIISR1A 0x0
159+#define REG_BCIISR2A 0x01
160+
161+/* Interrupt flags bits BCIISR1 */
162+#define BATSTS_ISR1 0x080
163+#define VBATLVL_ISR1 0x001
164+
165+/* Interrupt mask registers for int1*/
166+#define REG_BCIIMR1A 0x002
167+#define REG_BCIIMR2A 0x003
168+
169+ /* Interrupt masks for BCIIMR1 */
170+#define BATSTS_IMR1 0x080
171+#define VBATLVL_IMR1 0x001
172+
173+/* Interrupt edge detection register */
174+#define REG_BCIEDR1 0x00A
175+#define REG_BCIEDR2 0x00B
176+#define REG_BCIEDR3 0x00C
177+
178+/* BCIEDR2 */
179+#define BATSTS_EDRRISIN 0x080
180+#define BATSTS_EDRFALLING 0x040
181+
182+/* BCIEDR3 */
183+#define VBATLVL_EDRRISIN 0x02
184+
185+/* BCIIREF1 */
186+#define REG_BCIIREF1 0x027
187+#define REG_BCIIREF2 0x028
188+
189+/* BCIMFTH1 */
190+#define REG_BCIMFTH1 0x016
191+
192+/* Key */
193+#define KEY_IIREF 0xE7
194+#define KEY_FTH1 0xD2
195+#define REG_BCIMFKEY 0x011
196+
197+/* Step size and prescaler ratio */
198+#define TEMP_STEP_SIZE 147
199+#define TEMP_PSR_R 100
200+
201+#define VOLT_STEP_SIZE 588
202+#define VOLT_PSR_R 100
203+
204+#define CURR_STEP_SIZE 147
205+#define CURR_PSR_R1 44
206+#define CURR_PSR_R2 80
207+
208+#define BK_VOLT_STEP_SIZE 441
209+#define BK_VOLT_PSR_R 100
210+
211+#define ENABLE 1
212+#define DISABLE 1
213+
214+struct twl4030_bci_device_info {
215+ struct device *dev;
216+
217+ unsigned long update_time;
218+ int voltage_uV;
219+ int bk_voltage_uV;
220+ int current_uA;
221+ int temp_C;
222+ int charge_rsoc;
223+ int charge_status;
224+
225+ struct power_supply bat;
226+ struct power_supply bk_bat;
227+ struct delayed_work twl4030_bci_monitor_work;
228+ struct delayed_work twl4030_bk_bci_monitor_work;
229+
230+ struct twl4030_bci_platform_data *pdata;
231+};
232+
233+static int usb_charger_flag;
234+static int LVL_1, LVL_2, LVL_3, LVL_4;
235+
236+static int read_bci_val(u8 reg_1);
237+static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg);
238+static int twl4030charger_presence(void);
239+
240+/*
241+ * Report and clear the charger presence event.
242+ */
243+static inline int twl4030charger_presence_evt(void)
244+{
245+ int ret;
246+ u8 chg_sts, set = 0, clear = 0;
247+
248+ /* read charger power supply status */
249+ ret = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts,
250+ REG_STS_HW_CONDITIONS);
251+ if (ret)
252+ return IRQ_NONE;
253+
254+ if (chg_sts & STS_CHG) { /* If the AC charger have been connected */
255+ /* configuring falling edge detection for CHG_PRES */
256+ set = CHG_PRES_FALLING;
257+ clear = CHG_PRES_RISING;
258+ } else { /* If the AC charger have been disconnected */
259+ /* configuring rising edge detection for CHG_PRES */
260+ set = CHG_PRES_RISING;
261+ clear = CHG_PRES_FALLING;
262+ }
263+
264+ /* Update the interrupt edge detection register */
265+ clear_n_set(TWL4030_MODULE_INT, clear, set, REG_PWR_EDR1);
266+
267+ return 0;
268+}
269+
270+/*
271+ * Interrupt service routine
272+ *
273+ * Attends to TWL 4030 power module interruptions events, specifically
274+ * USB_PRES (USB charger presence) CHG_PRES (AC charger presence) events
275+ *
276+ */
277+static irqreturn_t twl4030charger_interrupt(int irq, void *_di)
278+{
279+ struct twl4030_bci_device_info *di = _di;
280+
281+#ifdef CONFIG_LOCKDEP
282+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
283+ * we don't want and can't tolerate. Although it might be
284+ * friendlier not to borrow this thread context...
285+ */
286+ local_irq_enable();
287+#endif
288+
289+ twl4030charger_presence_evt();
290+ power_supply_changed(&di->bat);
291+
292+ return IRQ_HANDLED;
293+}
294+
295+/*
296+ * This function handles the twl4030 battery presence interrupt
297+ */
298+static int twl4030battery_presence_evt(void)
299+{
300+ int ret;
301+ u8 batstsmchg, batstspchg;
302+
303+ /* check for the battery presence in main charge*/
304+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
305+ &batstsmchg, REG_BCIMFSTS3);
306+ if (ret)
307+ return ret;
308+
309+ /* check for the battery presence in precharge */
310+ ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE,
311+ &batstspchg, REG_BCIMFSTS1);
312+ if (ret)
313+ return ret;
314+
315+ /*
316+ * REVISIT: Physically inserting/removing the batt
317+ * does not seem to generate an int on 3430ES2 SDP.
318+ */
319+ if ((batstspchg & BATSTSPCHG) || (batstsmchg & BATSTSMCHG)) {
320+ /* In case of the battery insertion event */
321+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRRISIN,
322+ BATSTS_EDRFALLING, REG_BCIEDR2);
323+ if (ret)
324+ return ret;
325+ } else {
326+ /* In case of the battery removal event */
327+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRFALLING,
328+ BATSTS_EDRRISIN, REG_BCIEDR2);
329+ if (ret)
330+ return ret;
331+ }
332+
333+ return 0;
334+}
335+
336+/*
337+ * This function handles the twl4030 battery voltage level interrupt.
338+ */
339+static int twl4030battery_level_evt(void)
340+{
341+ int ret;
342+ u8 mfst;
343+
344+ /* checking for threshold event */
345+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
346+ &mfst, REG_BCIMFSTS2);
347+ if (ret)
348+ return ret;
349+
350+ /* REVISIT could use a bitmap */
351+ if (mfst & VBATOV4) {
352+ LVL_4 = 1;
353+ LVL_3 = 0;
354+ LVL_2 = 0;
355+ LVL_1 = 0;
356+ } else if (mfst & VBATOV3) {
357+ LVL_4 = 0;
358+ LVL_3 = 1;
359+ LVL_2 = 0;
360+ LVL_1 = 0;
361+ } else if (mfst & VBATOV2) {
362+ LVL_4 = 0;
363+ LVL_3 = 0;
364+ LVL_2 = 1;
365+ LVL_1 = 0;
366+ } else {
367+ LVL_4 = 0;
368+ LVL_3 = 0;
369+ LVL_2 = 0;
370+ LVL_1 = 1;
371+ }
372+
373+ return 0;
374+}
375+
376+/*
377+ * Interrupt service routine
378+ *
379+ * Attends to BCI interruptions events,
380+ * specifically BATSTS (battery connection and removal)
381+ * VBATOV (main battery voltage threshold) events
382+ *
383+ */
384+static irqreturn_t twl4030battery_interrupt(int irq, void *_di)
385+{
386+ u8 isr1a_val, isr2a_val, clear_2a, clear_1a;
387+ int ret;
388+
389+#ifdef CONFIG_LOCKDEP
390+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
391+ * we don't want and can't tolerate. Although it might be
392+ * friendlier not to borrow this thread context...
393+ */
394+ local_irq_enable();
395+#endif
396+
397+ ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr1a_val,
398+ REG_BCIISR1A);
399+ if (ret)
400+ return IRQ_NONE;
401+
402+ ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr2a_val,
403+ REG_BCIISR2A);
404+ if (ret)
405+ return IRQ_NONE;
406+
407+ clear_2a = (isr2a_val & VBATLVL_ISR1) ? (VBATLVL_ISR1) : 0;
408+ clear_1a = (isr1a_val & BATSTS_ISR1) ? (BATSTS_ISR1) : 0;
409+
410+ /* cleaning BCI interrupt status flags */
411+ ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
412+ clear_1a , REG_BCIISR1A);
413+ if (ret)
414+ return IRQ_NONE;
415+
416+ ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
417+ clear_2a , REG_BCIISR2A);
418+ if (ret)
419+ return IRQ_NONE;
420+
421+ /* battery connetion or removal event */
422+ if (isr1a_val & BATSTS_ISR1)
423+ twl4030battery_presence_evt();
424+ /* battery voltage threshold event*/
425+ else if (isr2a_val & VBATLVL_ISR1)
426+ twl4030battery_level_evt();
427+ else
428+ return IRQ_NONE;
429+
430+ return IRQ_HANDLED;
431+}
432+
433+/*
434+ * Enable/Disable hardware battery level event notifications.
435+ */
436+static int twl4030battery_hw_level_en(int enable)
437+{
438+ int ret;
439+
440+ if (enable) {
441+ /* unmask VBATOV interrupt for INT1 */
442+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, VBATLVL_IMR1,
443+ 0, REG_BCIIMR2A);
444+ if (ret)
445+ return ret;
446+
447+ /* configuring interrupt edge detection for VBATOv */
448+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
449+ VBATLVL_EDRRISIN, REG_BCIEDR3);
450+ if (ret)
451+ return ret;
452+ } else {
453+ /* mask VBATOV interrupt for INT1 */
454+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
455+ VBATLVL_IMR1, REG_BCIIMR2A);
456+ if (ret)
457+ return ret;
458+ }
459+
460+ return 0;
461+}
462+
463+/*
464+ * Enable/disable hardware battery presence event notifications.
465+ */
466+static int twl4030battery_hw_presence_en(int enable)
467+{
468+ int ret;
469+
470+ if (enable) {
471+ /* unmask BATSTS interrupt for INT1 */
472+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_IMR1,
473+ 0, REG_BCIIMR1A);
474+ if (ret)
475+ return ret;
476+
477+ /* configuring interrupt edge for BATSTS */
478+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
479+ BATSTS_EDRRISIN | BATSTS_EDRFALLING, REG_BCIEDR2);
480+ if (ret)
481+ return ret;
482+ } else {
483+ /* mask BATSTS interrupt for INT1 */
484+ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
485+ BATSTS_IMR1, REG_BCIIMR1A);
486+ if (ret)
487+ return ret;
488+ }
489+
490+ return 0;
491+}
492+
493+/*
494+ * Enable/Disable AC Charge funtionality.
495+ */
496+static int twl4030charger_ac_en(int enable, int automatic)
497+{
498+ int ret;
499+
500+ if (enable) {
501+ /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 1 */
502+ if(!automatic) {
503+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC | CVENAC,
504+ (CONFIG_DONE | BCIAUTOWEN),
505+ REG_BOOT_BCI);
506+ } else {
507+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
508+ (CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC | CVENAC),
509+ REG_BOOT_BCI);
510+ }
511+ if (ret)
512+ return ret;
513+ } else {
514+ /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 0*/
515+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC,
516+ (CONFIG_DONE | BCIAUTOWEN),
517+ REG_BOOT_BCI);
518+ if (ret)
519+ return ret;
520+ }
521+
522+ return 0;
523+}
524+
525+/*
526+ * Enable/Disable USB Charge funtionality.
527+ */
528+int twl4030charger_usb_en(int enable)
529+{
530+ u8 value;
531+ int ret;
532+ unsigned long timeout;
533+
534+ if (enable) {
535+ /* Check for USB charger conneted */
536+ ret = twl4030charger_presence();
537+ if (ret < 0)
538+ return ret;
539+
540+ if (!(ret & USB_PW_CONN))
541+ return -ENXIO;
542+
543+ /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
544+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
545+ (CONFIG_DONE | BCIAUTOWEN | BCIAUTOUSB),
546+ REG_BOOT_BCI);
547+ if (ret)
548+ return ret;
549+
550+ ret = clear_n_set(TWL4030_MODULE_USB, 0, PHY_DPLL_CLK,
551+ REG_PHY_CLK_CTRL);
552+ if (ret)
553+ return ret;
554+
555+ value = 0;
556+ timeout = jiffies + msecs_to_jiffies(50);
557+
558+ while ((!(value & PHY_DPLL_CLK)) &&
559+ time_before(jiffies, timeout)) {
560+ udelay(10);
561+ ret = twl_i2c_read_u8(TWL4030_MODULE_USB, &value,
562+ REG_PHY_CLK_CTRL_STS);
563+ if (ret)
564+ return ret;
565+ }
566+
567+ /* OTG_EN (POWER_CTRL[5]) to 1 */
568+ ret = clear_n_set(TWL4030_MODULE_USB, 0, OTG_EN,
569+ REG_POWER_CTRL);
570+ if (ret)
571+ return ret;
572+
573+ mdelay(50);
574+
575+ /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
576+ ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0,
577+ USBFASTMCHG, REG_BCIMFSTS4);
578+ if (ret)
579+ return ret;
580+ } else {
581+ twl4030charger_presence();
582+ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOUSB,
583+ (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI);
584+ if (ret)
585+ return ret;
586+ }
587+
588+ return 0;
589+}
590+
591+/*
592+ * Return battery temperature
593+ * Or < 0 on failure.
594+ */
595+static int twl4030battery_temperature(struct twl4030_bci_device_info *di)
596+{
597+ u8 val;
598+ int temp, curr, volt, res, ret;
599+
600+ /* Is a temperature table specified? */
601+ if (!di->pdata->tblsize)
602+ return 0;
603+
604+ /* Getting and calculating the thermistor voltage */
605+ ret = read_bci_val(T2_BATTERY_TEMP);
606+ if (ret < 0)
607+ return ret;
608+
609+ volt = (ret * TEMP_STEP_SIZE) / TEMP_PSR_R;
610+
611+ /* Getting and calculating the supply current in micro ampers */
612+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
613+ REG_BCICTL2);
614+ if (ret)
615+ return 0;
616+
617+ curr = ((val & ITHSENS) + 1) * 10;
618+
619+ /* Getting and calculating the thermistor resistance in ohms*/
620+ res = volt * 1000 / curr;
621+
622+ /*calculating temperature*/
623+ for (temp = 58; temp >= 0; temp--) {
624+ int actual = di->pdata->battery_tmp_tbl[temp];
625+ if ((actual - res) >= 0)
626+ break;
627+ }
628+
629+ /* Negative temperature */
630+ if (temp < 3) {
631+ if (temp == 2)
632+ temp = -1;
633+ else if (temp == 1)
634+ temp = -2;
635+ else
636+ temp = -3;
637+ }
638+
639+ return temp + 1;
640+}
641+
642+/*
643+ * Return battery voltage
644+ * Or < 0 on failure.
645+ */
646+static int twl4030battery_voltage(void)
647+{
648+ int volt = read_bci_val(T2_BATTERY_VOLT);
649+ return (volt * VOLT_STEP_SIZE) / VOLT_PSR_R;
650+}
651+
652+/*
653+ * Get latest battery voltage (using MADC)
654+ *
655+ * When the BCI is not charging, the BCI voltage registers are not
656+ * updated and are 'frozen' but the data can be read through the
657+ * MADC.
658+ */
659+static int twl4030battery_voltage_madc(void)
660+{
661+ struct twl4030_madc_request req;
662+
663+ req.channels = (1 << 12);
664+ req.do_avg = 0;
665+ req.method = TWL4030_MADC_SW1;
666+ req.active = 0;
667+ req.func_cb = NULL;
668+ twl4030_madc_conversion(&req);
669+
670+ return (((int) req.rbuf[12]) * VOLT_STEP_SIZE) / VOLT_PSR_R;
671+}
672+
673+/*
674+ * Return the battery current
675+ * Or < 0 on failure.
676+ */
677+static int twl4030battery_current(void)
678+{
679+ int ret, curr = read_bci_val(T2_BATTERY_CUR);
680+ u8 val;
681+
682+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
683+ REG_BCICTL1);
684+ if (ret)
685+ return ret;
686+
687+ if (val & CGAIN) /* slope of 0.44 mV/mA */
688+ return (curr * CURR_STEP_SIZE) / CURR_PSR_R1;
689+ else /* slope of 0.88 mV/mA */
690+ return (curr * CURR_STEP_SIZE) / CURR_PSR_R2;
691+}
692+
693+/*
694+ * Return the battery backup voltage
695+ * Or < 0 on failure.
696+ */
697+static int twl4030backupbatt_voltage(void)
698+{
699+ struct twl4030_madc_request req;
700+ int temp;
701+
702+ req.channels = (1 << 9);
703+ req.do_avg = 0;
704+ req.method = TWL4030_MADC_SW1;
705+ req.active = 0;
706+ req.func_cb = NULL;
707+ twl4030_madc_conversion(&req);
708+ temp = (u16)req.rbuf[9];
709+
710+ return (temp * BK_VOLT_STEP_SIZE) / BK_VOLT_PSR_R;
711+}
712+
713+/*
714+ * Returns an integer value, that means,
715+ * NO_PW_CONN no power supply is connected
716+ * AC_PW_CONN if the AC power supply is connected
717+ * USB_PW_CONN if the USB power supply is connected
718+ * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
719+ *
720+ * Or < 0 on failure.
721+ */
722+static int twl4030charger_presence(void)
723+{
724+ int ret;
725+ u8 hwsts;
726+
727+ ret = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
728+ REG_STS_HW_CONDITIONS);
729+ if (ret) {
730+ pr_err("twl4030_bci: error reading STS_HW_CONDITIONS\n");
731+ return ret;
732+ }
733+
734+ ret = (hwsts & STS_CHG) ? AC_PW_CONN : NO_PW_CONN;
735+ ret += (hwsts & STS_VBUS) ? USB_PW_CONN : NO_PW_CONN;
736+
737+ if (ret & USB_PW_CONN)
738+ usb_charger_flag = 1;
739+ else
740+ usb_charger_flag = 0;
741+
742+ return ret;
743+
744+}
745+
746+/*
747+ * Returns the main charge FSM status
748+ * Or < 0 on failure.
749+ */
750+static int twl4030bci_status(void)
751+{
752+ int ret;
753+ u8 status;
754+
755+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
756+ &status, REG_BCIMSTATEC);
757+ if (ret) {
758+ pr_err("twl4030_bci: error reading BCIMSTATEC\n");
759+ return ret;
760+ }
761+
762+#ifdef DEBUG
763+ printk("BCI DEBUG: BCIMSTATEC Charge state is 0x%x\n", status);
764+#endif
765+ return (int) (status & BCIMSTAT_MASK);
766+}
767+
768+static int read_bci_val(u8 reg)
769+{
770+ int ret, temp;
771+ u8 val;
772+
773+ /* reading MSB */
774+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
775+ reg + 1);
776+ if (ret)
777+ return ret;
778+
779+ temp = ((int)(val & 0x03)) << 8;
780+
781+ /* reading LSB */
782+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
783+ reg);
784+ if (ret)
785+ return ret;
786+
787+ return temp | val;
788+}
789+
790+/*
791+ * Settup the twl4030 BCI module to enable backup
792+ * battery charging.
793+ */
794+static int twl4030backupbatt_voltage_setup(void)
795+{
796+ int ret;
797+
798+ /* Starting backup batery charge */
799+ ret = clear_n_set(TWL4030_MODULE_PM_RECEIVER, 0, BBCHEN,
800+ REG_BB_CFG);
801+ if (ret)
802+ return ret;
803+
804+ return 0;
805+}
806+
807+/*
808+ * Settup the twl4030 BCI module to measure battery
809+ * temperature
810+ */
811+static int twl4030battery_temp_setup(void)
812+{
813+#ifdef DEBUG
814+ u8 i;
815+#endif
816+ u8 ret;
817+
818+ /* Enabling thermistor current */
819+ ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, 0x1B,
820+ REG_BCICTL1);
821+ if (ret)
822+ return ret;
823+
824+#ifdef DEBUG
825+ twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &ret, REG_BOOT_BCI);
826+ printk("BCI DEBUG: BOOT_BCI Value is 0x%x\n", ret);
827+
828+ twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &ret, REG_STS_HW_CONDITIONS);
829+ printk("BCI DEBUG: STS_HW_CONDITIONS Value is 0x%x\n", ret);
830+
831+ twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ret, REG_BCICTL1);
832+ printk("BCI DEBUG: BCICTL1 Value is 0x%x\n", ret);
833+
834+ twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ret, REG_BCICTL2);
835+ printk("BCI DEBUG: BCICTL2 Value is 0x%x\n", ret);
836+
837+ twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ret, 0x0);
838+ printk("BCI DEBUG: BCIMDEN Value is 0x%x\n", ret);
839+
840+ twl_i2c_read_u8(TWL4030_MODULE_INTBR, &ret, REG_GPBR1);
841+ printk("BCI DEBUG: GPBR1 Value is 0x%x\n", ret);
842+
843+ for(i = 0x0; i <= 0x32; i++)
844+ {
845+ twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ret, i);
846+ printk("BCI DEBUG: BCI 0x%x Value is 0x%x\n", i, ret);
847+ }
848+#endif
849+
850+ return 0;
851+}
852+
853+/*
854+ * Sets and clears bits on an given register on a given module
855+ */
856+static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg)
857+{
858+ int ret;
859+ u8 val = 0;
860+
861+ /* Gets the initial register value */
862+ ret = twl_i2c_read_u8(mod_no, &val, reg);
863+ if (ret)
864+ return ret;
865+ /* Clearing all those bits to clear */
866+ val &= ~(clear);
867+
868+ /* Setting all those bits to set */
869+ val |= set;
870+
871+ /* Update the register */
872+ ret = twl_i2c_write_u8(mod_no, val, reg);
873+ if (ret)
874+ return ret;
875+
876+ return 0;
877+}
878+
879+static enum power_supply_property twl4030_bci_battery_props[] = {
880+ POWER_SUPPLY_PROP_STATUS,
881+ POWER_SUPPLY_PROP_ONLINE,
882+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
883+ POWER_SUPPLY_PROP_CURRENT_NOW,
884+ POWER_SUPPLY_PROP_CAPACITY,
885+ POWER_SUPPLY_PROP_TEMP,
886+};
887+
888+static enum power_supply_property twl4030_bk_bci_battery_props[] = {
889+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
890+};
891+
892+static void
893+twl4030_bk_bci_battery_read_status(struct twl4030_bci_device_info *di)
894+{
895+ di->bk_voltage_uV = twl4030backupbatt_voltage();
896+}
897+
898+static void twl4030_bk_bci_battery_work(struct work_struct *work)
899+{
900+ struct twl4030_bci_device_info *di = container_of(work,
901+ struct twl4030_bci_device_info,
902+ twl4030_bk_bci_monitor_work.work);
903+
904+ if(!di->pdata->no_backup_battery)
905+ twl4030_bk_bci_battery_read_status(di);
906+ schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
907+}
908+
909+static void twl4030_bci_battery_read_status(struct twl4030_bci_device_info *di)
910+{
911+ if(di->charge_status != POWER_SUPPLY_STATUS_DISCHARGING) {
912+ di->temp_C = twl4030battery_temperature(di);
913+ di->voltage_uV = twl4030battery_voltage();
914+ di->current_uA = twl4030battery_current();
915+ }
916+}
917+
918+static void
919+twl4030_bci_battery_update_status(struct twl4030_bci_device_info *di)
920+{
921+ if (power_supply_am_i_supplied(&di->bat))
922+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
923+ else
924+ di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
925+ twl4030_bci_battery_read_status(di);
926+}
927+
928+static void twl4030_bci_battery_work(struct work_struct *work)
929+{
930+ struct twl4030_bci_device_info *di = container_of(work,
931+ struct twl4030_bci_device_info, twl4030_bci_monitor_work.work);
932+
933+ twl4030_bci_battery_update_status(di);
934+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 100);
935+}
936+
937+
938+#define to_twl4030_bci_device_info(x) container_of((x), \
939+ struct twl4030_bci_device_info, bat);
940+
941+static void twl4030_bci_battery_external_power_changed(struct power_supply *psy)
942+{
943+ struct twl4030_bci_device_info *di = to_twl4030_bci_device_info(psy);
944+
945+ cancel_delayed_work(&di->twl4030_bci_monitor_work);
946+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
947+}
948+
949+#define to_twl4030_bk_bci_device_info(x) container_of((x), \
950+ struct twl4030_bci_device_info, bk_bat);
951+
952+static ssize_t
953+show_charge_current(struct device *dev, struct device_attribute *attr, char *buf)
954+{
955+ u8 ctl;
956+ int ret = read_bci_val(REG_BCIIREF1) & 0x1FF;
957+ twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ctl, REG_BCICTL1);
958+
959+ if (ctl & CGAIN)
960+ ret |= 0x200;
961+
962+#ifdef DEBUG
963+ /* Dump debug */
964+ twl4030battery_temp_setup();
965+#endif
966+
967+ return sprintf(buf, "%d\n", ret);
968+}
969+
970+static ssize_t
971+set_charge_current(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
972+{
973+ unsigned long newCurrent;
974+ int ret;
975+
976+ ret = strict_strtoul(buf, 10, &newCurrent);
977+ if (ret)
978+ return -EINVAL;
979+
980+ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, KEY_IIREF, REG_BCIMFKEY);
981+ if (ret)
982+ return ret;
983+
984+ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, newCurrent & 0xff, REG_BCIIREF1);
985+ if (ret)
986+ return ret;
987+
988+ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, KEY_IIREF, REG_BCIMFKEY);
989+ if (ret)
990+ return ret;
991+
992+ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, (newCurrent >> 8) & 0x1, REG_BCIIREF2);
993+ if (ret)
994+ return ret;
995+
996+ /* Set software-controlled charge */
997+ twl4030charger_ac_en(ENABLE, 0);
998+
999+ /* Set CGAIN = 0 or 1 */
1000+ if(newCurrent > 511) {
1001+ u8 tmp;
1002+
1003+ /* Set CGAIN = 1 -- need to wait until automatic charge turns off */
1004+ while(!ret) {
1005+ clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, CGAIN | 0x1B, REG_BCICTL1);
1006+ twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &tmp, REG_BCICTL1);
1007+
1008+ ret = tmp & CGAIN;
1009+ if(!ret)
1010+ mdelay(50);
1011+ }
1012+ } else {
1013+ u8 tmp;
1014+
1015+ /* Set CGAIN = 0 -- need to wait until automatic charge turns off */
1016+ while(!ret) {
1017+ clear_n_set(TWL4030_MODULE_MAIN_CHARGE, CGAIN, 0x1B, REG_BCICTL1);
1018+ twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &tmp, REG_BCICTL1);
1019+
1020+ ret = !(tmp & CGAIN);
1021+ if(!ret)
1022+ mdelay(50);
1023+ }
1024+ }
1025+
1026+ /* Set automatic charge (CGAIN = 0/1 persists) */
1027+ twl4030charger_ac_en(ENABLE, 1);
1028+
1029+ return count;
1030+}
1031+
1032+static ssize_t
1033+show_voltage(struct device *dev, struct device_attribute *attr, char *buf)
1034+{
1035+ return sprintf(buf, "%d\n", twl4030battery_voltage_madc());
1036+}
1037+
1038+static DEVICE_ATTR(charge_current, S_IRUGO | S_IWUGO, show_charge_current, set_charge_current);
1039+static DEVICE_ATTR(voltage_now_madc, S_IRUGO, show_voltage, NULL);
1040+
1041+static int twl4030_bk_bci_battery_get_property(struct power_supply *psy,
1042+ enum power_supply_property psp,
1043+ union power_supply_propval *val)
1044+{
1045+ struct twl4030_bci_device_info *di = to_twl4030_bk_bci_device_info(psy);
1046+
1047+ switch (psp) {
1048+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
1049+ val->intval = di->bk_voltage_uV;
1050+ break;
1051+ default:
1052+ return -EINVAL;
1053+ }
1054+
1055+ return 0;
1056+}
1057+
1058+static int twl4030_bci_battery_get_property(struct power_supply *psy,
1059+ enum power_supply_property psp,
1060+ union power_supply_propval *val)
1061+{
1062+ struct twl4030_bci_device_info *di;
1063+ int status = 0;
1064+
1065+ di = to_twl4030_bci_device_info(psy);
1066+
1067+ switch (psp) {
1068+ case POWER_SUPPLY_PROP_STATUS:
1069+ val->intval = di->charge_status;
1070+ return 0;
1071+ default:
1072+ break;
1073+ }
1074+
1075+ switch (psp) {
1076+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
1077+ {
1078+ /* Get latest data from MADC -- not done periodically by
1079+ worker as this is more expensive, so only do it when we
1080+ are actually asked for the data... */
1081+ if(di->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
1082+ val->intval = twl4030battery_voltage_madc();
1083+ else
1084+ val->intval = di->voltage_uV;
1085+
1086+ break;
1087+ }
1088+ case POWER_SUPPLY_PROP_CURRENT_NOW:
1089+ /* FIXME: Get from MADC */
1090+ if(di->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
1091+ val->intval = 0;
1092+ else
1093+ val->intval = di->current_uA;
1094+ break;
1095+ case POWER_SUPPLY_PROP_TEMP:
1096+ val->intval = di->temp_C;
1097+ break;
1098+ case POWER_SUPPLY_PROP_ONLINE:
1099+ status = twl4030bci_status();
1100+ if ((status & AC_STATEC) == AC_STATEC)
1101+ val->intval = POWER_SUPPLY_TYPE_MAINS;
1102+ else if (usb_charger_flag)
1103+ val->intval = POWER_SUPPLY_TYPE_USB;
1104+ else
1105+ val->intval = 0;
1106+ break;
1107+ case POWER_SUPPLY_PROP_CAPACITY:
1108+ /* Get latest data from MADC -- not done periodically by
1109+ worker as this is more expensive, so only do it when we
1110+ are actually asked for the data... */
1111+ if(di->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
1112+ di->voltage_uV = twl4030battery_voltage_madc();
1113+
1114+ /*
1115+ * need to get the correct percentage value per the
1116+ * battery characteristics. Approx values for now.
1117+ */
1118+ if (di->voltage_uV < 2894 || LVL_1) {
1119+ val->intval = 5;
1120+ LVL_1 = 0;
1121+ } else if ((di->voltage_uV < 3451 && di->voltage_uV > 2894)
1122+ || LVL_2) {
1123+ val->intval = 20;
1124+ LVL_2 = 0;
1125+ } else if ((di->voltage_uV < 3902 && di->voltage_uV > 3451)
1126+ || LVL_3) {
1127+ val->intval = 50;
1128+ LVL_3 = 0;
1129+ } else if ((di->voltage_uV < 3949 && di->voltage_uV > 3902)
1130+ || LVL_4) {
1131+ val->intval = 75;
1132+ LVL_4 = 0;
1133+ } else if (di->voltage_uV > 3949)
1134+ val->intval = 90;
1135+ break;
1136+ default:
1137+ return -EINVAL;
1138+ }
1139+ return 0;
1140+}
1141+
1142+static char *twl4030_bci_supplied_to[] = {
1143+ "twl4030_bci_battery",
1144+};
1145+
1146+static int __init twl4030_bci_battery_probe(struct platform_device *pdev)
1147+{
1148+ struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
1149+ struct twl4030_bci_device_info *di;
1150+ int irq;
1151+ int ret;
1152+
1153+ di = kzalloc(sizeof(*di), GFP_KERNEL);
1154+ if (!di)
1155+ return -ENOMEM;
1156+
1157+ di->dev = &pdev->dev;
1158+ di->bat.name = "twl4030_bci_battery";
1159+ di->bat.supplied_to = twl4030_bci_supplied_to;
1160+ di->bat.num_supplicants = ARRAY_SIZE(twl4030_bci_supplied_to);
1161+ di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
1162+ di->bat.properties = twl4030_bci_battery_props;
1163+ di->bat.num_properties = ARRAY_SIZE(twl4030_bci_battery_props);
1164+ di->bat.get_property = twl4030_bci_battery_get_property;
1165+ di->bat.external_power_changed =
1166+ twl4030_bci_battery_external_power_changed;
1167+
1168+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
1169+
1170+ di->bk_bat.name = "twl4030_bci_bk_battery";
1171+ di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
1172+ di->bk_bat.properties = twl4030_bk_bci_battery_props;
1173+ di->bk_bat.num_properties = ARRAY_SIZE(twl4030_bk_bci_battery_props);
1174+ di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
1175+ di->bk_bat.external_power_changed = NULL;
1176+ di->pdata = pdata;
1177+
1178+ /* Set up clocks */
1179+ twl_i2c_write_u8(TWL4030_MODULE_INTBR, MADC_HFCLK_EN | DEFAULT_MADC_CLK_EN, REG_GPBR1);
1180+
1181+ twl4030charger_ac_en(ENABLE, CHARGE_MODE);
1182+ twl4030charger_usb_en(ENABLE);
1183+ twl4030battery_hw_level_en(ENABLE);
1184+ twl4030battery_hw_presence_en(ENABLE);
1185+
1186+ platform_set_drvdata(pdev, di);
1187+
1188+ /* settings for temperature sensing */
1189+ ret = twl4030battery_temp_setup();
1190+ if (ret)
1191+ goto temp_setup_fail;
1192+
1193+ /* enabling GPCH09 for read back battery voltage */
1194+ if(!di->pdata->no_backup_battery)
1195+ {
1196+ ret = twl4030backupbatt_voltage_setup();
1197+ if (ret)
1198+ goto voltage_setup_fail;
1199+ }
1200+
1201+ /* REVISIT do we need to request both IRQs ?? */
1202+
1203+ /* request BCI interruption */
1204+ irq = platform_get_irq(pdev, 1);
1205+ ret = request_irq(irq, twl4030battery_interrupt,
1206+ 0, pdev->name, NULL);
1207+ if (ret) {
1208+ dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
1209+ irq, ret);
1210+ goto batt_irq_fail;
1211+ }
1212+
1213+ /* request Power interruption */
1214+ irq = platform_get_irq(pdev, 0);
1215+ ret = request_irq(irq, twl4030charger_interrupt,
1216+ 0, pdev->name, di);
1217+
1218+ if (ret) {
1219+ dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
1220+ irq, ret);
1221+ goto chg_irq_fail;
1222+ }
1223+
1224+ ret = power_supply_register(&pdev->dev, &di->bat);
1225+ if (ret) {
1226+ dev_dbg(&pdev->dev, "failed to register main battery\n");
1227+ goto batt_failed;
1228+ }
1229+
1230+ INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bci_monitor_work,
1231+ twl4030_bci_battery_work);
1232+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
1233+
1234+ if(!pdata->no_backup_battery)
1235+ {
1236+ ret = power_supply_register(&pdev->dev, &di->bk_bat);
1237+ if (ret) {
1238+ dev_dbg(&pdev->dev, "failed to register backup battery\n");
1239+ goto bk_batt_failed;
1240+ }
1241+ }
1242+
1243+ ret = device_create_file(di->bat.dev, &dev_attr_voltage_now_madc);
1244+ ret = device_create_file(di->bat.dev, &dev_attr_charge_current);
1245+ if (ret) {
1246+ dev_err(&pdev->dev, "failed to create sysfs entries\n");
1247+ goto bk_batt_failed;
1248+ }
1249+
1250+ INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bk_bci_monitor_work,
1251+ twl4030_bk_bci_battery_work);
1252+ schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
1253+
1254+ set_charge_current (NULL, NULL, "1023", 4);
1255+ return 0;
1256+
1257+bk_batt_failed:
1258+ if(!pdata->no_backup_battery)
1259+ power_supply_unregister(&di->bat);
1260+batt_failed:
1261+ free_irq(irq, di);
1262+chg_irq_fail:
1263+ irq = platform_get_irq(pdev, 1);
1264+ free_irq(irq, NULL);
1265+batt_irq_fail:
1266+voltage_setup_fail:
1267+temp_setup_fail:
1268+ twl4030charger_ac_en(DISABLE, CHARGE_MODE);
1269+ twl4030charger_usb_en(DISABLE);
1270+ twl4030battery_hw_level_en(DISABLE);
1271+ twl4030battery_hw_presence_en(DISABLE);
1272+ kfree(di);
1273+
1274+ return ret;
1275+}
1276+
1277+static int __exit twl4030_bci_battery_remove(struct platform_device *pdev)
1278+{
1279+ struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1280+ int irq;
1281+
1282+ twl4030charger_ac_en(DISABLE, CHARGE_MODE);
1283+ twl4030charger_usb_en(DISABLE);
1284+ twl4030battery_hw_level_en(DISABLE);
1285+ twl4030battery_hw_presence_en(DISABLE);
1286+
1287+ irq = platform_get_irq(pdev, 0);
1288+ free_irq(irq, di);
1289+
1290+ irq = platform_get_irq(pdev, 1);
1291+ free_irq(irq, NULL);
1292+
1293+ flush_scheduled_work();
1294+ power_supply_unregister(&di->bat);
1295+ power_supply_unregister(&di->bk_bat);
1296+ platform_set_drvdata(pdev, NULL);
1297+ kfree(di);
1298+
1299+ return 0;
1300+}
1301+
1302+#ifdef CONFIG_PM
1303+static int twl4030_bci_battery_suspend(struct platform_device *pdev,
1304+ pm_message_t state)
1305+{
1306+ struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1307+
1308+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
1309+ cancel_delayed_work(&di->twl4030_bci_monitor_work);
1310+ cancel_delayed_work(&di->twl4030_bk_bci_monitor_work);
1311+ return 0;
1312+}
1313+
1314+static int twl4030_bci_battery_resume(struct platform_device *pdev)
1315+{
1316+ struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1317+
1318+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
1319+ schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 50);
1320+ return 0;
1321+}
1322+#else
1323+#define twl4030_bci_battery_suspend NULL
1324+#define twl4030_bci_battery_resume NULL
1325+#endif /* CONFIG_PM */
1326+
1327+static struct platform_driver twl4030_bci_battery_driver = {
1328+ .probe = twl4030_bci_battery_probe,
1329+ .remove = __exit_p(twl4030_bci_battery_remove),
1330+ .suspend = twl4030_bci_battery_suspend,
1331+ .resume = twl4030_bci_battery_resume,
1332+ .driver = {
1333+ .name = "twl4030_bci",
1334+ },
1335+};
1336+
1337+MODULE_LICENSE("GPL");
1338+MODULE_ALIAS("platform:twl4030_bci");
1339+MODULE_AUTHOR("Texas Instruments Inc");
1340+
1341+static int __init twl4030_battery_init(void)
1342+{
1343+ return platform_driver_register(&twl4030_bci_battery_driver);
1344+}
1345+module_init(twl4030_battery_init);
1346+
1347+static void __exit twl4030_battery_exit(void)
1348+{
1349+ platform_driver_unregister(&twl4030_bci_battery_driver);
1350+}
1351+module_exit(twl4030_battery_exit);
1352+
1353diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
1354index d975c5b..a3470ce 100644
1355--- a/include/linux/i2c/twl.h
1356+++ b/include/linux/i2c/twl.h
1357@@ -442,6 +442,7 @@ struct twl4030_clock_init_data {
1358 struct twl4030_bci_platform_data {
1359 int *battery_tmp_tbl;
1360 unsigned int tblsize;
1361+ bool no_backup_battery;
1362 };
1363
1364 /* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
1365--
13661.6.6.1
1367