aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/twl4030_charger.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/twl4030_charger.c')
-rw-r--r--drivers/power/twl4030_charger.c80
1 files changed, 77 insertions, 3 deletions
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 7cacbaa68efe..15f4d5d8611b 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -22,6 +22,7 @@
22#include <linux/power_supply.h> 22#include <linux/power_supply.h>
23#include <linux/notifier.h> 23#include <linux/notifier.h>
24#include <linux/usb/otg.h> 24#include <linux/usb/otg.h>
25#include <linux/regulator/machine.h>
25 26
26#define TWL4030_BCIMSTATEC 0x02 27#define TWL4030_BCIMSTATEC 0x02
27#define TWL4030_BCIICHG 0x08 28#define TWL4030_BCIICHG 0x08
@@ -29,6 +30,7 @@
29#define TWL4030_BCIVBUS 0x0c 30#define TWL4030_BCIVBUS 0x0c
30#define TWL4030_BCIMFSTS4 0x10 31#define TWL4030_BCIMFSTS4 0x10
31#define TWL4030_BCICTL1 0x23 32#define TWL4030_BCICTL1 0x23
33#define TWL4030_BB_CFG 0x12
32 34
33#define TWL4030_BCIAUTOWEN BIT(5) 35#define TWL4030_BCIAUTOWEN BIT(5)
34#define TWL4030_CONFIG_DONE BIT(4) 36#define TWL4030_CONFIG_DONE BIT(4)
@@ -38,6 +40,17 @@
38#define TWL4030_USBFASTMCHG BIT(2) 40#define TWL4030_USBFASTMCHG BIT(2)
39#define TWL4030_STS_VBUS BIT(7) 41#define TWL4030_STS_VBUS BIT(7)
40#define TWL4030_STS_USB_ID BIT(2) 42#define TWL4030_STS_USB_ID BIT(2)
43#define TWL4030_BBCHEN BIT(4)
44#define TWL4030_BBSEL_MASK 0b1100
45#define TWL4030_BBSEL_2V5 0b0000
46#define TWL4030_BBSEL_3V0 0b0100
47#define TWL4030_BBSEL_3V1 0b1000
48#define TWL4030_BBSEL_3V2 0b1100
49#define TWL4030_BBISEL_MASK 0b11
50#define TWL4030_BBISEL_25uA 0b00
51#define TWL4030_BBISEL_150uA 0b01
52#define TWL4030_BBISEL_500uA 0b10
53#define TWL4030_BBISEL_1000uA 0b11
41 54
42/* BCI interrupts */ 55/* BCI interrupts */
43#define TWL4030_WOVF BIT(0) /* Watchdog overflow */ 56#define TWL4030_WOVF BIT(0) /* Watchdog overflow */
@@ -75,6 +88,8 @@ struct twl4030_bci {
75 struct work_struct work; 88 struct work_struct work;
76 int irq_chg; 89 int irq_chg;
77 int irq_bci; 90 int irq_bci;
91 struct regulator *usb_reg;
92 int usb_enabled;
78 93
79 unsigned long event; 94 unsigned long event;
80}; 95};
@@ -104,7 +119,7 @@ static int twl4030_bci_read(u8 reg, u8 *val)
104 119
105static int twl4030_clear_set_boot_bci(u8 clear, u8 set) 120static int twl4030_clear_set_boot_bci(u8 clear, u8 set)
106{ 121{
107 return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, 0, 122 return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, clear,
108 TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set, 123 TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set,
109 TWL4030_PM_MASTER_BOOT_BCI); 124 TWL4030_PM_MASTER_BOOT_BCI);
110} 125}
@@ -152,14 +167,14 @@ static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
152} 167}
153 168
154/* 169/*
155 * Enable/Disable USB Charge funtionality. 170 * Enable/Disable USB Charge functionality.
156 */ 171 */
157static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) 172static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
158{ 173{
159 int ret; 174 int ret;
160 175
161 if (enable) { 176 if (enable) {
162 /* Check for USB charger conneted */ 177 /* Check for USB charger connected */
163 if (!twl4030_bci_have_vbus(bci)) 178 if (!twl4030_bci_have_vbus(bci))
164 return -ENODEV; 179 return -ENODEV;
165 180
@@ -172,6 +187,12 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
172 return -EACCES; 187 return -EACCES;
173 } 188 }
174 189
190 /* Need to keep regulator on */
191 if (!bci->usb_enabled) {
192 regulator_enable(bci->usb_reg);
193 bci->usb_enabled = 1;
194 }
195
175 /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ 196 /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
176 ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); 197 ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
177 if (ret < 0) 198 if (ret < 0)
@@ -182,6 +203,10 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
182 TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); 203 TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
183 } else { 204 } else {
184 ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); 205 ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
206 if (bci->usb_enabled) {
207 regulator_disable(bci->usb_reg);
208 bci->usb_enabled = 0;
209 }
185 } 210 }
186 211
187 return ret; 212 return ret;
@@ -203,6 +228,49 @@ static int twl4030_charger_enable_ac(bool enable)
203} 228}
204 229
205/* 230/*
231 * Enable/Disable charging of Backup Battery.
232 */
233static int twl4030_charger_enable_backup(int uvolt, int uamp)
234{
235 int ret;
236 u8 flags;
237
238 if (uvolt < 2500000 ||
239 uamp < 25) {
240 /* disable charging of backup battery */
241 ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER,
242 TWL4030_BBCHEN, 0, TWL4030_BB_CFG);
243 return ret;
244 }
245
246 flags = TWL4030_BBCHEN;
247 if (uvolt >= 3200000)
248 flags |= TWL4030_BBSEL_3V2;
249 else if (uvolt >= 3100000)
250 flags |= TWL4030_BBSEL_3V1;
251 else if (uvolt >= 3000000)
252 flags |= TWL4030_BBSEL_3V0;
253 else
254 flags |= TWL4030_BBSEL_2V5;
255
256 if (uamp >= 1000)
257 flags |= TWL4030_BBISEL_1000uA;
258 else if (uamp >= 500)
259 flags |= TWL4030_BBISEL_500uA;
260 else if (uamp >= 150)
261 flags |= TWL4030_BBISEL_150uA;
262 else
263 flags |= TWL4030_BBISEL_25uA;
264
265 ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER,
266 TWL4030_BBSEL_MASK | TWL4030_BBISEL_MASK,
267 flags,
268 TWL4030_BB_CFG);
269
270 return ret;
271}
272
273/*
206 * TWL4030 CHG_PRES (AC charger presence) events 274 * TWL4030 CHG_PRES (AC charger presence) events
207 */ 275 */
208static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) 276static irqreturn_t twl4030_charger_interrupt(int irq, void *arg)
@@ -425,6 +493,7 @@ static enum power_supply_property twl4030_charger_props[] = {
425static int __init twl4030_bci_probe(struct platform_device *pdev) 493static int __init twl4030_bci_probe(struct platform_device *pdev)
426{ 494{
427 struct twl4030_bci *bci; 495 struct twl4030_bci *bci;
496 struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
428 int ret; 497 int ret;
429 u32 reg; 498 u32 reg;
430 499
@@ -456,6 +525,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
456 bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props); 525 bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props);
457 bci->usb.get_property = twl4030_bci_get_property; 526 bci->usb.get_property = twl4030_bci_get_property;
458 527
528 bci->usb_reg = regulator_get(bci->dev, "bci3v1");
529
459 ret = power_supply_register(&pdev->dev, &bci->usb); 530 ret = power_supply_register(&pdev->dev, &bci->usb);
460 if (ret) { 531 if (ret) {
461 dev_err(&pdev->dev, "failed to register usb: %d\n", ret); 532 dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
@@ -504,6 +575,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
504 575
505 twl4030_charger_enable_ac(true); 576 twl4030_charger_enable_ac(true);
506 twl4030_charger_enable_usb(bci, true); 577 twl4030_charger_enable_usb(bci, true);
578 twl4030_charger_enable_backup(pdata->bb_uvolt,
579 pdata->bb_uamp);
507 580
508 return 0; 581 return 0;
509 582
@@ -532,6 +605,7 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
532 605
533 twl4030_charger_enable_ac(false); 606 twl4030_charger_enable_ac(false);
534 twl4030_charger_enable_usb(bci, false); 607 twl4030_charger_enable_usb(bci, false);
608 twl4030_charger_enable_backup(0, 0);
535 609
536 /* mask interrupts */ 610 /* mask interrupts */
537 twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, 611 twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,