diff options
author | Lee Jones <lee.jones@linaro.org> | 2013-02-14 12:39:15 +0000 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2013-03-07 12:35:46 +0800 |
commit | db43e6c473b57d4e7a55c4bd6edef71f40f13eae (patch) | |
tree | 0fbe4762c914ba15898cf8bcb9bd8e531fe8fc31 /drivers/power/abx500_chargalg.c | |
parent | 405fea1c6691eb8259f2ca879c9348a4cf5d898d (diff) | |
download | linux-db43e6c473b57d4e7a55c4bd6edef71f40f13eae.tar.gz linux-db43e6c473b57d4e7a55c4bd6edef71f40f13eae.tar.bz2 linux-db43e6c473b57d4e7a55c4bd6edef71f40f13eae.zip |
ab8500-bm: Add usb power path support
AB8540 supports power path function in USB charging mode for fast
power up with dead and weak battery, and it could extend
the battery age.
When USB charging starts, if the Vbattrue is below than SW cut off
voltage, power path and pre-charge should be enabled. If Vbattrue
is higher than SW cut off voltage, power path and pre-charge should
be disabled. This is to make sure full current to battery charge.
At the end of charge, power path should be enable again to reduce
charging the battery again.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/power/abx500_chargalg.c')
-rw-r--r-- | drivers/power/abx500_chargalg.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index a876976678ab..a9b8efdafb8f 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -34,6 +34,9 @@ /* End-of-charge criteria counter */ #define EOC_COND_CNT 10 +/* Plus margin for the low battery threshold */ +#define BAT_PLUS_MARGIN (100) + #define to_abx500_chargalg_device_info(x) container_of((x), \ struct abx500_chargalg, chargalg_psy); @@ -83,6 +86,7 @@ enum abx500_chargalg_states { STATE_HW_TEMP_PROTECT_INIT, STATE_HW_TEMP_PROTECT, STATE_NORMAL_INIT, + STATE_USB_PP_PRE_CHARGE, STATE_NORMAL, STATE_WAIT_FOR_RECHARGE_INIT, STATE_WAIT_FOR_RECHARGE, @@ -114,6 +118,7 @@ static const char *states[] = { "HW_TEMP_PROTECT_INIT", "HW_TEMP_PROTECT", "NORMAL_INIT", + "USB_PP_PRE_CHARGE", "NORMAL", "WAIT_FOR_RECHARGE_INIT", "WAIT_FOR_RECHARGE", @@ -560,6 +565,37 @@ static int abx500_chargalg_usb_en(struct abx500_chargalg *di, int enable, return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset); } + /** + * ab8540_chargalg_usb_pp_en() - Enable/ disable USB power path + * @di: pointer to the abx500_chargalg structure + * @enable: power path enable/disable + * + * The USB power path will be enable/ disable + */ +static int ab8540_chargalg_usb_pp_en(struct abx500_chargalg *di, bool enable) +{ + if (!di->usb_chg || !di->usb_chg->ops.pp_enable) + return -ENXIO; + + return di->usb_chg->ops.pp_enable(di->usb_chg, enable); +} + +/** + * ab8540_chargalg_usb_pre_chg_en() - Enable/ disable USB pre-charge + * @di: pointer to the abx500_chargalg structure + * @enable: USB pre-charge enable/disable + * + * The USB USB pre-charge will be enable/ disable + */ +static int ab8540_chargalg_usb_pre_chg_en(struct abx500_chargalg *di, + bool enable) +{ + if (!di->usb_chg || !di->usb_chg->ops.pre_chg_enable) + return -ENXIO; + + return di->usb_chg->ops.pre_chg_enable(di->usb_chg, enable); +} + /** * abx500_chargalg_update_chg_curr() - Update charger current * @di: pointer to the abx500_chargalg structure @@ -765,6 +801,9 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di) di->batt_data.avg_curr > 0) { if (++di->eoc_cnt >= EOC_COND_CNT) { di->eoc_cnt = 0; + if ((di->chg_info.charger_type & USB_CHG) && + (di->usb_chg->power_path)) + ab8540_chargalg_usb_pp_en(di, true); di->charge_status = POWER_SUPPLY_STATUS_FULL; di->maintenance_chg = true; dev_dbg(di->dev, "EOC reached!\n"); @@ -1465,6 +1504,22 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) break; case STATE_NORMAL_INIT: + if ((di->chg_info.charger_type & USB_CHG) && + di->usb_chg->power_path) { + if (di->batt_data.volt > + (di->bm->fg_params->lowbat_threshold + + BAT_PLUS_MARGIN)) { + ab8540_chargalg_usb_pre_chg_en(di, false); + ab8540_chargalg_usb_pp_en(di, false); + } else { + ab8540_chargalg_usb_pp_en(di, true); + ab8540_chargalg_usb_pre_chg_en(di, true); + abx500_chargalg_state_to(di, + STATE_USB_PP_PRE_CHARGE); + break; + } + } + abx500_chargalg_start_charging(di, di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); @@ -1479,6 +1534,13 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) break; + case STATE_USB_PP_PRE_CHARGE: + if (di->batt_data.volt > + (di->bm->fg_params->lowbat_threshold + + BAT_PLUS_MARGIN)) + abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + break; + case STATE_NORMAL: handle_maxim_chg_curr(di); if (di->charge_status == POWER_SUPPLY_STATUS_FULL && |