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