aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/charger-manager.c
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2012-07-12 02:03:25 -0400
committerAnton Vorontsov <anton.vorontsov@linaro.org>2012-07-13 21:31:13 -0400
commitbee737bccb03ebd27f2d52706e9aed2fa2c8dcc4 (patch)
treebf652913262e9e0504324c090b5893c58c936396 /drivers/power/charger-manager.c
parent85a392d47cac8fa9258c5609a7b02adade961076 (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.c137
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}
995EXPORT_SYMBOL_GPL(setup_charger_manager); 992EXPORT_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 */
1000static 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 */
1016static 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 */
1035static 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
997static int charger_manager_probe(struct platform_device *pdev) 1059static 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
1199err_chg_enable: 1282err_chg_enable:
1200 regulator_bulk_free(desc->num_charger_regulators, 1283err_extcon:
1201 desc->charger_regulators); 1284 for (i = 0 ; i < desc->num_charger_regulators ; i++) {
1202err_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 }
1292err_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);
1204err_register: 1297err_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);