Merge current mainline tree into linux-omap tree
[pandora-kernel.git] / drivers / power / twl4030_bci_battery.c
1 /*
2  * linux/drivers/power/twl4030_bci_battery.c
3  *
4  * OMAP2430/3430 BCI battery driver for Linux
5  *
6  * Copyright (C) 2008 Texas Instruments, Inc.
7  * Author: Texas Instruments, Inc.
8  *
9  * This package is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17
18 #include <linux/init.h>
19 #include <linux/module.h>
20 #include <linux/device.h>
21 #include <linux/interrupt.h>
22 #include <linux/delay.h>
23 #include <linux/platform_device.h>
24 #include <linux/i2c/twl4030.h>
25 #include <linux/power_supply.h>
26 #include <linux/i2c/twl4030-madc.h>
27
28 #define T2_BATTERY_VOLT         0x04
29 #define T2_BATTERY_TEMP         0x06
30 #define T2_BATTERY_CUR          0x08
31
32 /* charger constants */
33 #define NO_PW_CONN              0
34 #define AC_PW_CONN              0x01
35 #define USB_PW_CONN             0x02
36
37 /* TWL4030_MODULE_USB */
38 #define REG_POWER_CTRL          0x0AC
39 #define OTG_EN                  0x020
40 #define REG_PHY_CLK_CTRL        0x0FE
41 #define REG_PHY_CLK_CTRL_STS    0x0FF
42 #define PHY_DPLL_CLK            0x01
43
44 #define REG_BCICTL1             0x023
45 #define REG_BCICTL2             0x024
46 #define CGAIN                   0x020
47 #define ITHEN                   0x010
48 #define ITHSENS                 0x007
49
50 /* Boot BCI flag bits */
51 #define BCIAUTOWEN              0x020
52 #define CONFIG_DONE             0x010
53 #define BCIAUTOUSB              0x002
54 #define BCIAUTOAC               0x001
55 #define BCIMSTAT_MASK           0x03F
56
57 /* Boot BCI register */
58 #define REG_BOOT_BCI            0x007
59 #define REG_CTRL1               0x00
60 #define REG_SW1SELECT_MSB       0x07
61 #define SW1_CH9_SEL             0x02
62 #define REG_CTRL_SW1            0x012
63 #define SW1_TRIGGER             0x020
64 #define EOC_SW1                 0x002
65 #define REG_GPCH9               0x049
66 #define REG_STS_HW_CONDITIONS   0x0F
67 #define STS_VBUS                0x080
68 #define STS_CHG                 0x02
69 #define REG_BCIMSTATEC          0x02
70 #define REG_BCIMFSTS4           0x010
71 #define REG_BCIMFSTS2           0x00E
72 #define REG_BCIMFSTS3           0x00F
73 #define REG_BCIMFSTS1           0x001
74 #define USBFASTMCHG             0x004
75 #define BATSTSPCHG              0x004
76 #define BATSTSMCHG              0x040
77 #define VBATOV4                 0x020
78 #define VBATOV3                 0x010
79 #define VBATOV2                 0x008
80 #define VBATOV1                 0x004
81 #define REG_BB_CFG              0x012
82 #define BBCHEN                  0x010
83
84 /* Power supply charge interrupt */
85 #define REG_PWR_ISR1            0x00
86 #define REG_PWR_IMR1            0x01
87 #define REG_PWR_EDR1            0x05
88 #define REG_PWR_SIH_CTRL        0x007
89
90 #define USB_PRES                0x004
91 #define CHG_PRES                0x002
92
93 #define USB_PRES_RISING         0x020
94 #define USB_PRES_FALLING        0x010
95 #define CHG_PRES_RISING         0x008
96 #define CHG_PRES_FALLING        0x004
97 #define AC_STATEC               0x20
98 #define COR                     0x004
99
100 /* interrupt status registers */
101 #define REG_BCIISR1A            0x0
102 #define REG_BCIISR2A            0x01
103
104 /* Interrupt flags bits BCIISR1 */
105 #define BATSTS_ISR1             0x080
106 #define VBATLVL_ISR1            0x001
107
108 /* Interrupt mask registers for int1*/
109 #define REG_BCIIMR1A            0x002
110 #define REG_BCIIMR2A            0x003
111
112  /* Interrupt masks for BCIIMR1 */
113 #define BATSTS_IMR1             0x080
114 #define VBATLVL_IMR1            0x001
115
116 /* Interrupt edge detection register */
117 #define REG_BCIEDR1             0x00A
118 #define REG_BCIEDR2             0x00B
119 #define REG_BCIEDR3             0x00C
120
121 /* BCIEDR2 */
122 #define BATSTS_EDRRISIN         0x080
123 #define BATSTS_EDRFALLING       0x040
124
125 /* BCIEDR3 */
126 #define VBATLVL_EDRRISIN        0x02
127
128 /* Step size and prescaler ratio */
129 #define TEMP_STEP_SIZE          147
130 #define TEMP_PSR_R              100
131
132 #define VOLT_STEP_SIZE          588
133 #define VOLT_PSR_R              100
134
135 #define CURR_STEP_SIZE          147
136 #define CURR_PSR_R1             44
137 #define CURR_PSR_R2             80
138
139 #define BK_VOLT_STEP_SIZE       441
140 #define BK_VOLT_PSR_R           100
141
142 #define ENABLE          1
143 #define DISABLE         1
144
145 /* Ptr to thermistor table */
146 int *therm_tbl;
147
148 struct twl4030_bci_device_info {
149         struct device           *dev;
150
151         unsigned long           update_time;
152         int                     voltage_uV;
153         int                     bk_voltage_uV;
154         int                     current_uA;
155         int                     temp_C;
156         int                     charge_rsoc;
157         int                     charge_status;
158
159         struct power_supply     bat;
160         struct power_supply     bk_bat;
161         struct delayed_work     twl4030_bci_monitor_work;
162         struct delayed_work     twl4030_bk_bci_monitor_work;
163 };
164
165 static int usb_charger_flag;
166 static int LVL_1, LVL_2, LVL_3, LVL_4;
167
168 static int read_bci_val(u8 reg_1);
169 static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg);
170 static int twl4030charger_presence(void);
171
172 /*
173  * Report and clear the charger presence event.
174  */
175 static inline int twl4030charger_presence_evt(void)
176 {
177         int ret;
178         u8 chg_sts, set = 0, clear = 0;
179
180         /* read charger power supply status */
181         ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts,
182                 REG_STS_HW_CONDITIONS);
183         if (ret)
184                 return IRQ_NONE;
185
186         if (chg_sts & STS_CHG) { /* If the AC charger have been connected */
187                 /* configuring falling edge detection for CHG_PRES */
188                 set = CHG_PRES_FALLING;
189                 clear = CHG_PRES_RISING;
190         } else { /* If the AC charger have been disconnected */
191                 /* configuring rising edge detection for CHG_PRES */
192                 set = CHG_PRES_RISING;
193                 clear = CHG_PRES_FALLING;
194         }
195
196         /* Update the interrupt edge detection register */
197         clear_n_set(TWL4030_MODULE_INT, clear, set, REG_PWR_EDR1);
198
199         return 0;
200 }
201
202 /*
203  * Interrupt service routine
204  *
205  * Attends to TWL 4030 power module interruptions events, specifically
206  * USB_PRES (USB charger presence) CHG_PRES (AC charger presence) events
207  *
208  */
209 static irqreturn_t twl4030charger_interrupt(int irq, void *_di)
210 {
211         struct twl4030_bci_device_info *di = _di;
212
213 #ifdef CONFIG_LOCKDEP
214         /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
215          * we don't want and can't tolerate.  Although it might be
216          * friendlier not to borrow this thread context...
217          */
218         local_irq_enable();
219 #endif
220
221         twl4030charger_presence_evt();
222         power_supply_changed(&di->bat);
223
224         return IRQ_HANDLED;
225 }
226
227 /*
228  * This function handles the twl4030 battery presence interrupt
229  */
230 static int twl4030battery_presence_evt(void)
231 {
232         int ret;
233         u8 batstsmchg, batstspchg;
234
235         /* check for the battery presence in main charge*/
236         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
237                         &batstsmchg, REG_BCIMFSTS3);
238         if (ret)
239                 return ret;
240
241         /* check for the battery presence in precharge */
242         ret = twl4030_i2c_read_u8(TWL4030_MODULE_PRECHARGE,
243                         &batstspchg, REG_BCIMFSTS1);
244         if (ret)
245                 return ret;
246
247         /*
248          * REVISIT: Physically inserting/removing the batt
249          * does not seem to generate an int on 3430ES2 SDP.
250          */
251         if ((batstspchg & BATSTSPCHG) || (batstsmchg & BATSTSMCHG)) {
252                 /* In case of the battery insertion event */
253                 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRRISIN,
254                         BATSTS_EDRFALLING, REG_BCIEDR2);
255                 if (ret)
256                         return ret;
257         } else {
258                 /* In case of the battery removal event */
259                 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRFALLING,
260                         BATSTS_EDRRISIN, REG_BCIEDR2);
261                 if (ret)
262                         return ret;
263         }
264
265         return 0;
266 }
267
268 /*
269  * This function handles the twl4030 battery voltage level interrupt.
270  */
271 static int twl4030battery_level_evt(void)
272 {
273         int ret;
274         u8 mfst;
275
276         /* checking for threshold event */
277         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
278                         &mfst, REG_BCIMFSTS2);
279         if (ret)
280                 return ret;
281
282         /* REVISIT could use a bitmap */
283         if (mfst & VBATOV4) {
284                 LVL_4 = 1;
285                 LVL_3 = 0;
286                 LVL_2 = 0;
287                 LVL_1 = 0;
288         } else if (mfst & VBATOV3) {
289                 LVL_4 = 0;
290                 LVL_3 = 1;
291                 LVL_2 = 0;
292                 LVL_1 = 0;
293         } else if (mfst & VBATOV2) {
294                 LVL_4 = 0;
295                 LVL_3 = 0;
296                 LVL_2 = 1;
297                 LVL_1 = 0;
298         } else {
299                 LVL_4 = 0;
300                 LVL_3 = 0;
301                 LVL_2 = 0;
302                 LVL_1 = 1;
303         }
304
305         return 0;
306 }
307
308 /*
309  * Interrupt service routine
310  *
311  * Attends to BCI interruptions events,
312  * specifically BATSTS (battery connection and removal)
313  * VBATOV (main battery voltage threshold) events
314  *
315  */
316 static irqreturn_t twl4030battery_interrupt(int irq, void *_di)
317 {
318         u8 isr1a_val, isr2a_val, clear_2a, clear_1a;
319         int ret;
320
321 #ifdef CONFIG_LOCKDEP
322         /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
323          * we don't want and can't tolerate.  Although it might be
324          * friendlier not to borrow this thread context...
325          */
326         local_irq_enable();
327 #endif
328
329         ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr1a_val,
330                                 REG_BCIISR1A);
331         if (ret)
332                 return IRQ_NONE;
333
334         ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr2a_val,
335                                 REG_BCIISR2A);
336         if (ret)
337                 return IRQ_NONE;
338
339         clear_2a = (isr2a_val & VBATLVL_ISR1) ? (VBATLVL_ISR1) : 0;
340         clear_1a = (isr1a_val & BATSTS_ISR1) ? (BATSTS_ISR1) : 0;
341
342         /* cleaning BCI interrupt status flags */
343         ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
344                         clear_1a , REG_BCIISR1A);
345         if (ret)
346                 return IRQ_NONE;
347
348         ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
349                         clear_2a , REG_BCIISR2A);
350         if (ret)
351                 return IRQ_NONE;
352
353         /* battery connetion or removal event */
354         if (isr1a_val & BATSTS_ISR1)
355                 twl4030battery_presence_evt();
356         /* battery voltage threshold event*/
357         else if (isr2a_val & VBATLVL_ISR1)
358                 twl4030battery_level_evt();
359         else
360                 return IRQ_NONE;
361
362         return IRQ_HANDLED;
363 }
364
365 /*
366  * Enable/Disable hardware battery level event notifications.
367  */
368 static int twl4030battery_hw_level_en(int enable)
369 {
370         int ret;
371
372         if (enable) {
373                 /* unmask VBATOV interrupt for INT1 */
374                 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, VBATLVL_IMR1,
375                         0, REG_BCIIMR2A);
376                 if (ret)
377                         return ret;
378
379                 /* configuring interrupt edge detection for VBATOv */
380                 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
381                         VBATLVL_EDRRISIN, REG_BCIEDR3);
382                 if (ret)
383                         return ret;
384         } else {
385                 /* mask VBATOV interrupt for INT1 */
386                 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
387                         VBATLVL_IMR1, REG_BCIIMR2A);
388                 if (ret)
389                         return ret;
390         }
391
392         return 0;
393 }
394
395 /*
396  * Enable/disable hardware battery presence event notifications.
397  */
398 static int twl4030battery_hw_presence_en(int enable)
399 {
400         int ret;
401
402         if (enable) {
403                 /* unmask BATSTS interrupt for INT1 */
404                 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_IMR1,
405                         0, REG_BCIIMR1A);
406                 if (ret)
407                         return ret;
408
409                 /* configuring interrupt edge for BATSTS */
410                 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
411                         BATSTS_EDRRISIN | BATSTS_EDRFALLING, REG_BCIEDR2);
412                 if (ret)
413                         return ret;
414         } else {
415                 /* mask BATSTS interrupt for INT1 */
416                 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
417                         BATSTS_IMR1, REG_BCIIMR1A);
418                 if (ret)
419                         return ret;
420         }
421
422         return 0;
423 }
424
425 /*
426  * Enable/Disable AC Charge funtionality.
427  */
428 static int twl4030charger_ac_en(int enable)
429 {
430         int ret;
431
432         if (enable) {
433                 /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 1 */
434                 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
435                         (CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC),
436                         REG_BOOT_BCI);
437                 if (ret)
438                         return ret;
439         } else {
440                 /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 0*/
441                 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC,
442                         (CONFIG_DONE | BCIAUTOWEN),
443                         REG_BOOT_BCI);
444                 if (ret)
445                         return ret;
446         }
447
448         return 0;
449 }
450
451 /*
452  * Enable/Disable USB Charge funtionality.
453  */
454 int twl4030charger_usb_en(int enable)
455 {
456         u8 value;
457         int ret;
458         unsigned long timeout;
459
460         if (enable) {
461                 /* Check for USB charger conneted */
462                 ret = twl4030charger_presence();
463                 if (ret < 0)
464                         return ret;
465
466                 if (!(ret & USB_PW_CONN))
467                         return -ENXIO;
468
469                 /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
470                 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
471                         (CONFIG_DONE | BCIAUTOWEN | BCIAUTOUSB),
472                         REG_BOOT_BCI);
473                 if (ret)
474                         return ret;
475
476                 ret = clear_n_set(TWL4030_MODULE_USB, 0, PHY_DPLL_CLK,
477                         REG_PHY_CLK_CTRL);
478                 if (ret)
479                         return ret;
480
481                 value = 0;
482                 timeout = jiffies + msecs_to_jiffies(50);
483
484                 while ((!(value & PHY_DPLL_CLK)) &&
485                         time_before(jiffies, timeout)) {
486                         udelay(10);
487                         ret = twl4030_i2c_read_u8(TWL4030_MODULE_USB, &value,
488                                 REG_PHY_CLK_CTRL_STS);
489                         if (ret)
490                                 return ret;
491                 }
492
493                 /* OTG_EN (POWER_CTRL[5]) to 1 */
494                 ret = clear_n_set(TWL4030_MODULE_USB, 0, OTG_EN,
495                         REG_POWER_CTRL);
496                 if (ret)
497                         return ret;
498
499                 mdelay(50);
500
501                 /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
502                 ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0,
503                         USBFASTMCHG, REG_BCIMFSTS4);
504                 if (ret)
505                         return ret;
506         } else {
507                 twl4030charger_presence();
508                 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOUSB,
509                         (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI);
510                 if (ret)
511                         return ret;
512         }
513
514         return 0;
515 }
516
517 /*
518  * Return battery temperature
519  * Or < 0 on failure.
520  */
521 static int twl4030battery_temperature(void)
522 {
523         u8 val;
524         int temp, curr, volt, res, ret;
525
526         /* Getting and calculating the thermistor voltage */
527         ret = read_bci_val(T2_BATTERY_TEMP);
528         if (ret < 0)
529                 return ret;
530
531         volt = (ret * TEMP_STEP_SIZE) / TEMP_PSR_R;
532
533         /* Getting and calculating the supply current in micro ampers */
534         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
535                  REG_BCICTL2);
536         if (ret)
537                 return 0;
538
539         curr = ((val & ITHSENS) + 1) * 10;
540
541         /* Getting and calculating the thermistor resistance in ohms*/
542         res = volt * 1000 / curr;
543
544         /*calculating temperature*/
545         for (temp = 58; temp >= 0; temp--) {
546                 int actual = therm_tbl[temp];
547                 if ((actual - res) >= 0)
548                         break;
549         }
550
551         /* Negative temperature */
552         if (temp < 3) {
553                 if (temp == 2)
554                         temp = -1;
555                 else if (temp == 1)
556                         temp = -2;
557                 else
558                         temp = -3;
559         }
560
561         return temp + 1;
562 }
563
564 /*
565  * Return battery voltage
566  * Or < 0 on failure.
567  */
568 static int twl4030battery_voltage(void)
569 {
570         int volt = read_bci_val(T2_BATTERY_VOLT);
571
572         return (volt * VOLT_STEP_SIZE) / VOLT_PSR_R;
573 }
574
575 /*
576  * Return the battery current
577  * Or < 0 on failure.
578  */
579 static int twl4030battery_current(void)
580 {
581         int ret, curr = read_bci_val(T2_BATTERY_CUR);
582         u8 val;
583
584         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
585                 REG_BCICTL1);
586         if (ret)
587                 return ret;
588
589         if (val & CGAIN) /* slope of 0.44 mV/mA */
590                 return (curr * CURR_STEP_SIZE) / CURR_PSR_R1;
591         else /* slope of 0.88 mV/mA */
592                 return (curr * CURR_STEP_SIZE) / CURR_PSR_R2;
593 }
594
595 /*
596  * Return the battery backup voltage
597  * Or < 0 on failure.
598  */
599 static int twl4030backupbatt_voltage(void)
600 {
601         struct twl4030_madc_request req;
602         int temp;
603
604         req.channels = (1 << 9);
605         req.do_avg = 0;
606         req.method = TWL4030_MADC_SW1;
607         req.active = 0;
608         req.func_cb = NULL;
609         twl4030_madc_conversion(&req);
610         temp = (u16)req.rbuf[9];
611
612         return  (temp * BK_VOLT_STEP_SIZE) / BK_VOLT_PSR_R;
613 }
614
615 /*
616  * Returns an integer value, that means,
617  * NO_PW_CONN  no power supply is connected
618  * AC_PW_CONN  if the AC power supply is connected
619  * USB_PW_CONN  if the USB power supply is connected
620  * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
621  *
622  * Or < 0 on failure.
623  */
624 static int twl4030charger_presence(void)
625 {
626         int ret;
627         u8 hwsts;
628
629         ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
630                 REG_STS_HW_CONDITIONS);
631         if (ret) {
632                 pr_err("twl4030_bci: error reading STS_HW_CONDITIONS\n");
633                 return ret;
634         }
635
636         ret = (hwsts & STS_CHG) ? AC_PW_CONN : NO_PW_CONN;
637         ret += (hwsts & STS_VBUS) ? USB_PW_CONN : NO_PW_CONN;
638
639         if (ret & USB_PW_CONN)
640                 usb_charger_flag = 1;
641         else
642                 usb_charger_flag = 0;
643
644         return ret;
645
646 }
647
648 /*
649  * Returns the main charge FSM status
650  * Or < 0 on failure.
651  */
652 static int twl4030bci_status(void)
653 {
654         int ret;
655         u8 status;
656
657         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
658                 &status, REG_BCIMSTATEC);
659         if (ret) {
660                 pr_err("twl4030_bci: error reading BCIMSTATEC\n");
661                 return ret;
662         }
663
664         return (int) (status & BCIMSTAT_MASK);
665 }
666
667 static int read_bci_val(u8 reg)
668 {
669         int ret, temp;
670         u8 val;
671
672         /* reading MSB */
673         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
674                 reg + 1);
675         if (ret)
676                 return ret;
677
678         temp = ((int)(val & 0x03)) << 8;
679
680         /* reading LSB */
681         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
682                 reg);
683         if (ret)
684                 return ret;
685
686         return temp | val;
687 }
688
689 /*
690  * Settup the twl4030 BCI module to enable backup
691  * battery charging.
692  */
693 static int twl4030backupbatt_voltage_setup(void)
694 {
695         int ret;
696
697         /* Starting backup batery charge */
698         ret = clear_n_set(TWL4030_MODULE_PM_RECEIVER, 0, BBCHEN,
699                 REG_BB_CFG);
700         if (ret)
701                 return ret;
702
703         return 0;
704 }
705
706 /*
707  * Settup the twl4030 BCI module to measure battery
708  * temperature
709  */
710 static int twl4030battery_temp_setup(void)
711 {
712         int ret;
713
714         /* Enabling thermistor current */
715         ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, ITHEN,
716                 REG_BCICTL1);
717         if (ret)
718                 return ret;
719
720         return 0;
721 }
722
723 /*
724  * Sets and clears bits on an given register on a given module
725  */
726 static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg)
727 {
728         int ret;
729         u8 val = 0;
730
731         /* Gets the initial register value */
732         ret = twl4030_i2c_read_u8(mod_no, &val, reg);
733         if (ret)
734                 return ret;
735
736         /* Clearing all those bits to clear */
737         val &= ~(clear);
738
739         /* Setting all those bits to set */
740         val |= set;
741
742         /* Update the register */
743         ret = twl4030_i2c_write_u8(mod_no, val, reg);
744         if (ret)
745                 return ret;
746
747         return 0;
748 }
749
750 static enum power_supply_property twl4030_bci_battery_props[] = {
751         POWER_SUPPLY_PROP_STATUS,
752         POWER_SUPPLY_PROP_ONLINE,
753         POWER_SUPPLY_PROP_VOLTAGE_NOW,
754         POWER_SUPPLY_PROP_CURRENT_NOW,
755         POWER_SUPPLY_PROP_CAPACITY,
756         POWER_SUPPLY_PROP_TEMP,
757 };
758
759 static enum power_supply_property twl4030_bk_bci_battery_props[] = {
760         POWER_SUPPLY_PROP_VOLTAGE_NOW,
761 };
762
763 static void
764 twl4030_bk_bci_battery_read_status(struct twl4030_bci_device_info *di)
765 {
766         di->bk_voltage_uV = twl4030backupbatt_voltage();
767 }
768
769 static void twl4030_bk_bci_battery_work(struct work_struct *work)
770 {
771         struct twl4030_bci_device_info *di = container_of(work,
772                 struct twl4030_bci_device_info,
773                 twl4030_bk_bci_monitor_work.work);
774
775         twl4030_bk_bci_battery_read_status(di);
776         schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
777 }
778
779 static void twl4030_bci_battery_read_status(struct twl4030_bci_device_info *di)
780 {
781         di->temp_C = twl4030battery_temperature();
782         di->voltage_uV = twl4030battery_voltage();
783         di->current_uA = twl4030battery_current();
784 }
785
786 static void
787 twl4030_bci_battery_update_status(struct twl4030_bci_device_info *di)
788 {
789         twl4030_bci_battery_read_status(di);
790         di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
791
792         if (power_supply_am_i_supplied(&di->bat))
793                 di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
794         else
795                 di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
796 }
797
798 static void twl4030_bci_battery_work(struct work_struct *work)
799 {
800         struct twl4030_bci_device_info *di = container_of(work,
801                 struct twl4030_bci_device_info, twl4030_bci_monitor_work.work);
802
803         twl4030_bci_battery_update_status(di);
804         schedule_delayed_work(&di->twl4030_bci_monitor_work, 100);
805 }
806
807
808 #define to_twl4030_bci_device_info(x) container_of((x), \
809                         struct twl4030_bci_device_info, bat);
810
811 static void twl4030_bci_battery_external_power_changed(struct power_supply *psy)
812 {
813         struct twl4030_bci_device_info *di = to_twl4030_bci_device_info(psy);
814
815         cancel_delayed_work(&di->twl4030_bci_monitor_work);
816         schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
817 }
818
819 #define to_twl4030_bk_bci_device_info(x) container_of((x), \
820                 struct twl4030_bci_device_info, bk_bat);
821
822 static int twl4030_bk_bci_battery_get_property(struct power_supply *psy,
823                                         enum power_supply_property psp,
824                                         union power_supply_propval *val)
825 {
826         struct twl4030_bci_device_info *di = to_twl4030_bk_bci_device_info(psy);
827
828         switch (psp) {
829         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
830                 val->intval = di->bk_voltage_uV;
831                 break;
832         default:
833                 return -EINVAL;
834         }
835
836         return 0;
837 }
838
839 static int twl4030_bci_battery_get_property(struct power_supply *psy,
840                                         enum power_supply_property psp,
841                                         union power_supply_propval *val)
842 {
843         struct twl4030_bci_device_info *di;
844         int status = 0;
845
846         di = to_twl4030_bci_device_info(psy);
847
848         switch (psp) {
849         case POWER_SUPPLY_PROP_STATUS:
850                 val->intval = di->charge_status;
851                 return 0;
852         default:
853                 break;
854         }
855
856         switch (psp) {
857         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
858                 val->intval = di->voltage_uV;
859                 break;
860         case POWER_SUPPLY_PROP_CURRENT_NOW:
861                 val->intval = di->current_uA;
862                 break;
863         case POWER_SUPPLY_PROP_TEMP:
864                 val->intval = di->temp_C;
865                 break;
866         case POWER_SUPPLY_PROP_ONLINE:
867                 status = twl4030bci_status();
868                 if ((status & AC_STATEC) == AC_STATEC)
869                         val->intval = POWER_SUPPLY_TYPE_MAINS;
870                 else if (usb_charger_flag)
871                         val->intval = POWER_SUPPLY_TYPE_USB;
872                 else
873                         val->intval = 0;
874                 break;
875         case POWER_SUPPLY_PROP_CAPACITY:
876                 /*
877                  * need to get the correct percentage value per the
878                  * battery characteristics. Approx values for now.
879                  */
880                 if (di->voltage_uV < 2894 || LVL_1) {
881                         val->intval = 5;
882                         LVL_1 = 0;
883                 } else if ((di->voltage_uV < 3451 && di->voltage_uV > 2894)
884                         || LVL_2) {
885                         val->intval = 20;
886                         LVL_2 = 0;
887                 } else if ((di->voltage_uV < 3902 && di->voltage_uV > 3451)
888                         || LVL_3) {
889                         val->intval = 50;
890                         LVL_3 = 0;
891                 } else if ((di->voltage_uV < 3949 && di->voltage_uV > 3902)
892                         || LVL_4) {
893                         val->intval = 75;
894                         LVL_4 = 0;
895                 } else if (di->voltage_uV > 3949)
896                         val->intval = 90;
897                 break;
898         default:
899                 return -EINVAL;
900         }
901         return 0;
902 }
903
904 static char *twl4030_bci_supplied_to[] = {
905         "twl4030_bci_battery",
906 };
907
908 static int __init twl4030_bci_battery_probe(struct platform_device *pdev)
909 {
910         struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
911         struct twl4030_bci_device_info *di;
912         int irq;
913         int ret;
914
915         therm_tbl = pdata->battery_tmp_tbl;
916
917         di = kzalloc(sizeof(*di), GFP_KERNEL);
918         if (!di)
919                 return -ENOMEM;
920
921         di->dev = &pdev->dev;
922         di->bat.name = "twl4030_bci_battery";
923         di->bat.supplied_to = twl4030_bci_supplied_to;
924         di->bat.num_supplicants = ARRAY_SIZE(twl4030_bci_supplied_to);
925         di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
926         di->bat.properties = twl4030_bci_battery_props;
927         di->bat.num_properties = ARRAY_SIZE(twl4030_bci_battery_props);
928         di->bat.get_property = twl4030_bci_battery_get_property;
929         di->bat.external_power_changed =
930                         twl4030_bci_battery_external_power_changed;
931
932         di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
933
934         di->bk_bat.name = "twl4030_bci_bk_battery";
935         di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
936         di->bk_bat.properties = twl4030_bk_bci_battery_props;
937         di->bk_bat.num_properties = ARRAY_SIZE(twl4030_bk_bci_battery_props);
938         di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
939         di->bk_bat.external_power_changed = NULL;
940
941         twl4030charger_ac_en(ENABLE);
942         twl4030charger_usb_en(ENABLE);
943         twl4030battery_hw_level_en(ENABLE);
944         twl4030battery_hw_presence_en(ENABLE);
945
946         platform_set_drvdata(pdev, di);
947
948         /* settings for temperature sensing */
949         ret = twl4030battery_temp_setup();
950         if (ret)
951                 goto temp_setup_fail;
952
953         /* enabling GPCH09 for read back battery voltage */
954         ret = twl4030backupbatt_voltage_setup();
955         if (ret)
956                 goto voltage_setup_fail;
957
958         /* REVISIT do we need to request both IRQs ?? */
959
960         /* request BCI interruption */
961         ret = request_irq(TWL4030_MODIRQ_BCI, twl4030battery_interrupt,
962                 0, pdev->name, NULL);
963         if (ret) {
964                 dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
965                         TWL4030_MODIRQ_BCI, ret);
966                 goto batt_irq_fail;
967         }
968
969         irq = platform_get_irq(pdev, 0);
970
971         /* request Power interruption */
972         ret = request_irq(irq, twl4030charger_interrupt,
973                 0, pdev->name, di);
974
975         if (ret) {
976                 dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
977                         irq, ret);
978                 goto chg_irq_fail;
979         }
980
981         ret = power_supply_register(&pdev->dev, &di->bat);
982         if (ret) {
983                 dev_dbg(&pdev->dev, "failed to register main battery\n");
984                 goto batt_failed;
985         }
986
987         INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bci_monitor_work,
988                                 twl4030_bci_battery_work);
989         schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
990
991         ret = power_supply_register(&pdev->dev, &di->bk_bat);
992         if (ret) {
993                 dev_dbg(&pdev->dev, "failed to register backup battery\n");
994                 goto bk_batt_failed;
995         }
996
997         INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bk_bci_monitor_work,
998                                 twl4030_bk_bci_battery_work);
999         schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
1000
1001         return 0;
1002
1003 bk_batt_failed:
1004         power_supply_unregister(&di->bat);
1005 batt_failed:
1006         free_irq(irq, di);
1007 chg_irq_fail:
1008         free_irq(TWL4030_MODIRQ_BCI, NULL);
1009 batt_irq_fail:
1010 voltage_setup_fail:
1011 temp_setup_fail:
1012         twl4030charger_ac_en(DISABLE);
1013         twl4030charger_usb_en(DISABLE);
1014         twl4030battery_hw_level_en(DISABLE);
1015         twl4030battery_hw_presence_en(DISABLE);
1016         kfree(di);
1017
1018         return ret;
1019 }
1020
1021 static int __exit twl4030_bci_battery_remove(struct platform_device *pdev)
1022 {
1023         struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1024         int irq = platform_get_irq(pdev, 0);
1025
1026         twl4030charger_ac_en(DISABLE);
1027         twl4030charger_usb_en(DISABLE);
1028         twl4030battery_hw_level_en(DISABLE);
1029         twl4030battery_hw_presence_en(DISABLE);
1030
1031         free_irq(TWL4030_MODIRQ_BCI, NULL);
1032         free_irq(irq, di);
1033
1034         flush_scheduled_work();
1035         power_supply_unregister(&di->bat);
1036         power_supply_unregister(&di->bk_bat);
1037         platform_set_drvdata(pdev, NULL);
1038         kfree(di);
1039
1040         return 0;
1041 }
1042
1043 #ifdef CONFIG_PM
1044 static int twl4030_bci_battery_suspend(struct platform_device *pdev,
1045         pm_message_t state)
1046 {
1047         struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1048
1049         di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
1050         cancel_delayed_work(&di->twl4030_bci_monitor_work);
1051         cancel_delayed_work(&di->twl4030_bk_bci_monitor_work);
1052         return 0;
1053 }
1054
1055 static int twl4030_bci_battery_resume(struct platform_device *pdev)
1056 {
1057         struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1058
1059         schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
1060         schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 50);
1061         return 0;
1062 }
1063 #else
1064 #define twl4030_bci_battery_suspend     NULL
1065 #define twl4030_bci_battery_resume      NULL
1066 #endif /* CONFIG_PM */
1067
1068 static struct platform_driver twl4030_bci_battery_driver = {
1069         .probe          = twl4030_bci_battery_probe,
1070         .remove         = __exit_p(twl4030_bci_battery_remove),
1071         .suspend        = twl4030_bci_battery_suspend,
1072         .resume         = twl4030_bci_battery_resume,
1073         .driver         = {
1074                 .name   = "twl4030_bci",
1075         },
1076 };
1077
1078 MODULE_LICENSE("GPL");
1079 MODULE_ALIAS("platform:twl4030_bci");
1080 MODULE_AUTHOR("Texas Instruments Inc");
1081
1082 static int __init twl4030_battery_init(void)
1083 {
1084         return platform_driver_register(&twl4030_bci_battery_driver);
1085 }
1086 module_init(twl4030_battery_init);
1087
1088 static void __exit twl4030_battery_exit(void)
1089 {
1090         platform_driver_unregister(&twl4030_bci_battery_driver);
1091 }
1092 module_exit(twl4030_battery_exit);
1093