diff options
author | Marcus Cooper <marcus.xm.cooper@stericsson.com> | 2013-01-11 08:13:04 -0500 |
---|---|---|
committer | Anton Vorontsov <anton@enomsg.org> | 2013-01-15 20:44:42 -0500 |
commit | 4b45f4a9cd4eae34b23becb686f2c2a637d844d3 (patch) | |
tree | 49ad2345837b17686313c5eb0ac806e7ed71c912 /drivers/power/ab8500_charger.c | |
parent | 377345c2be3afad0d5cd16b2340c0da876494f6d (diff) |
ab8500_charger: Adds support for legacy USB chargers
A Legacy USB charger should be handled directly by the charger
driver.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Marcus Cooper <marcus.xm.cooper@stericsson.com>
Reviewed-by: Karl KOMIEROWSKI <karl.komierowski@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Signed-off-by: Anton Vorontsov <anton@enomsg.org>
Diffstat (limited to 'drivers/power/ab8500_charger.c')
-rw-r--r-- | drivers/power/ab8500_charger.c | 79 |
1 files changed, 63 insertions, 16 deletions
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 6ba7efff81e8..d5a8bdadb49a 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c | |||
@@ -88,6 +88,9 @@ | |||
88 | /* Step up/down delay in us */ | 88 | /* Step up/down delay in us */ |
89 | #define STEP_UDELAY 1000 | 89 | #define STEP_UDELAY 1000 |
90 | 90 | ||
91 | /* Wait for enumeration before charging in ms */ | ||
92 | #define WAIT_FOR_USB_ENUMERATION 5 * 1000 | ||
93 | |||
91 | #define CHARGER_STATUS_POLL 10 /* in ms */ | 94 | #define CHARGER_STATUS_POLL 10 /* in ms */ |
92 | 95 | ||
93 | /* UsbLineStatus register - usb types */ | 96 | /* UsbLineStatus register - usb types */ |
@@ -201,6 +204,7 @@ struct ab8500_charger_usb_state { | |||
201 | * charger is enabled | 204 | * charger is enabled |
202 | * @vbat Battery voltage | 205 | * @vbat Battery voltage |
203 | * @old_vbat Previously measured battery voltage | 206 | * @old_vbat Previously measured battery voltage |
207 | * @usb_device_is_unrecognised USB device is unrecognised by the hardware | ||
204 | * @autopower Indicate if we should have automatic pwron after pwrloss | 208 | * @autopower Indicate if we should have automatic pwron after pwrloss |
205 | * @autopower_cfg platform specific power config support for "pwron after pwrloss" | 209 | * @autopower_cfg platform specific power config support for "pwron after pwrloss" |
206 | * @parent: Pointer to the struct ab8500 | 210 | * @parent: Pointer to the struct ab8500 |
@@ -219,6 +223,7 @@ struct ab8500_charger_usb_state { | |||
219 | * @check_usbchgnotok_work: Work for checking USB charger not ok status | 223 | * @check_usbchgnotok_work: Work for checking USB charger not ok status |
220 | * @kick_wd_work: Work for kicking the charger watchdog in case | 224 | * @kick_wd_work: Work for kicking the charger watchdog in case |
221 | * of ABB rev 1.* due to the watchog logic bug | 225 | * of ABB rev 1.* due to the watchog logic bug |
226 | * @attach_work: Work for checking the usb enumeration | ||
222 | * @ac_charger_attached_work: Work for checking if AC charger is still | 227 | * @ac_charger_attached_work: Work for checking if AC charger is still |
223 | * connected | 228 | * connected |
224 | * @usb_charger_attached_work: Work for checking if USB charger is still | 229 | * @usb_charger_attached_work: Work for checking if USB charger is still |
@@ -243,6 +248,7 @@ struct ab8500_charger { | |||
243 | bool vddadc_en_usb; | 248 | bool vddadc_en_usb; |
244 | int vbat; | 249 | int vbat; |
245 | int old_vbat; | 250 | int old_vbat; |
251 | bool usb_device_is_unrecognised; | ||
246 | bool autopower; | 252 | bool autopower; |
247 | bool autopower_cfg; | 253 | bool autopower_cfg; |
248 | struct ab8500 *parent; | 254 | struct ab8500 *parent; |
@@ -260,6 +266,7 @@ struct ab8500_charger { | |||
260 | struct delayed_work check_hw_failure_work; | 266 | struct delayed_work check_hw_failure_work; |
261 | struct delayed_work check_usbchgnotok_work; | 267 | struct delayed_work check_usbchgnotok_work; |
262 | struct delayed_work kick_wd_work; | 268 | struct delayed_work kick_wd_work; |
269 | struct delayed_work attach_work; | ||
263 | struct delayed_work ac_charger_attached_work; | 270 | struct delayed_work ac_charger_attached_work; |
264 | struct delayed_work usb_charger_attached_work; | 271 | struct delayed_work usb_charger_attached_work; |
265 | struct work_struct ac_work; | 272 | struct work_struct ac_work; |
@@ -597,6 +604,8 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, | |||
597 | { | 604 | { |
598 | int ret = 0; | 605 | int ret = 0; |
599 | 606 | ||
607 | di->usb_device_is_unrecognised = false; | ||
608 | |||
600 | switch (link_status) { | 609 | switch (link_status) { |
601 | case USB_STAT_STD_HOST_NC: | 610 | case USB_STAT_STD_HOST_NC: |
602 | case USB_STAT_STD_HOST_C_NS: | 611 | case USB_STAT_STD_HOST_C_NS: |
@@ -642,9 +651,15 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, | |||
642 | dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, | 651 | dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, |
643 | di->max_usb_in_curr); | 652 | di->max_usb_in_curr); |
644 | break; | 653 | break; |
654 | case USB_STAT_NOT_CONFIGURED: | ||
655 | if (di->vbus_detected) { | ||
656 | di->usb_device_is_unrecognised = true; | ||
657 | dev_dbg(di->dev, "USB Type - Legacy charger.\n"); | ||
658 | di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5; | ||
659 | break; | ||
660 | } | ||
645 | case USB_STAT_HM_IDGND: | 661 | case USB_STAT_HM_IDGND: |
646 | case USB_STAT_NOT_VALID_LINK: | 662 | case USB_STAT_NOT_VALID_LINK: |
647 | case USB_STAT_NOT_CONFIGURED: | ||
648 | dev_err(di->dev, "USB Type - Charging not allowed\n"); | 663 | dev_err(di->dev, "USB Type - Charging not allowed\n"); |
649 | di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05; | 664 | di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05; |
650 | ret = -ENXIO; | 665 | ret = -ENXIO; |
@@ -1912,6 +1927,29 @@ static void ab8500_charger_detect_usb_type_work(struct work_struct *work) | |||
1912 | } | 1927 | } |
1913 | 1928 | ||
1914 | /** | 1929 | /** |
1930 | * ab8500_charger_usb_link_attach_work() - delayd work to detect USB type | ||
1931 | * @work: pointer to the work_struct structure | ||
1932 | * | ||
1933 | * Detect the type of USB plugged | ||
1934 | */ | ||
1935 | static void ab8500_charger_usb_link_attach_work(struct work_struct *work) | ||
1936 | { | ||
1937 | struct ab8500_charger *di = | ||
1938 | container_of(work, struct ab8500_charger, attach_work.work); | ||
1939 | int ret; | ||
1940 | |||
1941 | /* Update maximum input current if USB enumeration is not detected */ | ||
1942 | if (!di->usb.charger_online) { | ||
1943 | ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr); | ||
1944 | if (ret) | ||
1945 | return; | ||
1946 | } | ||
1947 | |||
1948 | ab8500_charger_set_usb_connected(di, true); | ||
1949 | ab8500_power_supply_changed(di, &di->usb_chg.psy); | ||
1950 | } | ||
1951 | |||
1952 | /** | ||
1915 | * ab8500_charger_usb_link_status_work() - work to detect USB type | 1953 | * ab8500_charger_usb_link_status_work() - work to detect USB type |
1916 | * @work: pointer to the work_struct structure | 1954 | * @work: pointer to the work_struct structure |
1917 | * | 1955 | * |
@@ -1937,23 +1975,29 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) | |||
1937 | di->vbus_detected = 0; | 1975 | di->vbus_detected = 0; |
1938 | ab8500_charger_set_usb_connected(di, false); | 1976 | ab8500_charger_set_usb_connected(di, false); |
1939 | ab8500_power_supply_changed(di, &di->usb_chg.psy); | 1977 | ab8500_power_supply_changed(di, &di->usb_chg.psy); |
1940 | } else { | 1978 | return; |
1941 | di->vbus_detected = 1; | 1979 | } |
1942 | ret = ab8500_charger_read_usb_type(di); | ||
1943 | if (!ret) { | ||
1944 | /* Update maximum input current */ | ||
1945 | ret = ab8500_charger_set_vbus_in_curr(di, | ||
1946 | di->max_usb_in_curr); | ||
1947 | if (ret) | ||
1948 | return; | ||
1949 | 1980 | ||
1950 | ab8500_charger_set_usb_connected(di, true); | 1981 | di->vbus_detected = 1; |
1951 | ab8500_power_supply_changed(di, &di->usb_chg.psy); | 1982 | ret = ab8500_charger_read_usb_type(di); |
1952 | } else if (ret == -ENXIO) { | 1983 | if (!ret) { |
1953 | /* No valid charger type detected */ | 1984 | if (di->usb_device_is_unrecognised) { |
1954 | ab8500_charger_set_usb_connected(di, false); | 1985 | dev_dbg(di->dev, |
1955 | ab8500_power_supply_changed(di, &di->usb_chg.psy); | 1986 | "Potential Legacy Charger device. " |
1987 | "Delay work for %d msec for USB enum " | ||
1988 | "to finish", | ||
1989 | WAIT_FOR_USB_ENUMERATION); | ||
1990 | queue_delayed_work(di->charger_wq, | ||
1991 | &di->attach_work, | ||
1992 | msecs_to_jiffies(WAIT_FOR_USB_ENUMERATION)); | ||
1993 | } else { | ||
1994 | queue_delayed_work(di->charger_wq, | ||
1995 | &di->attach_work, 0); | ||
1956 | } | 1996 | } |
1997 | } else if (ret == -ENXIO) { | ||
1998 | /* No valid charger type detected */ | ||
1999 | ab8500_charger_set_usb_connected(di, false); | ||
2000 | ab8500_power_supply_changed(di, &di->usb_chg.psy); | ||
1957 | } | 2001 | } |
1958 | } | 2002 | } |
1959 | 2003 | ||
@@ -2911,6 +2955,9 @@ static int ab8500_charger_probe(struct platform_device *pdev) | |||
2911 | INIT_DEFERRABLE_WORK(&di->check_vbat_work, | 2955 | INIT_DEFERRABLE_WORK(&di->check_vbat_work, |
2912 | ab8500_charger_check_vbat_work); | 2956 | ab8500_charger_check_vbat_work); |
2913 | 2957 | ||
2958 | INIT_DELAYED_WORK(&di->attach_work, | ||
2959 | ab8500_charger_usb_link_attach_work); | ||
2960 | |||
2914 | /* Init work for charger detection */ | 2961 | /* Init work for charger detection */ |
2915 | INIT_WORK(&di->usb_link_status_work, | 2962 | INIT_WORK(&di->usb_link_status_work, |
2916 | ab8500_charger_usb_link_status_work); | 2963 | ab8500_charger_usb_link_status_work); |