diff options
author | Henrik Sölver <henrik.solver@stericsson.com> | 2012-04-17 09:51:01 -0400 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2013-01-23 06:33:03 -0500 |
commit | ff38090aa2e1423e130cc72e790145bad7de8215 (patch) | |
tree | 3ab24aed90dd12a9a323a8c0eee95680f1473421 /drivers/power | |
parent | 01ec8c5423901c4fe8d97f786ed9a0c31215b53a (diff) |
ab8500-charger: AB workaround for invalid charger
AB8500 refuses to start charging when some types of non standard
chargers are connected. This change force the AB to start charging.
Signed-off-by: Henrik Sölver <henrik.solver@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Yvan FILLION <yvan.fillion@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Tested-by: Yvan FILLION <yvan.fillion@stericsson.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/ab8500_charger.c | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 43ec82ba4275..4c66172aaa64 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c | |||
@@ -207,6 +207,7 @@ struct ab8500_charger_usb_state { | |||
207 | * @usb_device_is_unrecognised USB device is unrecognised by the hardware | 207 | * @usb_device_is_unrecognised USB device is unrecognised by the hardware |
208 | * @autopower Indicate if we should have automatic pwron after pwrloss | 208 | * @autopower Indicate if we should have automatic pwron after pwrloss |
209 | * @autopower_cfg platform specific power config support for "pwron after pwrloss" | 209 | * @autopower_cfg platform specific power config support for "pwron after pwrloss" |
210 | * @invalid_charger_detect_state State when forcing AB to use invalid charger | ||
210 | * @parent: Pointer to the struct ab8500 | 211 | * @parent: Pointer to the struct ab8500 |
211 | * @gpadc: Pointer to the struct gpadc | 212 | * @gpadc: Pointer to the struct gpadc |
212 | * @bm: Platform specific battery management information | 213 | * @bm: Platform specific battery management information |
@@ -251,6 +252,7 @@ struct ab8500_charger { | |||
251 | bool usb_device_is_unrecognised; | 252 | bool usb_device_is_unrecognised; |
252 | bool autopower; | 253 | bool autopower; |
253 | bool autopower_cfg; | 254 | bool autopower_cfg; |
255 | int invalid_charger_detect_state; | ||
254 | struct ab8500 *parent; | 256 | struct ab8500 *parent; |
255 | struct ab8500_gpadc *gpadc; | 257 | struct ab8500_gpadc *gpadc; |
256 | struct abx500_bm_data *bm; | 258 | struct abx500_bm_data *bm; |
@@ -659,7 +661,6 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, | |||
659 | break; | 661 | break; |
660 | } | 662 | } |
661 | case USB_STAT_HM_IDGND: | 663 | case USB_STAT_HM_IDGND: |
662 | case USB_STAT_NOT_VALID_LINK: | ||
663 | dev_err(di->dev, "USB Type - Charging not allowed\n"); | 664 | dev_err(di->dev, "USB Type - Charging not allowed\n"); |
664 | di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05; | 665 | di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05; |
665 | ret = -ENXIO; | 666 | ret = -ENXIO; |
@@ -688,6 +689,9 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, | |||
688 | di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; | 689 | di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; |
689 | dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, | 690 | dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, |
690 | di->max_usb_in_curr); | 691 | di->max_usb_in_curr); |
692 | case USB_STAT_NOT_VALID_LINK: | ||
693 | dev_err(di->dev, "USB Type invalid - try charging anyway\n"); | ||
694 | di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5; | ||
691 | break; | 695 | break; |
692 | 696 | ||
693 | default: | 697 | default: |
@@ -1957,7 +1961,9 @@ static void ab8500_charger_usb_link_attach_work(struct work_struct *work) | |||
1957 | */ | 1961 | */ |
1958 | static void ab8500_charger_usb_link_status_work(struct work_struct *work) | 1962 | static void ab8500_charger_usb_link_status_work(struct work_struct *work) |
1959 | { | 1963 | { |
1964 | int detected_chargers; | ||
1960 | int ret; | 1965 | int ret; |
1966 | u8 val; | ||
1961 | 1967 | ||
1962 | struct ab8500_charger *di = container_of(work, | 1968 | struct ab8500_charger *di = container_of(work, |
1963 | struct ab8500_charger, usb_link_status_work); | 1969 | struct ab8500_charger, usb_link_status_work); |
@@ -1967,11 +1973,55 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) | |||
1967 | * synchronously, we have the check if is | 1973 | * synchronously, we have the check if is |
1968 | * connected by reading the status register | 1974 | * connected by reading the status register |
1969 | */ | 1975 | */ |
1970 | ret = ab8500_charger_detect_chargers(di); | 1976 | detected_chargers = ab8500_charger_detect_chargers(di); |
1971 | if (ret < 0) | 1977 | if (detected_chargers < 0) |
1972 | return; | 1978 | return; |
1973 | 1979 | ||
1974 | if (!(ret & USB_PW_CONN)) { | 1980 | /* |
1981 | * Some chargers that breaks the USB spec is | ||
1982 | * identified as invalid by AB8500 and it refuse | ||
1983 | * to start the charging process. but by jumping | ||
1984 | * thru a few hoops it can be forced to start. | ||
1985 | */ | ||
1986 | ret = abx500_get_register_interruptible(di->dev, AB8500_USB, | ||
1987 | AB8500_USB_LINE_STAT_REG, &val); | ||
1988 | if (ret >= 0) | ||
1989 | dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val); | ||
1990 | else | ||
1991 | dev_dbg(di->dev, "Error reading USB link status\n"); | ||
1992 | |||
1993 | if (detected_chargers & USB_PW_CONN) { | ||
1994 | if (((val & AB8500_USB_LINK_STATUS) >> 3) == USB_STAT_NOT_VALID_LINK && | ||
1995 | di->invalid_charger_detect_state == 0) { | ||
1996 | dev_dbg(di->dev, "Invalid charger detected, state= 0\n"); | ||
1997 | /*Enable charger*/ | ||
1998 | abx500_mask_and_set_register_interruptible(di->dev, | ||
1999 | AB8500_CHARGER, AB8500_USBCH_CTRL1_REG, 0x01, 0x01); | ||
2000 | /*Enable charger detection*/ | ||
2001 | abx500_mask_and_set_register_interruptible(di->dev, AB8500_USB, | ||
2002 | AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x01); | ||
2003 | di->invalid_charger_detect_state = 1; | ||
2004 | /*exit and wait for new link status interrupt.*/ | ||
2005 | return; | ||
2006 | |||
2007 | } | ||
2008 | if (di->invalid_charger_detect_state == 1) { | ||
2009 | dev_dbg(di->dev, "Invalid charger detected, state= 1\n"); | ||
2010 | /*Stop charger detection*/ | ||
2011 | abx500_mask_and_set_register_interruptible(di->dev, AB8500_USB, | ||
2012 | AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x00); | ||
2013 | /*Check link status*/ | ||
2014 | ret = abx500_get_register_interruptible(di->dev, AB8500_USB, | ||
2015 | AB8500_USB_LINE_STAT_REG, &val); | ||
2016 | dev_dbg(di->dev, "USB link status= 0x%02x\n", | ||
2017 | (val & AB8500_USB_LINK_STATUS) >> 3); | ||
2018 | di->invalid_charger_detect_state = 2; | ||
2019 | } | ||
2020 | } else { | ||
2021 | di->invalid_charger_detect_state = 0; | ||
2022 | } | ||
2023 | |||
2024 | if (!(detected_chargers & USB_PW_CONN)) { | ||
1975 | di->vbus_detected = 0; | 2025 | di->vbus_detected = 0; |
1976 | ab8500_charger_set_usb_connected(di, false); | 2026 | ab8500_charger_set_usb_connected(di, false); |
1977 | ab8500_power_supply_changed(di, &di->usb_chg.psy); | 2027 | ab8500_power_supply_changed(di, &di->usb_chg.psy); |
@@ -2884,6 +2934,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) | |||
2884 | spin_lock_init(&di->usb_state.usb_lock); | 2934 | spin_lock_init(&di->usb_state.usb_lock); |
2885 | 2935 | ||
2886 | di->autopower = false; | 2936 | di->autopower = false; |
2937 | di->invalid_charger_detect_state = 0; | ||
2887 | 2938 | ||
2888 | /* AC supply */ | 2939 | /* AC supply */ |
2889 | /* power_supply base class */ | 2940 | /* power_supply base class */ |