diff options
-rw-r--r-- | drivers/power/ab8500_charger.c | 81 | ||||
-rw-r--r-- | drivers/power/abx500_chargalg.c | 62 | ||||
-rw-r--r-- | include/linux/mfd/abx500.h | 1 | ||||
-rw-r--r-- | include/linux/mfd/abx500/ab8500-bm.h | 12 | ||||
-rw-r--r-- | include/linux/mfd/abx500/ux500_chargalg.h | 4 |
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 | */ | ||
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 | static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data) | 1989 | static 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 | |||
3204 | out: | 3282 | out: |
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 | */ | ||
575 | static 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 | */ | ||
590 | static 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 | */ |
34 | struct ux500_charger { | 37 | struct 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 | ||
44 | extern struct blocking_notifier_head charger_notifier_list; | 48 | extern struct blocking_notifier_head charger_notifier_list; |