2 * linux/drivers/power/twl4030_bci_battery.c
4 * OMAP2430/3430 BCI battery driver for Linux
6 * Copyright (C) 2008 Texas Instruments, Inc.
7 * Author: Texas Instruments, Inc.
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.
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.
18 /* Boot with automatic charge */
21 #include <linux/init.h>
22 #include <linux/module.h>
23 #include <linux/device.h>
24 #include <linux/interrupt.h>
25 #include <linux/delay.h>
26 #include <linux/platform_device.h>
27 #include <linux/i2c/twl4030.h>
28 #include <linux/power_supply.h>
29 #include <linux/i2c/twl4030-madc.h>
31 #define T2_BATTERY_VOLT 0x04
32 #define T2_BATTERY_TEMP 0x06
33 #define T2_BATTERY_CUR 0x08
35 /* charger constants */
37 #define AC_PW_CONN 0x01
38 #define USB_PW_CONN 0x02
40 /* TWL4030_MODULE_USB */
41 #define REG_POWER_CTRL 0x0AC
43 #define REG_PHY_CLK_CTRL 0x0FE
44 #define REG_PHY_CLK_CTRL_STS 0x0FF
45 #define PHY_DPLL_CLK 0x01
47 #define REG_BCICTL1 0x023
48 #define REG_BCICTL2 0x024
53 /* Boot BCI flag bits */
54 #define BCIAUTOWEN 0x020
55 #define CONFIG_DONE 0x010
57 #define BCIAUTOUSB 0x002
58 #define BCIAUTOAC 0x001
59 #define BCIMSTAT_MASK 0x03F
61 /* Boot BCI register */
62 #define REG_BOOT_BCI 0x007
63 #define REG_CTRL1 0x00
64 #define REG_SW1SELECT_MSB 0x07
65 #define SW1_CH9_SEL 0x02
66 #define REG_CTRL_SW1 0x012
67 #define SW1_TRIGGER 0x020
69 #define REG_GPCH9 0x049
70 #define REG_STS_HW_CONDITIONS 0x0F
71 #define STS_VBUS 0x080
73 #define STS_USB_ID 0x04
74 #define REG_BCIMSTATEC 0x02
75 #define REG_BCIMFSTS4 0x010
76 #define REG_BCIMFSTS2 0x00E
77 #define REG_BCIMFSTS3 0x00F
78 #define REG_BCIMFSTS1 0x001
79 #define USBFASTMCHG 0x004
80 #define BATSTSPCHG 0x004
81 #define BATSTSMCHG 0x040
86 #define REG_BB_CFG 0x012
90 #define REG_GPBR1 0x0c
91 #define MADC_HFCLK_EN 0x80
92 #define DEFAULT_MADC_CLK_EN 0x10
94 /* Power supply charge interrupt */
95 #define REG_PWR_ISR1 0x00
96 #define REG_PWR_IMR1 0x01
97 #define REG_PWR_EDR1 0x05
98 #define REG_PWR_SIH_CTRL 0x007
100 #define USB_PRES 0x004
101 #define CHG_PRES 0x002
103 #define USB_PRES_RISING 0x020
104 #define USB_PRES_FALLING 0x010
105 #define CHG_PRES_RISING 0x008
106 #define CHG_PRES_FALLING 0x004
107 #define AC_STATEC 0x20
108 #define USB_STATEC 0x10
111 /* interrupt status registers */
112 #define REG_BCIISR1A 0x0
113 #define REG_BCIISR2A 0x01
115 /* Interrupt flags bits BCIISR1 */
116 #define BATSTS_ISR1 0x080
117 #define VBATLVL_ISR1 0x001
119 /* Interrupt mask registers for int1*/
120 #define REG_BCIIMR1A 0x002
121 #define REG_BCIIMR2A 0x003
123 /* Interrupt masks for BCIIMR1 */
124 #define BATSTS_IMR1 0x080
125 #define VBATLVL_IMR1 0x001
127 /* Interrupt edge detection register */
128 #define REG_BCIEDR1 0x00A
129 #define REG_BCIEDR2 0x00B
130 #define REG_BCIEDR3 0x00C
133 #define BATSTS_EDRRISIN 0x080
134 #define BATSTS_EDRFALLING 0x040
137 #define VBATLVL_EDRRISIN 0x02
140 #define REG_BCIIREF1 0x027
141 #define REG_BCIIREF2 0x028
144 #define REG_BCIMFTH1 0x016
147 #define KEY_IIREF 0xE7
148 #define KEY_FTH1 0xD2
149 #define REG_BCIMFKEY 0x011
151 /* Step size and prescaler ratio */
152 #define TEMP_STEP_SIZE 147
153 #define TEMP_PSR_R 100
155 #define VOLT_STEP_SIZE 588
156 #define VOLT_PSR_R 100
158 #define BK_VOLT_STEP_SIZE 441
159 #define BK_VOLT_PSR_R 100
164 struct twl4030_bci_device_info {
167 unsigned long update_time;
177 struct power_supply bat;
178 struct power_supply bk_bat;
179 struct delayed_work twl4030_bci_monitor_work;
180 struct delayed_work twl4030_bk_bci_monitor_work;
182 struct twl4030_bci_platform_data *pdata;
185 static int LVL_1, LVL_2, LVL_3, LVL_4;
187 static int read_bci_val(u8 reg_1);
188 static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg);
189 static int twl4030charger_presence(void);
192 * Report and clear the charger presence event.
194 static inline int twl4030charger_presence_evt(void)
197 u8 chg_sts, set = 0, clear = 0;
199 /* read charger power supply status */
200 ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts,
201 REG_STS_HW_CONDITIONS);
205 if (chg_sts & STS_CHG) { /* If the AC charger have been connected */
206 /* configuring falling edge detection for CHG_PRES */
207 set = CHG_PRES_FALLING;
208 clear = CHG_PRES_RISING;
209 } else { /* If the AC charger have been disconnected */
210 /* configuring rising edge detection for CHG_PRES */
211 set = CHG_PRES_RISING;
212 clear = CHG_PRES_FALLING;
215 /* Update the interrupt edge detection register */
216 clear_n_set(TWL4030_MODULE_INT, clear, set, REG_PWR_EDR1);
222 * Interrupt service routine
224 * Attends to TWL 4030 power module interruptions events, specifically
225 * USB_PRES (USB charger presence) CHG_PRES (AC charger presence) events
228 static irqreturn_t twl4030charger_interrupt(int irq, void *_di)
230 struct twl4030_bci_device_info *di = _di;
232 #ifdef CONFIG_LOCKDEP
233 /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
234 * we don't want and can't tolerate. Although it might be
235 * friendlier not to borrow this thread context...
240 twl4030charger_presence_evt();
241 cancel_delayed_work(&di->twl4030_bci_monitor_work);
242 schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
248 * This function handles the twl4030 battery presence interrupt
250 static int twl4030battery_presence_evt(void)
253 u8 batstsmchg, batstspchg;
255 /* check for the battery presence in main charge*/
256 ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
257 &batstsmchg, REG_BCIMFSTS3);
261 /* check for the battery presence in precharge */
262 ret = twl4030_i2c_read_u8(TWL4030_MODULE_PRECHARGE,
263 &batstspchg, REG_BCIMFSTS1);
268 * REVISIT: Physically inserting/removing the batt
269 * does not seem to generate an int on 3430ES2 SDP.
271 if ((batstspchg & BATSTSPCHG) || (batstsmchg & BATSTSMCHG)) {
272 /* In case of the battery insertion event */
273 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRRISIN,
274 BATSTS_EDRFALLING, REG_BCIEDR2);
278 /* In case of the battery removal event */
279 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRFALLING,
280 BATSTS_EDRRISIN, REG_BCIEDR2);
289 * This function handles the twl4030 battery voltage level interrupt.
291 static int twl4030battery_level_evt(void)
296 /* checking for threshold event */
297 ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
298 &mfst, REG_BCIMFSTS2);
302 /* REVISIT could use a bitmap */
303 if (mfst & VBATOV4) {
308 } else if (mfst & VBATOV3) {
313 } else if (mfst & VBATOV2) {
329 * Interrupt service routine
331 * Attends to BCI interruptions events,
332 * specifically BATSTS (battery connection and removal)
333 * VBATOV (main battery voltage threshold) events
336 static irqreturn_t twl4030battery_interrupt(int irq, void *_di)
338 u8 isr1a_val, isr2a_val, clear_2a, clear_1a;
341 #ifdef CONFIG_LOCKDEP
342 /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
343 * we don't want and can't tolerate. Although it might be
344 * friendlier not to borrow this thread context...
349 ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr1a_val,
354 ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr2a_val,
359 clear_2a = (isr2a_val & VBATLVL_ISR1) ? (VBATLVL_ISR1) : 0;
360 clear_1a = (isr1a_val & BATSTS_ISR1) ? (BATSTS_ISR1) : 0;
362 /* cleaning BCI interrupt status flags */
363 ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
364 clear_1a , REG_BCIISR1A);
368 ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
369 clear_2a , REG_BCIISR2A);
373 /* battery connetion or removal event */
374 if (isr1a_val & BATSTS_ISR1)
375 twl4030battery_presence_evt();
376 /* battery voltage threshold event*/
377 else if (isr2a_val & VBATLVL_ISR1)
378 twl4030battery_level_evt();
386 * Enable/Disable hardware battery level event notifications.
388 static int twl4030battery_hw_level_en(int enable)
393 /* unmask VBATOV interrupt for INT1 */
394 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, VBATLVL_IMR1,
399 /* configuring interrupt edge detection for VBATOv */
400 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
401 VBATLVL_EDRRISIN, REG_BCIEDR3);
405 /* mask VBATOV interrupt for INT1 */
406 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
407 VBATLVL_IMR1, REG_BCIIMR2A);
416 * Enable/disable hardware battery presence event notifications.
418 static int twl4030battery_hw_presence_en(int enable)
423 /* unmask BATSTS interrupt for INT1 */
424 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_IMR1,
429 /* configuring interrupt edge for BATSTS */
430 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
431 BATSTS_EDRRISIN | BATSTS_EDRFALLING, REG_BCIEDR2);
435 /* mask BATSTS interrupt for INT1 */
436 ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
437 BATSTS_IMR1, REG_BCIIMR1A);
446 * Enable/Disable AC Charge funtionality.
448 static int twl4030charger_ac_en(int enable, int automatic)
453 /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 1 */
455 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC | CVENAC,
456 (CONFIG_DONE | BCIAUTOWEN),
459 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
460 (CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC | CVENAC),
466 /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 0*/
467 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC,
468 (CONFIG_DONE | BCIAUTOWEN),
478 * Enable/Disable USB Charge funtionality.
480 int twl4030charger_usb_en(int enable)
485 /* Check for USB charger conneted */
486 ret = twl4030charger_presence();
490 if (!(ret & USB_PW_CONN))
493 /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
494 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
495 (CONFIG_DONE | BCIAUTOWEN | BCIAUTOUSB),
500 /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
501 ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0,
502 USBFASTMCHG, REG_BCIMFSTS4);
506 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOUSB,
507 (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI);
516 * Return battery temperature
519 static int twl4030battery_temperature(struct twl4030_bci_device_info *di)
522 int temp, curr, volt, res, ret;
524 /* Is a temperature table specified? */
525 if (!di->pdata->tblsize)
528 /* Getting and calculating the thermistor voltage */
529 ret = read_bci_val(T2_BATTERY_TEMP);
533 volt = (ret * TEMP_STEP_SIZE) / TEMP_PSR_R;
535 /* Getting and calculating the supply current in micro ampers */
536 ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
541 curr = ((val & ITHSENS) + 1) * 10;
543 /* Getting and calculating the thermistor resistance in ohms*/
544 res = volt * 1000 / curr;
546 /*calculating temperature*/
547 for (temp = 58; temp >= 0; temp--) {
548 int actual = di->pdata->battery_tmp_tbl[temp];
549 if ((actual - res) >= 0)
553 /* Negative temperature */
567 * Return battery voltage
570 static int twl4030battery_voltage(void)
572 int volt = read_bci_val(T2_BATTERY_VOLT);
574 return (volt * VOLT_STEP_SIZE) / VOLT_PSR_R;
578 * Return the battery current
581 static int twl4030battery_current(void)
583 int ret, curr = read_bci_val(T2_BATTERY_CUR);
586 ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
592 //ret = (int)((float)curr * 1.6617790811339199f * 2.0f - 1.7f);
593 ret = curr * 16618 * 2 - 1700 * 10000;
595 //ret = (int)((float)curr * 1.6617790811339199f - 0.85f);
596 ret = curr * 16618 - 850 * 10000;
602 * Return the battery backup voltage
605 static int twl4030backupbatt_voltage(void)
607 struct twl4030_madc_request req;
610 req.channels = (1 << 9);
612 req.method = TWL4030_MADC_SW1;
615 twl4030_madc_conversion(&req);
616 temp = (u16)req.rbuf[9];
618 return (temp * BK_VOLT_STEP_SIZE) / BK_VOLT_PSR_R;
622 * Returns an integer value, that means,
623 * NO_PW_CONN no power supply is connected
624 * AC_PW_CONN if the AC power supply is connected
625 * USB_PW_CONN if the USB power supply is connected
626 * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
630 static int twl4030charger_presence(void)
635 ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
636 REG_STS_HW_CONDITIONS);
638 pr_err("twl4030_bci: error reading STS_HW_CONDITIONS\n");
642 ret = (hwsts & STS_CHG) ? AC_PW_CONN : NO_PW_CONN;
644 /* in case we have STS_USB_ID, VBUS is driven by TWL itself */
645 if ((hwsts & STS_VBUS) && !(hwsts & STS_USB_ID))
648 pr_debug("USB charger: %d, HW_CONDITIONS %02x\n",
649 !!(ret & USB_PW_CONN), hwsts);
655 * Returns the main charge FSM status
658 static int twl4030bci_status(void)
663 ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
664 &status, REG_BCIMSTATEC);
666 pr_err("twl4030_bci: error reading BCIMSTATEC\n");
670 return (int) (status & BCIMSTAT_MASK);
673 static int is_charge_state(int status)
676 return (1 < status && status < 8);
679 static int read_bci_val(u8 reg)
685 ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
690 temp = ((int)(val & 0x03)) << 8;
693 ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
702 * Settup the twl4030 BCI module to enable backup
705 static int twl4030backupbatt_voltage_setup(void)
709 /* Starting backup batery charge */
710 ret = clear_n_set(TWL4030_MODULE_PM_RECEIVER, 0, BBCHEN,
719 * Settup the twl4030 BCI module to measure battery
722 static int twl4030battery_temp_setup(void)
726 /* Enabling thermistor current */
727 ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, 0x1B,
736 * Sets and clears bits on an given register on a given module
738 static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg)
743 /* Gets the initial register value */
744 ret = twl4030_i2c_read_u8(mod_no, &val, reg);
747 /* Clearing all those bits to clear */
750 /* Setting all those bits to set */
753 /* Update the register */
754 ret = twl4030_i2c_write_u8(mod_no, val, reg);
761 int set_charge_current(int new_current)
763 u8 tmp, boot_bci_prev;
766 ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &boot_bci_prev, REG_BOOT_BCI);
770 /* Leave automatic mode as some things cannot be changed there. */
771 ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC | BCIAUTOUSB | CVENAC,
772 (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI);
776 ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, KEY_IIREF, REG_BCIMFKEY);
780 ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, new_current & 0xff, REG_BCIIREF1);
784 ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, KEY_IIREF, REG_BCIMFKEY);
788 ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, (new_current >> 8) & 0x1, REG_BCIIREF2);
792 /* Set CGAIN = 0 or 1 */
793 if (new_current > 511) {
794 /* Set CGAIN = 1 -- need to wait until automatic charge turns off */
795 for (i = 0; i < 10; i++) {
796 clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, CGAIN | 0x1B, REG_BCICTL1);
797 twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &tmp, REG_BCICTL1);
805 /* Set CGAIN = 0 -- need to wait until automatic charge turns off */
806 for (i = 0; i < 10; i++) {
807 clear_n_set(TWL4030_MODULE_MAIN_CHARGE, CGAIN, 0x1B, REG_BCICTL1);
808 twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &tmp, REG_BCICTL1);
810 ret = !(tmp & CGAIN);
818 pr_err("CGAIN change failed\n");
820 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, boot_bci_prev, REG_BOOT_BCI);
825 static enum power_supply_property twl4030_bci_battery_props[] = {
826 POWER_SUPPLY_PROP_STATUS,
827 POWER_SUPPLY_PROP_ONLINE,
828 POWER_SUPPLY_PROP_VOLTAGE_NOW,
829 POWER_SUPPLY_PROP_CURRENT_NOW,
830 POWER_SUPPLY_PROP_CAPACITY,
831 POWER_SUPPLY_PROP_TEMP,
834 static enum power_supply_property twl4030_bk_bci_battery_props[] = {
835 POWER_SUPPLY_PROP_VOLTAGE_NOW,
839 twl4030_bk_bci_battery_read_status(struct twl4030_bci_device_info *di)
841 di->bk_voltage_uV = twl4030backupbatt_voltage();
844 static void twl4030_bk_bci_battery_work(struct work_struct *work)
846 struct twl4030_bci_device_info *di = container_of(work,
847 struct twl4030_bci_device_info,
848 twl4030_bk_bci_monitor_work.work);
850 if(!di->pdata->no_backup_battery)
851 twl4030_bk_bci_battery_read_status(di);
852 schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
855 static void twl4030_bci_battery_read_status(struct twl4030_bci_device_info *di)
857 di->temp_C = twl4030battery_temperature(di);
858 di->voltage_uV = twl4030battery_voltage();
859 di->current_uA = twl4030battery_current();
862 static void twl4030_bci_battery_work(struct work_struct *work)
864 struct twl4030_bci_device_info *di = container_of(work,
865 struct twl4030_bci_device_info, twl4030_bci_monitor_work.work);
868 twl4030_bci_battery_read_status(di);
870 source = power_supply_am_i_supplied(&di->bat);
872 di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
874 di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
876 if (source != di->charge_source) {
877 pr_debug("charge source changed to %d\n", source);
879 di->charge_source = source;
880 power_supply_changed(&di->bat);
881 if (source == POWER_SUPPLY_TYPE_MAINS)
882 set_charge_current(di->ac_current);
884 set_charge_current(di->usb_current);
887 schedule_delayed_work(&di->twl4030_bci_monitor_work, HZ);
890 #define to_twl4030_bk_bci_device_info(x) container_of((x), \
891 struct twl4030_bci_device_info, bk_bat);
894 show_charge_current(struct device *dev, struct device_attribute *attr, char *buf)
897 int ret = read_bci_val(REG_BCIIREF1) & 0x1FF;
898 twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ctl, REG_BCICTL1);
905 twl4030battery_temp_setup();
908 return sprintf(buf, "%d\n", ret);
912 store_charge_current(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
914 struct twl4030_bci_device_info *di = dev_get_drvdata(dev);
915 unsigned long new_current;
918 ret = strict_strtoul(buf, 10, &new_current);
922 ret = set_charge_current(new_current);
926 if (di->charge_source == POWER_SUPPLY_TYPE_MAINS)
927 di->ac_current = new_current;
929 di->usb_current = new_current;
933 static DEVICE_ATTR(charge_current, S_IRUGO | S_IWUSR, show_charge_current, store_charge_current);
935 static int twl4030_bk_bci_battery_get_property(struct power_supply *psy,
936 enum power_supply_property psp,
937 union power_supply_propval *val)
939 struct twl4030_bci_device_info *di = to_twl4030_bk_bci_device_info(psy);
942 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
943 val->intval = di->bk_voltage_uV;
952 #define to_twl4030_bci_device_info(x) container_of((x), \
953 struct twl4030_bci_device_info, bat);
955 static int twl4030_bci_battery_get_property(struct power_supply *psy,
956 enum power_supply_property psp,
957 union power_supply_propval *val)
959 struct twl4030_bci_device_info *di;
962 di = to_twl4030_bci_device_info(psy);
965 case POWER_SUPPLY_PROP_STATUS:
966 val->intval = di->charge_status;
973 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
974 val->intval = di->voltage_uV;
976 case POWER_SUPPLY_PROP_CURRENT_NOW:
977 val->intval = di->current_uA;
979 case POWER_SUPPLY_PROP_TEMP:
980 val->intval = di->temp_C;
982 case POWER_SUPPLY_PROP_ONLINE:
983 status = twl4030bci_status();
984 if ((status & AC_STATEC) && is_charge_state(status))
985 val->intval = POWER_SUPPLY_TYPE_MAINS;
986 else if ((status & USB_STATEC) && is_charge_state(status))
987 val->intval = POWER_SUPPLY_TYPE_USB;
991 case POWER_SUPPLY_PROP_CAPACITY:
993 * need to get the correct percentage value per the
994 * battery characteristics. Approx values for now.
996 if (di->voltage_uV < 2894 || LVL_1) {
999 } else if ((di->voltage_uV < 3451 && di->voltage_uV > 2894)
1003 } else if ((di->voltage_uV < 3902 && di->voltage_uV > 3451)
1007 } else if ((di->voltage_uV < 3949 && di->voltage_uV > 3902)
1011 } else if (di->voltage_uV > 3949)
1020 static char *twl4030_bci_supplied_to[] = {
1021 "twl4030_bci_battery",
1024 static int __init twl4030_bci_battery_probe(struct platform_device *pdev)
1026 struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
1027 struct twl4030_bci_device_info *di;
1031 di = kzalloc(sizeof(*di), GFP_KERNEL);
1035 di->dev = &pdev->dev;
1036 di->bat.name = "twl4030_bci_battery";
1037 di->bat.supplied_to = twl4030_bci_supplied_to;
1038 di->bat.num_supplicants = ARRAY_SIZE(twl4030_bci_supplied_to);
1039 di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
1040 di->bat.properties = twl4030_bci_battery_props;
1041 di->bat.num_properties = ARRAY_SIZE(twl4030_bci_battery_props);
1042 di->bat.get_property = twl4030_bci_battery_get_property;
1043 di->bat.external_power_changed = NULL;
1045 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
1046 di->ac_current = 820; /* ~1A */
1047 di->usb_current = 360; /* ~600mA */
1049 di->bk_bat.name = "twl4030_bci_bk_battery";
1050 di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
1051 di->bk_bat.properties = twl4030_bk_bci_battery_props;
1052 di->bk_bat.num_properties = ARRAY_SIZE(twl4030_bk_bci_battery_props);
1053 di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
1054 di->bk_bat.external_power_changed = NULL;
1058 clear_n_set(TWL4030_MODULE_INTBR, 0,
1059 MADC_HFCLK_EN | DEFAULT_MADC_CLK_EN, REG_GPBR1);
1061 twl4030charger_ac_en(ENABLE, CHARGE_MODE);
1062 twl4030charger_usb_en(ENABLE);
1063 twl4030battery_hw_level_en(ENABLE);
1064 twl4030battery_hw_presence_en(ENABLE);
1066 platform_set_drvdata(pdev, di);
1068 /* settings for temperature sensing */
1069 ret = twl4030battery_temp_setup();
1071 goto temp_setup_fail;
1073 /* enabling GPCH09 for read back battery voltage */
1074 if(!di->pdata->no_backup_battery)
1076 ret = twl4030backupbatt_voltage_setup();
1078 goto voltage_setup_fail;
1081 /* REVISIT do we need to request both IRQs ?? */
1083 /* request BCI interruption */
1084 ret = request_irq(TWL4030_MODIRQ_BCI, twl4030battery_interrupt,
1085 0, pdev->name, NULL);
1087 dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
1088 TWL4030_MODIRQ_BCI, ret);
1092 irq = platform_get_irq(pdev, 0);
1094 /* request Power interruption */
1095 ret = request_irq(irq, twl4030charger_interrupt,
1099 dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
1104 ret = power_supply_register(&pdev->dev, &di->bat);
1106 dev_dbg(&pdev->dev, "failed to register main battery\n");
1110 INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bci_monitor_work,
1111 twl4030_bci_battery_work);
1112 schedule_delayed_work(&di->twl4030_bci_monitor_work, HZ);
1114 if(!pdata->no_backup_battery)
1116 ret = power_supply_register(&pdev->dev, &di->bk_bat);
1118 dev_dbg(&pdev->dev, "failed to register backup battery\n");
1119 goto bk_batt_failed;
1123 ret = device_create_file(di->bat.dev, &dev_attr_charge_current);
1125 dev_err(&pdev->dev, "failed to create sysfs entries\n");
1126 goto bk_batt_failed;
1129 INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bk_bci_monitor_work,
1130 twl4030_bk_bci_battery_work);
1131 schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
1136 if(!pdata->no_backup_battery)
1137 power_supply_unregister(&di->bat);
1141 free_irq(TWL4030_MODIRQ_BCI, NULL);
1145 twl4030charger_ac_en(DISABLE, CHARGE_MODE);
1146 twl4030charger_usb_en(DISABLE);
1147 twl4030battery_hw_level_en(DISABLE);
1148 twl4030battery_hw_presence_en(DISABLE);
1154 static int __exit twl4030_bci_battery_remove(struct platform_device *pdev)
1156 struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1157 int irq = platform_get_irq(pdev, 0);
1159 twl4030charger_ac_en(DISABLE, CHARGE_MODE);
1160 twl4030charger_usb_en(DISABLE);
1161 twl4030battery_hw_level_en(DISABLE);
1162 twl4030battery_hw_presence_en(DISABLE);
1164 free_irq(TWL4030_MODIRQ_BCI, NULL);
1167 flush_scheduled_work();
1168 power_supply_unregister(&di->bat);
1169 power_supply_unregister(&di->bk_bat);
1170 platform_set_drvdata(pdev, NULL);
1177 static int twl4030_bci_battery_suspend(struct platform_device *pdev,
1180 struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1182 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
1183 cancel_delayed_work(&di->twl4030_bci_monitor_work);
1184 cancel_delayed_work(&di->twl4030_bk_bci_monitor_work);
1188 static int twl4030_bci_battery_resume(struct platform_device *pdev)
1190 struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
1192 schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
1193 schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 50);
1197 #define twl4030_bci_battery_suspend NULL
1198 #define twl4030_bci_battery_resume NULL
1199 #endif /* CONFIG_PM */
1201 static struct platform_driver twl4030_bci_battery_driver = {
1202 .probe = twl4030_bci_battery_probe,
1203 .remove = __exit_p(twl4030_bci_battery_remove),
1204 .suspend = twl4030_bci_battery_suspend,
1205 .resume = twl4030_bci_battery_resume,
1207 .name = "twl4030_bci",
1211 MODULE_LICENSE("GPL");
1212 MODULE_ALIAS("platform:twl4030_bci");
1213 MODULE_AUTHOR("Texas Instruments Inc");
1215 static int __init twl4030_battery_init(void)
1217 return platform_driver_register(&twl4030_bci_battery_driver);
1219 module_init(twl4030_battery_init);
1221 static void __exit twl4030_battery_exit(void)
1223 platform_driver_unregister(&twl4030_bci_battery_driver);
1225 module_exit(twl4030_battery_exit);