aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2013-02-14 07:39:15 -0500
committerLee Jones <lee.jones@linaro.org>2013-03-06 23:35:46 -0500
commitdb43e6c473b57d4e7a55c4bd6edef71f40f13eae (patch)
tree0fbe4762c914ba15898cf8bcb9bd8e531fe8fc31
parent405fea1c6691eb8259f2ca879c9348a4cf5d898d (diff)
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>
-rw-r--r--drivers/power/ab8500_charger.c81
-rw-r--r--drivers/power/abx500_chargalg.c62
-rw-r--r--include/linux/mfd/abx500.h1
-rw-r--r--include/linux/mfd/abx500/ab8500-bm.h12
-rw-r--r--include/linux/mfd/abx500/ux500_chargalg.h4
5 files changed, 160 insertions, 0 deletions
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 6fea4fdf8701..f249a65b02e1 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -1925,6 +1925,67 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger,
1925 return ret; 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 */
1936static 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 */
1967static 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
1928static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data) 1989static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data)
1929{ 1990{
1930 struct power_supply *psy; 1991 struct power_supply *psy;
@@ -3201,6 +3262,23 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
3201 if (ret < 0) 3262 if (ret < 0)
3202 dev_err(di->dev, "%s mask and set failed\n", __func__); 3263 dev_err(di->dev, "%s mask and set failed\n", __func__);
3203 3264
3265 if (is_ab8540(di->parent)) {
3266 ret = abx500_mask_and_set_register_interruptible(di->dev,
3267 AB8500_CHARGER, AB8540_USB_PP_MODE_REG,
3268 BUS_VSYS_VOL_SELECT_MASK, BUS_VSYS_VOL_SELECT_3P6V);
3269 if (ret) {
3270 dev_err(di->dev, "failed to setup usb power path vsys voltage\n");
3271 goto out;
3272 }
3273 ret = abx500_mask_and_set_register_interruptible(di->dev,
3274 AB8500_CHARGER, AB8540_USB_PP_CHR_REG,
3275 BUS_PP_PRECHG_CURRENT_MASK, 0);
3276 if (ret) {
3277 dev_err(di->dev, "failed to setup usb power path prechage current\n");
3278 goto out;
3279 }
3280 }
3281
3204out: 3282out:
3205 return ret; 3283 return ret;
3206} 3284}
@@ -3484,6 +3562,8 @@ static int ab8500_charger_probe(struct platform_device *pdev)
3484 di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable; 3562 di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable;
3485 di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 3563 di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
3486 di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; 3564 di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current;
3565 di->usb_chg.ops.pp_enable = &ab8540_charger_power_path_enable;
3566 di->usb_chg.ops.pre_chg_enable = &ab8540_charger_usb_pre_chg_enable;
3487 di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ 3567 di->usb_chg.max_out_volt = ab8500_charger_voltage_map[
3488 ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; 3568 ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
3489 di->usb_chg.max_out_curr = ab8500_charger_current_map[ 3569 di->usb_chg.max_out_curr = ab8500_charger_current_map[
@@ -3491,6 +3571,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
3491 di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; 3571 di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
3492 di->usb_chg.enabled = di->bm->usb_enabled; 3572 di->usb_chg.enabled = di->bm->usb_enabled;
3493 di->usb_chg.external = false; 3573 di->usb_chg.external = false;
3574 di->usb_chg.power_path = di->bm->usb_power_path;
3494 di->usb_state.usb_current = -1; 3575 di->usb_state.usb_current = -1;
3495 3576
3496 /* Create a work queue for the charger */ 3577 /* Create a work queue for the charger */
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 @@
34/* End-of-charge criteria counter */ 34/* End-of-charge criteria counter */
35#define EOC_COND_CNT 10 35#define EOC_COND_CNT 10
36 36
37/* Plus margin for the low battery threshold */
38#define BAT_PLUS_MARGIN (100)
39
37#define to_abx500_chargalg_device_info(x) container_of((x), \ 40#define to_abx500_chargalg_device_info(x) container_of((x), \
38 struct abx500_chargalg, chargalg_psy); 41 struct abx500_chargalg, chargalg_psy);
39 42
@@ -83,6 +86,7 @@ enum abx500_chargalg_states {
83 STATE_HW_TEMP_PROTECT_INIT, 86 STATE_HW_TEMP_PROTECT_INIT,
84 STATE_HW_TEMP_PROTECT, 87 STATE_HW_TEMP_PROTECT,
85 STATE_NORMAL_INIT, 88 STATE_NORMAL_INIT,
89 STATE_USB_PP_PRE_CHARGE,
86 STATE_NORMAL, 90 STATE_NORMAL,
87 STATE_WAIT_FOR_RECHARGE_INIT, 91 STATE_WAIT_FOR_RECHARGE_INIT,
88 STATE_WAIT_FOR_RECHARGE, 92 STATE_WAIT_FOR_RECHARGE,
@@ -114,6 +118,7 @@ static const char *states[] = {
114 "HW_TEMP_PROTECT_INIT", 118 "HW_TEMP_PROTECT_INIT",
115 "HW_TEMP_PROTECT", 119 "HW_TEMP_PROTECT",
116 "NORMAL_INIT", 120 "NORMAL_INIT",
121 "USB_PP_PRE_CHARGE",
117 "NORMAL", 122 "NORMAL",
118 "WAIT_FOR_RECHARGE_INIT", 123 "WAIT_FOR_RECHARGE_INIT",
119 "WAIT_FOR_RECHARGE", 124 "WAIT_FOR_RECHARGE",
@@ -560,6 +565,37 @@ static int abx500_chargalg_usb_en(struct abx500_chargalg *di, int enable,
560 return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset); 565 return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset);
561} 566}
562 567
568 /**
569 * ab8540_chargalg_usb_pp_en() - Enable/ disable USB power path
570 * @di: pointer to the abx500_chargalg structure
571 * @enable: power path enable/disable
572 *
573 * The USB power path will be enable/ disable
574 */
575static int ab8540_chargalg_usb_pp_en(struct abx500_chargalg *di, bool enable)
576{
577 if (!di->usb_chg || !di->usb_chg->ops.pp_enable)
578 return -ENXIO;
579
580 return di->usb_chg->ops.pp_enable(di->usb_chg, enable);
581}
582
583/**
584 * ab8540_chargalg_usb_pre_chg_en() - Enable/ disable USB pre-charge
585 * @di: pointer to the abx500_chargalg structure
586 * @enable: USB pre-charge enable/disable
587 *
588 * The USB USB pre-charge will be enable/ disable
589 */
590static int ab8540_chargalg_usb_pre_chg_en(struct abx500_chargalg *di,
591 bool enable)
592{
593 if (!di->usb_chg || !di->usb_chg->ops.pre_chg_enable)
594 return -ENXIO;
595
596 return di->usb_chg->ops.pre_chg_enable(di->usb_chg, enable);
597}
598
563/** 599/**
564 * abx500_chargalg_update_chg_curr() - Update charger current 600 * abx500_chargalg_update_chg_curr() - Update charger current
565 * @di: pointer to the abx500_chargalg structure 601 * @di: pointer to the abx500_chargalg structure
@@ -765,6 +801,9 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di)
765 di->batt_data.avg_curr > 0) { 801 di->batt_data.avg_curr > 0) {
766 if (++di->eoc_cnt >= EOC_COND_CNT) { 802 if (++di->eoc_cnt >= EOC_COND_CNT) {
767 di->eoc_cnt = 0; 803 di->eoc_cnt = 0;
804 if ((di->chg_info.charger_type & USB_CHG) &&
805 (di->usb_chg->power_path))
806 ab8540_chargalg_usb_pp_en(di, true);
768 di->charge_status = POWER_SUPPLY_STATUS_FULL; 807 di->charge_status = POWER_SUPPLY_STATUS_FULL;
769 di->maintenance_chg = true; 808 di->maintenance_chg = true;
770 dev_dbg(di->dev, "EOC reached!\n"); 809 dev_dbg(di->dev, "EOC reached!\n");
@@ -1465,6 +1504,22 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
1465 break; 1504 break;
1466 1505
1467 case STATE_NORMAL_INIT: 1506 case STATE_NORMAL_INIT:
1507 if ((di->chg_info.charger_type & USB_CHG) &&
1508 di->usb_chg->power_path) {
1509 if (di->batt_data.volt >
1510 (di->bm->fg_params->lowbat_threshold +
1511 BAT_PLUS_MARGIN)) {
1512 ab8540_chargalg_usb_pre_chg_en(di, false);
1513 ab8540_chargalg_usb_pp_en(di, false);
1514 } else {
1515 ab8540_chargalg_usb_pp_en(di, true);
1516 ab8540_chargalg_usb_pre_chg_en(di, true);
1517 abx500_chargalg_state_to(di,
1518 STATE_USB_PP_PRE_CHARGE);
1519 break;
1520 }
1521 }
1522
1468 abx500_chargalg_start_charging(di, 1523 abx500_chargalg_start_charging(di,
1469 di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, 1524 di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
1470 di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); 1525 di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
@@ -1479,6 +1534,13 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
1479 1534
1480 break; 1535 break;
1481 1536
1537 case STATE_USB_PP_PRE_CHARGE:
1538 if (di->batt_data.volt >
1539 (di->bm->fg_params->lowbat_threshold +
1540 BAT_PLUS_MARGIN))
1541 abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
1542 break;
1543
1482 case STATE_NORMAL: 1544 case STATE_NORMAL:
1483 handle_maxim_chg_curr(di); 1545 handle_maxim_chg_curr(di);
1484 if (di->charge_status == POWER_SUPPLY_STATUS_FULL && 1546 if (di->charge_status == POWER_SUPPLY_STATUS_FULL &&
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 188aedc322c2..cd71d8eadf50 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -267,6 +267,7 @@ struct abx500_bm_data {
267 bool autopower_cfg; 267 bool autopower_cfg;
268 bool ac_enabled; 268 bool ac_enabled;
269 bool usb_enabled; 269 bool usb_enabled;
270 bool usb_power_path;
270 bool no_maintenance; 271 bool no_maintenance;
271 bool capacity_scaling; 272 bool capacity_scaling;
272 bool chg_unknown_bat; 273 bool chg_unknown_bat;
diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h
index a73e05a0441b..0ebf0c5d1f88 100644
--- a/include/linux/mfd/abx500/ab8500-bm.h
+++ b/include/linux/mfd/abx500/ab8500-bm.h
@@ -69,6 +69,8 @@
69#define AB8500_USBCH_CTRL1_REG 0xC0 69#define AB8500_USBCH_CTRL1_REG 0xC0
70#define AB8500_USBCH_CTRL2_REG 0xC1 70#define AB8500_USBCH_CTRL2_REG 0xC1
71#define AB8500_USBCH_IPT_CRNTLVL_REG 0xC2 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 * Gas Gauge register offsets 76 * Gas Gauge register offsets
@@ -259,6 +261,16 @@ enum bup_vch_sel {
259#define AB8505_RTC_PCUT_RESTART_REG 0x16 261#define AB8505_RTC_PCUT_RESTART_REG 0x16
260#define AB8505_RTC_PCUT_DEBOUNCE_REG 0x17 262#define AB8505_RTC_PCUT_DEBOUNCE_REG 0x17
261 263
264/* USB Power Path constants for ab8540 */
265#define BUS_VSYS_VOL_SELECT_MASK 0x06
266#define BUS_VSYS_VOL_SELECT_3P6V 0x00
267#define BUS_VSYS_VOL_SELECT_3P325V 0x02
268#define BUS_VSYS_VOL_SELECT_3P9V 0x04
269#define BUS_VSYS_VOL_SELECT_4P3V 0x06
270#define BUS_POWER_PATH_MODE_ENA 0x01
271#define BUS_PP_PRECHG_CURRENT_MASK 0x0E
272#define BUS_POWER_PATH_PRECHG_ENA 0x01
273
262/** 274/**
263 * struct res_to_temp - defines one point in a temp to res curve. To 275 * struct res_to_temp - defines one point in a temp to res curve. To
264 * be used in battery packs that combines the identification resistor with a 276 * be used in battery packs that combines the identification resistor with a
diff --git a/include/linux/mfd/abx500/ux500_chargalg.h b/include/linux/mfd/abx500/ux500_chargalg.h
index fa831f1e8cf8..234c99143bf7 100644
--- a/include/linux/mfd/abx500/ux500_chargalg.h
+++ b/include/linux/mfd/abx500/ux500_chargalg.h
@@ -20,6 +20,8 @@ struct ux500_charger_ops {
20 int (*check_enable) (struct ux500_charger *, int, int); 20 int (*check_enable) (struct ux500_charger *, int, int);
21 int (*kick_wd) (struct ux500_charger *); 21 int (*kick_wd) (struct ux500_charger *);
22 int (*update_curr) (struct ux500_charger *, int); 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/**
@@ -30,6 +32,7 @@ struct ux500_charger_ops {
30 * @max_out_curr maximum output charger current in mA 32 * @max_out_curr maximum output charger current in mA
31 * @enabled indicates if this charger is used or not 33 * @enabled indicates if this charger is used or not
32 * @external external charger unit (pm2xxx) 34 * @external external charger unit (pm2xxx)
35 * @power_path USB power path support
33 */ 36 */
34struct ux500_charger { 37struct ux500_charger {
35 struct power_supply psy; 38 struct power_supply psy;
@@ -39,6 +42,7 @@ struct ux500_charger {
39 int wdt_refresh; 42 int wdt_refresh;
40 bool enabled; 43 bool enabled;
41 bool external; 44 bool external;
45 bool power_path;
42}; 46};
43 47
44extern struct blocking_notifier_head charger_notifier_list; 48extern struct blocking_notifier_head charger_notifier_list;