Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

Lee Jones db43e6c4 405fea1c

+160
+81
drivers/power/ab8500_charger.c
··· 1925 1925 return ret; 1926 1926 } 1927 1927 1928 + /** 1929 + * ab8540_charger_power_path_enable() - enable usb power path mode 1930 + * @charger: pointer to the ux500_charger structure 1931 + * @enable: enable/disable flag 1932 + * 1933 + * Enable or disable the power path for usb mode 1934 + * Returns error code in case of failure else 0(on success) 1935 + */ 1936 + static int ab8540_charger_power_path_enable(struct ux500_charger *charger, 1937 + bool enable) 1938 + { 1939 + int ret; 1940 + struct ab8500_charger *di; 1941 + 1942 + if (charger->psy.type == POWER_SUPPLY_TYPE_USB) 1943 + di = to_ab8500_charger_usb_device_info(charger); 1944 + else 1945 + return -ENXIO; 1946 + 1947 + ret = abx500_mask_and_set_register_interruptible(di->dev, 1948 + AB8500_CHARGER, AB8540_USB_PP_MODE_REG, 1949 + BUS_POWER_PATH_MODE_ENA, enable); 1950 + if (ret) { 1951 + dev_err(di->dev, "%s write failed\n", __func__); 1952 + return ret; 1953 + } 1954 + 1955 + return ret; 1956 + } 1957 + 1958 + 1959 + /** 1960 + * ab8540_charger_usb_pre_chg_enable() - enable usb pre change 1961 + * @charger: pointer to the ux500_charger structure 1962 + * @enable: enable/disable flag 1963 + * 1964 + * Enable or disable the pre-chage for usb mode 1965 + * Returns error code in case of failure else 0(on success) 1966 + */ 1967 + static int ab8540_charger_usb_pre_chg_enable(struct ux500_charger *charger, 1968 + bool enable) 1969 + { 1970 + int ret; 1971 + struct ab8500_charger *di; 1972 + 1973 + if (charger->psy.type == POWER_SUPPLY_TYPE_USB) 1974 + di = to_ab8500_charger_usb_device_info(charger); 1975 + else 1976 + return -ENXIO; 1977 + 1978 + ret = abx500_mask_and_set_register_interruptible(di->dev, 1979 + AB8500_CHARGER, AB8540_USB_PP_CHR_REG, 1980 + BUS_POWER_PATH_PRECHG_ENA, enable); 1981 + if (ret) { 1982 + dev_err(di->dev, "%s write failed\n", __func__); 1983 + return ret; 1984 + } 1985 + 1986 + return ret; 1987 + } 1988 + 1928 1989 static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data) 1929 1990 { 1930 1991 struct power_supply *psy; ··· 3262 3201 if (ret < 0) 3263 3202 dev_err(di->dev, "%s mask and set failed\n", __func__); 3264 3203 3204 + if (is_ab8540(di->parent)) { 3205 + ret = abx500_mask_and_set_register_interruptible(di->dev, 3206 + AB8500_CHARGER, AB8540_USB_PP_MODE_REG, 3207 + BUS_VSYS_VOL_SELECT_MASK, BUS_VSYS_VOL_SELECT_3P6V); 3208 + if (ret) { 3209 + dev_err(di->dev, "failed to setup usb power path vsys voltage\n"); 3210 + goto out; 3211 + } 3212 + ret = abx500_mask_and_set_register_interruptible(di->dev, 3213 + AB8500_CHARGER, AB8540_USB_PP_CHR_REG, 3214 + BUS_PP_PRECHG_CURRENT_MASK, 0); 3215 + if (ret) { 3216 + dev_err(di->dev, "failed to setup usb power path prechage current\n"); 3217 + goto out; 3218 + } 3219 + } 3220 + 3265 3221 out: 3266 3222 return ret; 3267 3223 } ··· 3562 3484 di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable; 3563 3485 di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 3564 3486 di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; 3487 + di->usb_chg.ops.pp_enable = &ab8540_charger_power_path_enable; 3488 + di->usb_chg.ops.pre_chg_enable = &ab8540_charger_usb_pre_chg_enable; 3565 3489 di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ 3566 3490 ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; 3567 3491 di->usb_chg.max_out_curr = ab8500_charger_current_map[ ··· 3571 3491 di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; 3572 3492 di->usb_chg.enabled = di->bm->usb_enabled; 3573 3493 di->usb_chg.external = false; 3494 + di->usb_chg.power_path = di->bm->usb_power_path; 3574 3495 di->usb_state.usb_current = -1; 3575 3496 3576 3497 /* Create a work queue for the charger */
+62
drivers/power/abx500_chargalg.c
··· 34 34 /* End-of-charge criteria counter */ 35 35 #define EOC_COND_CNT 10 36 36 37 + /* Plus margin for the low battery threshold */ 38 + #define BAT_PLUS_MARGIN (100) 39 + 37 40 #define to_abx500_chargalg_device_info(x) container_of((x), \ 38 41 struct abx500_chargalg, chargalg_psy); 39 42 ··· 86 83 STATE_HW_TEMP_PROTECT_INIT, 87 84 STATE_HW_TEMP_PROTECT, 88 85 STATE_NORMAL_INIT, 86 + STATE_USB_PP_PRE_CHARGE, 89 87 STATE_NORMAL, 90 88 STATE_WAIT_FOR_RECHARGE_INIT, 91 89 STATE_WAIT_FOR_RECHARGE, ··· 118 114 "HW_TEMP_PROTECT_INIT", 119 115 "HW_TEMP_PROTECT", 120 116 "NORMAL_INIT", 117 + "USB_PP_PRE_CHARGE", 121 118 "NORMAL", 122 119 "WAIT_FOR_RECHARGE_INIT", 123 120 "WAIT_FOR_RECHARGE", ··· 565 560 return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset); 566 561 } 567 562 563 + /** 564 + * ab8540_chargalg_usb_pp_en() - Enable/ disable USB power path 565 + * @di: pointer to the abx500_chargalg structure 566 + * @enable: power path enable/disable 567 + * 568 + * The USB power path will be enable/ disable 569 + */ 570 + static int ab8540_chargalg_usb_pp_en(struct abx500_chargalg *di, bool enable) 571 + { 572 + if (!di->usb_chg || !di->usb_chg->ops.pp_enable) 573 + return -ENXIO; 574 + 575 + return di->usb_chg->ops.pp_enable(di->usb_chg, enable); 576 + } 577 + 578 + /** 579 + * ab8540_chargalg_usb_pre_chg_en() - Enable/ disable USB pre-charge 580 + * @di: pointer to the abx500_chargalg structure 581 + * @enable: USB pre-charge enable/disable 582 + * 583 + * The USB USB pre-charge will be enable/ disable 584 + */ 585 + static int ab8540_chargalg_usb_pre_chg_en(struct abx500_chargalg *di, 586 + bool enable) 587 + { 588 + if (!di->usb_chg || !di->usb_chg->ops.pre_chg_enable) 589 + return -ENXIO; 590 + 591 + return di->usb_chg->ops.pre_chg_enable(di->usb_chg, enable); 592 + } 593 + 568 594 /** 569 595 * abx500_chargalg_update_chg_curr() - Update charger current 570 596 * @di: pointer to the abx500_chargalg structure ··· 801 765 di->batt_data.avg_curr > 0) { 802 766 if (++di->eoc_cnt >= EOC_COND_CNT) { 803 767 di->eoc_cnt = 0; 768 + if ((di->chg_info.charger_type & USB_CHG) && 769 + (di->usb_chg->power_path)) 770 + ab8540_chargalg_usb_pp_en(di, true); 804 771 di->charge_status = POWER_SUPPLY_STATUS_FULL; 805 772 di->maintenance_chg = true; 806 773 dev_dbg(di->dev, "EOC reached!\n"); ··· 1504 1465 break; 1505 1466 1506 1467 case STATE_NORMAL_INIT: 1468 + if ((di->chg_info.charger_type & USB_CHG) && 1469 + di->usb_chg->power_path) { 1470 + if (di->batt_data.volt > 1471 + (di->bm->fg_params->lowbat_threshold + 1472 + BAT_PLUS_MARGIN)) { 1473 + ab8540_chargalg_usb_pre_chg_en(di, false); 1474 + ab8540_chargalg_usb_pp_en(di, false); 1475 + } else { 1476 + ab8540_chargalg_usb_pp_en(di, true); 1477 + ab8540_chargalg_usb_pre_chg_en(di, true); 1478 + abx500_chargalg_state_to(di, 1479 + STATE_USB_PP_PRE_CHARGE); 1480 + break; 1481 + } 1482 + } 1483 + 1507 1484 abx500_chargalg_start_charging(di, 1508 1485 di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, 1509 1486 di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); ··· 1532 1477 di->maintenance_chg = false; 1533 1478 power_supply_changed(&di->chargalg_psy); 1534 1479 1480 + break; 1481 + 1482 + case STATE_USB_PP_PRE_CHARGE: 1483 + if (di->batt_data.volt > 1484 + (di->bm->fg_params->lowbat_threshold + 1485 + BAT_PLUS_MARGIN)) 1486 + abx500_chargalg_state_to(di, STATE_NORMAL_INIT); 1535 1487 break; 1536 1488 1537 1489 case STATE_NORMAL:
+1
include/linux/mfd/abx500.h
··· 267 267 bool autopower_cfg; 268 268 bool ac_enabled; 269 269 bool usb_enabled; 270 + bool usb_power_path; 270 271 bool no_maintenance; 271 272 bool capacity_scaling; 272 273 bool chg_unknown_bat;
+12
include/linux/mfd/abx500/ab8500-bm.h
··· 69 69 #define AB8500_USBCH_CTRL1_REG 0xC0 70 70 #define AB8500_USBCH_CTRL2_REG 0xC1 71 71 #define AB8500_USBCH_IPT_CRNTLVL_REG 0xC2 72 + #define AB8540_USB_PP_MODE_REG 0xC5 73 + #define AB8540_USB_PP_CHR_REG 0xC6 72 74 73 75 /* 74 76 * Gas Gauge register offsets ··· 260 258 #define AB8505_RTC_PCUT_FLAG_TIME_REG 0x15 261 259 #define AB8505_RTC_PCUT_RESTART_REG 0x16 262 260 #define AB8505_RTC_PCUT_DEBOUNCE_REG 0x17 261 + 262 + /* USB Power Path constants for ab8540 */ 263 + #define BUS_VSYS_VOL_SELECT_MASK 0x06 264 + #define BUS_VSYS_VOL_SELECT_3P6V 0x00 265 + #define BUS_VSYS_VOL_SELECT_3P325V 0x02 266 + #define BUS_VSYS_VOL_SELECT_3P9V 0x04 267 + #define BUS_VSYS_VOL_SELECT_4P3V 0x06 268 + #define BUS_POWER_PATH_MODE_ENA 0x01 269 + #define BUS_PP_PRECHG_CURRENT_MASK 0x0E 270 + #define BUS_POWER_PATH_PRECHG_ENA 0x01 263 271 264 272 /** 265 273 * struct res_to_temp - defines one point in a temp to res curve. To
+4
include/linux/mfd/abx500/ux500_chargalg.h
··· 20 20 int (*check_enable) (struct ux500_charger *, int, int); 21 21 int (*kick_wd) (struct ux500_charger *); 22 22 int (*update_curr) (struct ux500_charger *, int); 23 + int (*pp_enable) (struct ux500_charger *, bool); 24 + int (*pre_chg_enable) (struct ux500_charger *, bool); 23 25 }; 24 26 25 27 /** ··· 32 30 * @max_out_curr maximum output charger current in mA 33 31 * @enabled indicates if this charger is used or not 34 32 * @external external charger unit (pm2xxx) 33 + * @power_path USB power path support 35 34 */ 36 35 struct ux500_charger { 37 36 struct power_supply psy; ··· 42 39 int wdt_refresh; 43 40 bool enabled; 44 41 bool external; 42 + bool power_path; 45 43 }; 46 44 47 45 extern struct blocking_notifier_head charger_notifier_list;