diff options
author | Chanwoo Choi <cw00.choi@samsung.com> | 2012-07-12 02:03:25 -0400 |
---|---|---|
committer | Anton Vorontsov <anton.vorontsov@linaro.org> | 2012-07-13 21:31:13 -0400 |
commit | bee737bccb03ebd27f2d52706e9aed2fa2c8dcc4 (patch) | |
tree | bf652913262e9e0504324c090b5893c58c936396 /drivers/power/charger-manager.c | |
parent | 85a392d47cac8fa9258c5609a7b02adade961076 (diff) |
charger-manager: Use EXTCON Subsystem to detect charger cables for charging
This patch support that charger-manager use EXTCON(External Connector)
Subsystem to detect the state of charger cables for enabling or disabling
charger(regulator) and select the charger cable for charging among
a number of external cable according to policy of H/W board.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Diffstat (limited to 'drivers/power/charger-manager.c')
-rw-r--r-- | drivers/power/charger-manager.c | 137 |
1 files changed, 121 insertions, 16 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 86935ec18954..d1e99e7957d2 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c | |||
@@ -271,16 +271,13 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
271 | if (enable) { | 271 | if (enable) { |
272 | if (cm->emergency_stop) | 272 | if (cm->emergency_stop) |
273 | return -EAGAIN; | 273 | return -EAGAIN; |
274 | err = regulator_bulk_enable(desc->num_charger_regulators, | 274 | for (i = 0 ; i < desc->num_charger_regulators ; i++) |
275 | desc->charger_regulators); | 275 | regulator_enable(desc->charger_regulators[i].consumer); |
276 | } else { | 276 | } else { |
277 | /* | 277 | /* |
278 | * Abnormal battery state - Stop charging forcibly, | 278 | * Abnormal battery state - Stop charging forcibly, |
279 | * even if charger was enabled at the other places | 279 | * even if charger was enabled at the other places |
280 | */ | 280 | */ |
281 | err = regulator_bulk_disable(desc->num_charger_regulators, | ||
282 | desc->charger_regulators); | ||
283 | |||
284 | for (i = 0; i < desc->num_charger_regulators; i++) { | 281 | for (i = 0; i < desc->num_charger_regulators; i++) { |
285 | if (regulator_is_enabled( | 282 | if (regulator_is_enabled( |
286 | desc->charger_regulators[i].consumer)) { | 283 | desc->charger_regulators[i].consumer)) { |
@@ -288,7 +285,7 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
288 | desc->charger_regulators[i].consumer); | 285 | desc->charger_regulators[i].consumer); |
289 | dev_warn(cm->dev, | 286 | dev_warn(cm->dev, |
290 | "Disable regulator(%s) forcibly.\n", | 287 | "Disable regulator(%s) forcibly.\n", |
291 | desc->charger_regulators[i].supply); | 288 | desc->charger_regulators[i].regulator_name); |
292 | } | 289 | } |
293 | } | 290 | } |
294 | } | 291 | } |
@@ -994,11 +991,77 @@ int setup_charger_manager(struct charger_global_desc *gd) | |||
994 | } | 991 | } |
995 | EXPORT_SYMBOL_GPL(setup_charger_manager); | 992 | EXPORT_SYMBOL_GPL(setup_charger_manager); |
996 | 993 | ||
994 | /** | ||
995 | * charger_extcon_work - enable/diable charger according to the state | ||
996 | * of charger cable | ||
997 | * | ||
998 | * @work: work_struct of the function charger_extcon_work. | ||
999 | */ | ||
1000 | static void charger_extcon_work(struct work_struct *work) | ||
1001 | { | ||
1002 | struct charger_cable *cable = | ||
1003 | container_of(work, struct charger_cable, wq); | ||
1004 | |||
1005 | try_charger_enable(cable->cm, cable->attached); | ||
1006 | } | ||
1007 | |||
1008 | /** | ||
1009 | * charger_extcon_notifier - receive the state of charger cable | ||
1010 | * when registered cable is attached or detached. | ||
1011 | * | ||
1012 | * @self: the notifier block of the charger_extcon_notifier. | ||
1013 | * @event: the cable state. | ||
1014 | * @ptr: the data pointer of notifier block. | ||
1015 | */ | ||
1016 | static int charger_extcon_notifier(struct notifier_block *self, | ||
1017 | unsigned long event, void *ptr) | ||
1018 | { | ||
1019 | struct charger_cable *cable = | ||
1020 | container_of(self, struct charger_cable, nb); | ||
1021 | |||
1022 | cable->attached = event; | ||
1023 | schedule_work(&cable->wq); | ||
1024 | |||
1025 | return NOTIFY_DONE; | ||
1026 | } | ||
1027 | |||
1028 | /** | ||
1029 | * charger_extcon_init - register external connector to use it | ||
1030 | * as the charger cable | ||
1031 | * | ||
1032 | * @cm: the Charger Manager representing the battery. | ||
1033 | * @cable: the Charger cable representing the external connector. | ||
1034 | */ | ||
1035 | static int charger_extcon_init(struct charger_manager *cm, | ||
1036 | struct charger_cable *cable) | ||
1037 | { | ||
1038 | int ret = 0; | ||
1039 | |||
1040 | /* | ||
1041 | * Charger manager use Extcon framework to identify | ||
1042 | * the charger cable among various external connector | ||
1043 | * cable (e.g., TA, USB, MHL, Dock). | ||
1044 | */ | ||
1045 | INIT_WORK(&cable->wq, charger_extcon_work); | ||
1046 | cable->nb.notifier_call = charger_extcon_notifier; | ||
1047 | ret = extcon_register_interest(&cable->extcon_dev, | ||
1048 | cable->extcon_name, cable->name, &cable->nb); | ||
1049 | if (ret < 0) { | ||
1050 | pr_info("Cannot register extcon_dev for %s(cable: %s).\n", | ||
1051 | cable->extcon_name, | ||
1052 | cable->name); | ||
1053 | ret = -EINVAL; | ||
1054 | } | ||
1055 | |||
1056 | return ret; | ||
1057 | } | ||
1058 | |||
997 | static int charger_manager_probe(struct platform_device *pdev) | 1059 | static int charger_manager_probe(struct platform_device *pdev) |
998 | { | 1060 | { |
999 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); | 1061 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); |
1000 | struct charger_manager *cm; | 1062 | struct charger_manager *cm; |
1001 | int ret = 0, i = 0; | 1063 | int ret = 0, i = 0; |
1064 | int j = 0; | ||
1002 | union power_supply_propval val; | 1065 | union power_supply_propval val; |
1003 | 1066 | ||
1004 | if (g_desc && !rtc_dev && g_desc->rtc_name) { | 1067 | if (g_desc && !rtc_dev && g_desc->rtc_name) { |
@@ -1167,11 +1230,31 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1167 | goto err_register; | 1230 | goto err_register; |
1168 | } | 1231 | } |
1169 | 1232 | ||
1170 | ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators, | 1233 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1171 | desc->charger_regulators); | 1234 | struct charger_regulator *charger |
1172 | if (ret) { | 1235 | = &desc->charger_regulators[i]; |
1173 | dev_err(&pdev->dev, "Cannot get charger regulators.\n"); | 1236 | |
1174 | goto err_bulk_get; | 1237 | charger->consumer = regulator_get(&pdev->dev, |
1238 | charger->regulator_name); | ||
1239 | if (charger->consumer == NULL) { | ||
1240 | dev_err(&pdev->dev, "Cannot find charger(%s)n", | ||
1241 | charger->regulator_name); | ||
1242 | ret = -EINVAL; | ||
1243 | goto err_chg_get; | ||
1244 | } | ||
1245 | |||
1246 | for (j = 0 ; j < charger->num_cables ; j++) { | ||
1247 | struct charger_cable *cable = &charger->cables[j]; | ||
1248 | |||
1249 | ret = charger_extcon_init(cm, cable); | ||
1250 | if (ret < 0) { | ||
1251 | dev_err(&pdev->dev, "Cannot find charger(%s)n", | ||
1252 | charger->regulator_name); | ||
1253 | goto err_extcon; | ||
1254 | } | ||
1255 | cable->charger = charger; | ||
1256 | cable->cm = cm; | ||
1257 | } | ||
1175 | } | 1258 | } |
1176 | 1259 | ||
1177 | ret = try_charger_enable(cm, true); | 1260 | ret = try_charger_enable(cm, true); |
@@ -1197,9 +1280,19 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1197 | return 0; | 1280 | return 0; |
1198 | 1281 | ||
1199 | err_chg_enable: | 1282 | err_chg_enable: |
1200 | regulator_bulk_free(desc->num_charger_regulators, | 1283 | err_extcon: |
1201 | desc->charger_regulators); | 1284 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1202 | err_bulk_get: | 1285 | struct charger_regulator *charger |
1286 | = &desc->charger_regulators[i]; | ||
1287 | for (j = 0 ; j < charger->num_cables ; j++) { | ||
1288 | struct charger_cable *cable = &charger->cables[j]; | ||
1289 | extcon_unregister_interest(&cable->extcon_dev); | ||
1290 | } | ||
1291 | } | ||
1292 | err_chg_get: | ||
1293 | for (i = 0 ; i < desc->num_charger_regulators ; i++) | ||
1294 | regulator_put(desc->charger_regulators[i].consumer); | ||
1295 | |||
1203 | power_supply_unregister(&cm->charger_psy); | 1296 | power_supply_unregister(&cm->charger_psy); |
1204 | err_register: | 1297 | err_register: |
1205 | kfree(cm->charger_psy.properties); | 1298 | kfree(cm->charger_psy.properties); |
@@ -1218,6 +1311,8 @@ static int __devexit charger_manager_remove(struct platform_device *pdev) | |||
1218 | { | 1311 | { |
1219 | struct charger_manager *cm = platform_get_drvdata(pdev); | 1312 | struct charger_manager *cm = platform_get_drvdata(pdev); |
1220 | struct charger_desc *desc = cm->desc; | 1313 | struct charger_desc *desc = cm->desc; |
1314 | int i = 0; | ||
1315 | int j = 0; | ||
1221 | 1316 | ||
1222 | /* Remove from the list */ | 1317 | /* Remove from the list */ |
1223 | mutex_lock(&cm_list_mtx); | 1318 | mutex_lock(&cm_list_mtx); |
@@ -1229,8 +1324,18 @@ static int __devexit charger_manager_remove(struct platform_device *pdev) | |||
1229 | if (delayed_work_pending(&cm_monitor_work)) | 1324 | if (delayed_work_pending(&cm_monitor_work)) |
1230 | cancel_delayed_work_sync(&cm_monitor_work); | 1325 | cancel_delayed_work_sync(&cm_monitor_work); |
1231 | 1326 | ||
1232 | regulator_bulk_free(desc->num_charger_regulators, | 1327 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1233 | desc->charger_regulators); | 1328 | struct charger_regulator *charger |
1329 | = &desc->charger_regulators[i]; | ||
1330 | for (j = 0 ; j < charger->num_cables ; j++) { | ||
1331 | struct charger_cable *cable = &charger->cables[j]; | ||
1332 | extcon_unregister_interest(&cable->extcon_dev); | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | for (i = 0 ; i < desc->num_charger_regulators ; i++) | ||
1337 | regulator_put(desc->charger_regulators[i].consumer); | ||
1338 | |||
1234 | power_supply_unregister(&cm->charger_psy); | 1339 | power_supply_unregister(&cm->charger_psy); |
1235 | 1340 | ||
1236 | try_charger_enable(cm, false); | 1341 | try_charger_enable(cm, false); |