diff options
author | Lee Jones <lee.jones@linaro.org> | 2013-02-13 06:39:19 -0500 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2013-03-06 23:35:40 -0500 |
commit | 8891716e24d7b0f4b1c3b4fdff641bcb1fb282c4 (patch) | |
tree | 4f5fbc4035d59faab6d6defee2e6f51f2bde021b /drivers/power/ab8500_charger.c | |
parent | 789ca7b46877f29b2aaa94401319c50be35b184f (diff) |
ab8500-bm: Charge only mode fixes for the ab9540
Fix for charging not getting enabled in charge only mode by
external charger.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/power/ab8500_charger.c')
-rw-r--r-- | drivers/power/ab8500_charger.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 3eb23cf9ff47..f1d712308b02 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/notifier.h> | ||
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
20 | #include <linux/power_supply.h> | 21 | #include <linux/power_supply.h> |
@@ -97,6 +98,10 @@ | |||
97 | #define AB8500_SW_CONTROL_FALLBACK 0x03 | 98 | #define AB8500_SW_CONTROL_FALLBACK 0x03 |
98 | /* Wait for enumeration before charing in us */ | 99 | /* Wait for enumeration before charing in us */ |
99 | #define WAIT_ACA_RID_ENUMERATION (5 * 1000) | 100 | #define WAIT_ACA_RID_ENUMERATION (5 * 1000) |
101 | /*External charger control*/ | ||
102 | #define AB8500_SYS_CHARGER_CONTROL_REG 0x52 | ||
103 | #define EXTERNAL_CHARGER_DISABLE_REG_VAL 0x03 | ||
104 | #define EXTERNAL_CHARGER_ENABLE_REG_VAL 0x07 | ||
100 | 105 | ||
101 | /* UsbLineStatus register - usb types */ | 106 | /* UsbLineStatus register - usb types */ |
102 | enum ab8500_charger_link_status { | 107 | enum ab8500_charger_link_status { |
@@ -1678,6 +1683,29 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, | |||
1678 | return ret; | 1683 | return ret; |
1679 | } | 1684 | } |
1680 | 1685 | ||
1686 | static int ab8500_external_charger_prepare(struct notifier_block *charger_nb, | ||
1687 | unsigned long event, void *data) | ||
1688 | { | ||
1689 | int ret; | ||
1690 | struct device *dev = data; | ||
1691 | /*Toggle External charger control pin*/ | ||
1692 | ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, | ||
1693 | AB8500_SYS_CHARGER_CONTROL_REG, | ||
1694 | EXTERNAL_CHARGER_DISABLE_REG_VAL); | ||
1695 | if (ret < 0) { | ||
1696 | dev_err(dev, "write reg failed %d\n", ret); | ||
1697 | goto out; | ||
1698 | } | ||
1699 | ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, | ||
1700 | AB8500_SYS_CHARGER_CONTROL_REG, | ||
1701 | EXTERNAL_CHARGER_ENABLE_REG_VAL); | ||
1702 | if (ret < 0) | ||
1703 | dev_err(dev, "Write reg failed %d\n", ret); | ||
1704 | |||
1705 | out: | ||
1706 | return ret; | ||
1707 | } | ||
1708 | |||
1681 | /** | 1709 | /** |
1682 | * ab8500_charger_usb_check_enable() - enable usb charging | 1710 | * ab8500_charger_usb_check_enable() - enable usb charging |
1683 | * @charger: pointer to the ux500_charger structure | 1711 | * @charger: pointer to the ux500_charger structure |
@@ -3221,6 +3249,10 @@ static int ab8500_charger_suspend(struct platform_device *pdev, | |||
3221 | #define ab8500_charger_resume NULL | 3249 | #define ab8500_charger_resume NULL |
3222 | #endif | 3250 | #endif |
3223 | 3251 | ||
3252 | static struct notifier_block charger_nb = { | ||
3253 | .notifier_call = ab8500_external_charger_prepare, | ||
3254 | }; | ||
3255 | |||
3224 | static int ab8500_charger_remove(struct platform_device *pdev) | 3256 | static int ab8500_charger_remove(struct platform_device *pdev) |
3225 | { | 3257 | { |
3226 | struct ab8500_charger *di = platform_get_drvdata(pdev); | 3258 | struct ab8500_charger *di = platform_get_drvdata(pdev); |
@@ -3250,6 +3282,11 @@ static int ab8500_charger_remove(struct platform_device *pdev) | |||
3250 | /* Delete the work queue */ | 3282 | /* Delete the work queue */ |
3251 | destroy_workqueue(di->charger_wq); | 3283 | destroy_workqueue(di->charger_wq); |
3252 | 3284 | ||
3285 | /* Unregister external charger enable notifier */ | ||
3286 | if (!di->ac_chg.enabled) | ||
3287 | blocking_notifier_chain_unregister( | ||
3288 | &charger_notifier_list, &charger_nb); | ||
3289 | |||
3253 | flush_scheduled_work(); | 3290 | flush_scheduled_work(); |
3254 | if (di->usb_chg.enabled) | 3291 | if (di->usb_chg.enabled) |
3255 | power_supply_unregister(&di->usb_chg.psy); | 3292 | power_supply_unregister(&di->usb_chg.psy); |
@@ -3331,6 +3368,11 @@ static int ab8500_charger_probe(struct platform_device *pdev) | |||
3331 | di->ac_chg.enabled = di->bm->ac_enabled; | 3368 | di->ac_chg.enabled = di->bm->ac_enabled; |
3332 | di->ac_chg.external = false; | 3369 | di->ac_chg.external = false; |
3333 | 3370 | ||
3371 | /*notifier for external charger enabling*/ | ||
3372 | if (!di->ac_chg.enabled) | ||
3373 | blocking_notifier_chain_register( | ||
3374 | &charger_notifier_list, &charger_nb); | ||
3375 | |||
3334 | /* USB supply */ | 3376 | /* USB supply */ |
3335 | /* power_supply base class */ | 3377 | /* power_supply base class */ |
3336 | di->usb_chg.psy.name = "ab8500_usb"; | 3378 | di->usb_chg.psy.name = "ab8500_usb"; |