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 | |
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>
-rw-r--r-- | drivers/power/ab8500_charger.c | 42 | ||||
-rw-r--r-- | drivers/power/abx500_chargalg.c | 14 | ||||
-rw-r--r-- | drivers/power/pm2301_charger.c | 7 | ||||
-rw-r--r-- | include/linux/mfd/abx500/ux500_chargalg.h | 2 |
4 files changed, 65 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"; |
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 8ab65a3a8190..a876976678ab 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/mfd/abx500.h> | 26 | #include <linux/mfd/abx500.h> |
27 | #include <linux/mfd/abx500/ux500_chargalg.h> | 27 | #include <linux/mfd/abx500/ux500_chargalg.h> |
28 | #include <linux/mfd/abx500/ab8500-bm.h> | 28 | #include <linux/mfd/abx500/ab8500-bm.h> |
29 | #include <linux/notifier.h> | ||
29 | 30 | ||
30 | /* Watchdog kick interval */ | 31 | /* Watchdog kick interval */ |
31 | #define CHG_WD_INTERVAL (6 * HZ) | 32 | #define CHG_WD_INTERVAL (6 * HZ) |
@@ -243,6 +244,9 @@ struct abx500_chargalg { | |||
243 | struct kobject chargalg_kobject; | 244 | struct kobject chargalg_kobject; |
244 | }; | 245 | }; |
245 | 246 | ||
247 | /*External charger prepare notifier*/ | ||
248 | BLOCKING_NOTIFIER_HEAD(charger_notifier_list); | ||
249 | |||
246 | /* Main battery properties */ | 250 | /* Main battery properties */ |
247 | static enum power_supply_property abx500_chargalg_props[] = { | 251 | static enum power_supply_property abx500_chargalg_props[] = { |
248 | POWER_SUPPLY_PROP_STATUS, | 252 | POWER_SUPPLY_PROP_STATUS, |
@@ -503,6 +507,8 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) | |||
503 | static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable, | 507 | static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable, |
504 | int vset, int iset) | 508 | int vset, int iset) |
505 | { | 509 | { |
510 | static int abx500_chargalg_ex_ac_enable_toggle; | ||
511 | |||
506 | if (!di->ac_chg || !di->ac_chg->ops.enable) | 512 | if (!di->ac_chg || !di->ac_chg->ops.enable) |
507 | return -ENXIO; | 513 | return -ENXIO; |
508 | 514 | ||
@@ -515,6 +521,14 @@ static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable, | |||
515 | di->chg_info.ac_iset = iset; | 521 | di->chg_info.ac_iset = iset; |
516 | di->chg_info.ac_vset = vset; | 522 | di->chg_info.ac_vset = vset; |
517 | 523 | ||
524 | /* Enable external charger */ | ||
525 | if (enable && di->ac_chg->external && | ||
526 | !abx500_chargalg_ex_ac_enable_toggle) { | ||
527 | blocking_notifier_call_chain(&charger_notifier_list, | ||
528 | 0, di->dev); | ||
529 | abx500_chargalg_ex_ac_enable_toggle++; | ||
530 | } | ||
531 | |||
518 | return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset); | 532 | return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset); |
519 | } | 533 | } |
520 | 534 | ||
diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c index b560fa5ac4e7..45ef3b9de6b9 100644 --- a/drivers/power/pm2301_charger.c +++ b/drivers/power/pm2301_charger.c | |||
@@ -1059,6 +1059,13 @@ static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client, | |||
1059 | ret = pm2xxx_charger_detection(pm2, &val); | 1059 | ret = pm2xxx_charger_detection(pm2, &val); |
1060 | 1060 | ||
1061 | if ((ret == 0) && val) { | 1061 | if ((ret == 0) && val) { |
1062 | /* | ||
1063 | * When boot is due to AC charger plug-in, | ||
1064 | * read interrupt registers | ||
1065 | */ | ||
1066 | pm2xxx_reg_read(pm2, PM2XXX_REG_INT1, &val); | ||
1067 | pm2xxx_reg_read(pm2, PM2XXX_REG_INT2, &val); | ||
1068 | pm2xxx_reg_read(pm2, PM2XXX_REG_INT4, &val); | ||
1062 | pm2->ac.charger_connected = 1; | 1069 | pm2->ac.charger_connected = 1; |
1063 | pm2->ac_conn = true; | 1070 | pm2->ac_conn = true; |
1064 | power_supply_changed(&pm2->ac_chg.psy); | 1071 | power_supply_changed(&pm2->ac_chg.psy); |
diff --git a/include/linux/mfd/abx500/ux500_chargalg.h b/include/linux/mfd/abx500/ux500_chargalg.h index 110d12f09548..fa831f1e8cf8 100644 --- a/include/linux/mfd/abx500/ux500_chargalg.h +++ b/include/linux/mfd/abx500/ux500_chargalg.h | |||
@@ -41,4 +41,6 @@ struct ux500_charger { | |||
41 | bool external; | 41 | bool external; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | extern struct blocking_notifier_head charger_notifier_list; | ||
45 | |||
44 | #endif | 46 | #endif |