diff options
Diffstat (limited to 'drivers/power/twl4030_charger.c')
-rw-r--r-- | drivers/power/twl4030_charger.c | 80 |
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 | ||
105 | static int twl4030_clear_set_boot_bci(u8 clear, u8 set) | 120 | static 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 | */ |
157 | static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) | 172 | static 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 | */ | ||
233 | static 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 | */ |
208 | static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) | 276 | static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) |
@@ -425,6 +493,7 @@ static enum power_supply_property twl4030_charger_props[] = { | |||
425 | static int __init twl4030_bci_probe(struct platform_device *pdev) | 493 | static 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, |