diff options
-rw-r--r-- | drivers/power/twl4030_charger.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 3b7cc631bb8a..982675df21b7 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/i2c/twl4030-madc.h> | ||
25 | 26 | ||
26 | #define TWL4030_BCIMSTATEC 0x02 | 27 | #define TWL4030_BCIMSTATEC 0x02 |
27 | #define TWL4030_BCIICHG 0x08 | 28 | #define TWL4030_BCIICHG 0x08 |
@@ -101,10 +102,13 @@ struct twl4030_bci { | |||
101 | int usb_enabled; | 102 | int usb_enabled; |
102 | 103 | ||
103 | /* | 104 | /* |
104 | * ichg values in uA. If any are 'large', we set CGAIN to | 105 | * ichg_* and *_cur values in uA. If any are 'large', we set |
105 | * '1' which doubles the range for half the precision. | 106 | * CGAIN to '1' which doubles the range for half the |
107 | * precision. | ||
106 | */ | 108 | */ |
107 | unsigned int ichg_eoc, ichg_lo, ichg_hi, cur; | 109 | unsigned int ichg_eoc, ichg_lo, ichg_hi; |
110 | unsigned int usb_cur, ac_cur; | ||
111 | bool ac_is_active; | ||
108 | 112 | ||
109 | unsigned long event; | 113 | unsigned long event; |
110 | }; | 114 | }; |
@@ -225,11 +229,24 @@ static int ua2regval(int ua, bool cgain) | |||
225 | static int twl4030_charger_update_current(struct twl4030_bci *bci) | 229 | static int twl4030_charger_update_current(struct twl4030_bci *bci) |
226 | { | 230 | { |
227 | int status; | 231 | int status; |
232 | int cur; | ||
228 | unsigned reg, cur_reg; | 233 | unsigned reg, cur_reg; |
229 | u8 bcictl1, oldreg, fullreg; | 234 | u8 bcictl1, oldreg, fullreg; |
230 | bool cgain = false; | 235 | bool cgain = false; |
231 | u8 boot_bci; | 236 | u8 boot_bci; |
232 | 237 | ||
238 | /* | ||
239 | * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11) | ||
240 | * and AC is enabled, set current for 'ac' | ||
241 | */ | ||
242 | if (twl4030_get_madc_conversion(11) > 4500) { | ||
243 | cur = bci->ac_cur; | ||
244 | bci->ac_is_active = true; | ||
245 | } else { | ||
246 | cur = bci->usb_cur; | ||
247 | bci->ac_is_active = false; | ||
248 | } | ||
249 | |||
233 | /* First, check thresholds and see if cgain is needed */ | 250 | /* First, check thresholds and see if cgain is needed */ |
234 | if (bci->ichg_eoc >= 200000) | 251 | if (bci->ichg_eoc >= 200000) |
235 | cgain = true; | 252 | cgain = true; |
@@ -237,7 +254,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) | |||
237 | cgain = true; | 254 | cgain = true; |
238 | if (bci->ichg_hi >= 820000) | 255 | if (bci->ichg_hi >= 820000) |
239 | cgain = true; | 256 | cgain = true; |
240 | if (bci->cur > 852000) | 257 | if (cur > 852000) |
241 | cgain = true; | 258 | cgain = true; |
242 | 259 | ||
243 | status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); | 260 | status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); |
@@ -318,7 +335,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) | |||
318 | * And finally, set the current. This is stored in | 335 | * And finally, set the current. This is stored in |
319 | * two registers. | 336 | * two registers. |
320 | */ | 337 | */ |
321 | reg = ua2regval(bci->cur, cgain); | 338 | reg = ua2regval(cur, cgain); |
322 | /* we have only 10 bits */ | 339 | /* we have only 10 bits */ |
323 | if (reg > 0x3ff) | 340 | if (reg > 0x3ff) |
324 | reg = 0x3ff; | 341 | reg = 0x3ff; |
@@ -371,6 +388,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) | |||
371 | 388 | ||
372 | if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { | 389 | if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { |
373 | 390 | ||
391 | twl4030_charger_update_current(bci); | ||
392 | |||
374 | /* Need to keep phy powered */ | 393 | /* Need to keep phy powered */ |
375 | if (!bci->usb_enabled) { | 394 | if (!bci->usb_enabled) { |
376 | pm_runtime_get_sync(bci->transceiver->dev); | 395 | pm_runtime_get_sync(bci->transceiver->dev); |
@@ -463,6 +482,7 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) | |||
463 | struct twl4030_bci *bci = arg; | 482 | struct twl4030_bci *bci = arg; |
464 | 483 | ||
465 | dev_dbg(bci->dev, "CHG_PRES irq\n"); | 484 | dev_dbg(bci->dev, "CHG_PRES irq\n"); |
485 | twl4030_charger_update_current(bci); | ||
466 | power_supply_changed(bci->ac); | 486 | power_supply_changed(bci->ac); |
467 | power_supply_changed(bci->usb); | 487 | power_supply_changed(bci->usb); |
468 | 488 | ||
@@ -495,6 +515,7 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) | |||
495 | power_supply_changed(bci->ac); | 515 | power_supply_changed(bci->ac); |
496 | power_supply_changed(bci->usb); | 516 | power_supply_changed(bci->usb); |
497 | } | 517 | } |
518 | twl4030_charger_update_current(bci); | ||
498 | 519 | ||
499 | /* various monitoring events, for now we just log them here */ | 520 | /* various monitoring events, for now we just log them here */ |
500 | if (irqs1 & (TWL4030_TBATOR2 | TWL4030_TBATOR1)) | 521 | if (irqs1 & (TWL4030_TBATOR2 | TWL4030_TBATOR1)) |
@@ -724,10 +745,11 @@ static int twl4030_bci_probe(struct platform_device *pdev) | |||
724 | bci->ichg_eoc = 80100; /* Stop charging when current drops to here */ | 745 | bci->ichg_eoc = 80100; /* Stop charging when current drops to here */ |
725 | bci->ichg_lo = 241000; /* Low threshold */ | 746 | bci->ichg_lo = 241000; /* Low threshold */ |
726 | bci->ichg_hi = 500000; /* High threshold */ | 747 | bci->ichg_hi = 500000; /* High threshold */ |
748 | bci->ac_cur = 500000; /* 500mA */ | ||
727 | if (allow_usb) | 749 | if (allow_usb) |
728 | bci->cur = 500000; /* 500mA */ | 750 | bci->usb_cur = 500000; /* 500mA */ |
729 | else | 751 | else |
730 | bci->cur = 100000; /* 100mA */ | 752 | bci->usb_cur = 100000; /* 100mA */ |
731 | 753 | ||
732 | bci->dev = &pdev->dev; | 754 | bci->dev = &pdev->dev; |
733 | bci->irq_chg = platform_get_irq(pdev, 0); | 755 | bci->irq_chg = platform_get_irq(pdev, 0); |