aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/power/twl4030_charger.c67
1 files changed, 61 insertions, 6 deletions
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 68117ad23564..2c537ee11bbe 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -119,6 +119,18 @@ struct twl4030_bci {
119#define CHARGE_AUTO 1 119#define CHARGE_AUTO 1
120#define CHARGE_LINEAR 2 120#define CHARGE_LINEAR 2
121 121
122 /* When setting the USB current we slowly increase the
123 * requested current until target is reached or the voltage
124 * drops below 4.75V. In the latter case we step back one
125 * step.
126 */
127 unsigned int usb_cur_target;
128 struct delayed_work current_worker;
129#define USB_CUR_STEP 20000 /* 20mA at a time */
130#define USB_MIN_VOLT 4750000 /* 4.75V */
131#define USB_CUR_DELAY msecs_to_jiffies(100)
132#define USB_MAX_CURRENT 1700000 /* TWL4030 caps at 1.7A */
133
122 unsigned long event; 134 unsigned long event;
123}; 135};
124 136
@@ -257,6 +269,12 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci)
257 } else { 269 } else {
258 cur = bci->usb_cur; 270 cur = bci->usb_cur;
259 bci->ac_is_active = false; 271 bci->ac_is_active = false;
272 if (cur > bci->usb_cur_target) {
273 cur = bci->usb_cur_target;
274 bci->usb_cur = cur;
275 }
276 if (cur < bci->usb_cur_target)
277 schedule_delayed_work(&bci->current_worker, USB_CUR_DELAY);
260 } 278 }
261 279
262 /* First, check thresholds and see if cgain is needed */ 280 /* First, check thresholds and see if cgain is needed */
@@ -391,6 +409,41 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci)
391 return 0; 409 return 0;
392} 410}
393 411
412static int twl4030_charger_get_current(void);
413
414static void twl4030_current_worker(struct work_struct *data)
415{
416 int v, curr;
417 int res;
418 struct twl4030_bci *bci = container_of(data, struct twl4030_bci,
419 current_worker.work);
420
421 res = twl4030bci_read_adc_val(TWL4030_BCIVBUS);
422 if (res < 0)
423 v = 0;
424 else
425 /* BCIVBUS uses ADCIN8, 7/1023 V/step */
426 v = res * 6843;
427 curr = twl4030_charger_get_current();
428
429 dev_dbg(bci->dev, "v=%d cur=%d limit=%d target=%d\n", v, curr,
430 bci->usb_cur, bci->usb_cur_target);
431
432 if (v < USB_MIN_VOLT) {
433 /* Back up and stop adjusting. */
434 bci->usb_cur -= USB_CUR_STEP;
435 bci->usb_cur_target = bci->usb_cur;
436 } else if (bci->usb_cur >= bci->usb_cur_target ||
437 bci->usb_cur + USB_CUR_STEP > USB_MAX_CURRENT) {
438 /* Reached target and voltage is OK - stop */
439 return;
440 } else {
441 bci->usb_cur += USB_CUR_STEP;
442 schedule_delayed_work(&bci->current_worker, USB_CUR_DELAY);
443 }
444 twl4030_charger_update_current(bci);
445}
446
394/* 447/*
395 * Enable/Disable USB Charge functionality. 448 * Enable/Disable USB Charge functionality.
396 */ 449 */
@@ -451,6 +504,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
451 pm_runtime_put_autosuspend(bci->transceiver->dev); 504 pm_runtime_put_autosuspend(bci->transceiver->dev);
452 bci->usb_enabled = 0; 505 bci->usb_enabled = 0;
453 } 506 }
507 bci->usb_cur = 0;
454 } 508 }
455 509
456 return ret; 510 return ret;
@@ -599,7 +653,7 @@ twl4030_bci_max_current_store(struct device *dev, struct device_attribute *attr,
599 if (dev == &bci->ac->dev) 653 if (dev == &bci->ac->dev)
600 bci->ac_cur = cur; 654 bci->ac_cur = cur;
601 else 655 else
602 bci->usb_cur = cur; 656 bci->usb_cur_target = cur;
603 657
604 twl4030_charger_update_current(bci); 658 twl4030_charger_update_current(bci);
605 return n; 659 return n;
@@ -621,7 +675,7 @@ static ssize_t twl4030_bci_max_current_show(struct device *dev,
621 cur = bci->ac_cur; 675 cur = bci->ac_cur;
622 } else { 676 } else {
623 if (bci->ac_is_active) 677 if (bci->ac_is_active)
624 cur = bci->usb_cur; 678 cur = bci->usb_cur_target;
625 } 679 }
626 if (cur < 0) { 680 if (cur < 0) {
627 cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1); 681 cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
@@ -662,9 +716,9 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
662 716
663 /* reset current on each 'plug' event */ 717 /* reset current on each 'plug' event */
664 if (allow_usb) 718 if (allow_usb)
665 bci->usb_cur = 500000; 719 bci->usb_cur_target = 500000;
666 else 720 else
667 bci->usb_cur = 100000; 721 bci->usb_cur_target = 100000;
668 722
669 bci->event = val; 723 bci->event = val;
670 schedule_work(&bci->work); 724 schedule_work(&bci->work);
@@ -927,9 +981,9 @@ static int twl4030_bci_probe(struct platform_device *pdev)
927 bci->ichg_hi = 500000; /* High threshold */ 981 bci->ichg_hi = 500000; /* High threshold */
928 bci->ac_cur = 500000; /* 500mA */ 982 bci->ac_cur = 500000; /* 500mA */
929 if (allow_usb) 983 if (allow_usb)
930 bci->usb_cur = 500000; /* 500mA */ 984 bci->usb_cur_target = 500000; /* 500mA */
931 else 985 else
932 bci->usb_cur = 100000; /* 100mA */ 986 bci->usb_cur_target = 100000; /* 100mA */
933 bci->usb_mode = CHARGE_AUTO; 987 bci->usb_mode = CHARGE_AUTO;
934 bci->ac_mode = CHARGE_AUTO; 988 bci->ac_mode = CHARGE_AUTO;
935 989
@@ -980,6 +1034,7 @@ static int twl4030_bci_probe(struct platform_device *pdev)
980 } 1034 }
981 1035
982 INIT_WORK(&bci->work, twl4030_bci_usb_work); 1036 INIT_WORK(&bci->work, twl4030_bci_usb_work);
1037 INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker);
983 1038
984 bci->usb_nb.notifier_call = twl4030_bci_usb_ncb; 1039 bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
985 if (bci->dev->of_node) { 1040 if (bci->dev->of_node) {