History

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.

Chanwoo Choi committed 14 years ago

Commit bee737b1 parent 85a392d2 files · +179 −17Browse files

Unified · Split

2 files
  1. drivers/power/charger-manager.c +121 −16
  2. include/linux/power/charger-manager.h +58 −1
drivers/power/charger-manager.c+121−16
@@ -271,16 +271,13 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) · 270 unmodified lines
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 places279 * 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) · 1 unmodified line
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) · 699 unmodified lines
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) · 162 unmodified lines
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) · 19 unmodified lines
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) · 12 unmodified lines
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) · 5 unmodified lines
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);
include/linux/power/charger-manager.h+58−1
@@ -16,6 +16,7 @@ · 15 unmodified lines
16#define _CHARGER_MANAGER_H16#define _CHARGER_MANAGER_H
17 17
18#include <linux/power_supply.h>18#include <linux/power_supply.h>
19#include <linux/extcon.h>
19 20
20enum data_source {21enum data_source {
21 CM_BATTERY_PRESENT,22 CM_BATTERY_PRESENT,
@@ -64,6 +65,62 @@ struct charger_global_desc { · 42 unmodified lines
64 bool assume_timer_stops_in_suspend;65 bool assume_timer_stops_in_suspend;
65};66};
66 67
68/**
69 * struct charger_cable
70 * @extcon_name: the name of extcon device.
71 * @name: the name of charger cable(external connector).
72 * @extcon_dev: the extcon device.
73 * @wq: the workqueue to control charger according to the state of
74 * charger cable. If charger cable is attached, enable charger.
75 * But if charger cable is detached, disable charger.
76 * @nb: the notifier block to receive changed state from EXTCON
77 * (External Connector) when charger cable is attached/detached.
78 * @attached: the state of charger cable.
79 * true: the charger cable is attached
80 * false: the charger cable is detached
81 * @charger: the instance of struct charger_regulator.
82 * @cm: the Charger Manager representing the battery.
83 */
84struct charger_cable {
85 const char *extcon_name;
86 const char *name;
87
88 /* The charger-manager use Exton framework*/
89 struct extcon_specific_cable_nb extcon_dev;
90 struct work_struct wq;
91 struct notifier_block nb;
92
93 /* The state of charger cable */
94 bool attached;
95
96 struct charger_regulator *charger;
97 struct charger_manager *cm;
98};
99
100/**
101 * struct charger_regulator
102 * @regulator_name: the name of regulator for using charger.
103 * @consumer: the regulator consumer for the charger.
104 * @cables:
105 * the array of charger cables to enable/disable charger
106 * and set current limit according to constratint data of
107 * struct charger_cable if only charger cable included
108 * in the array of charger cables is attached/detached.
109 * @num_cables: the number of charger cables.
110 */
111struct charger_regulator {
112 /* The name of regulator for charging */
113 const char *regulator_name;
114 struct regulator *consumer;
115
116 /*
117 * Store constraint information related to current limit,
118 * each cable have different condition for charging.
119 */
120 struct charger_cable *cables;
121 int num_cables;
122};
123
67/**124/**
68 * struct charger_desc125 * struct charger_desc
69 * @psy_name: the name of power-supply-class for charger manager126 * @psy_name: the name of power-supply-class for charger manager
@@ -109,7 +166,7 @@ struct charger_desc { · 39 unmodified lines
109 char **psy_charger_stat;166 char **psy_charger_stat;
110 167
111 int num_charger_regulators;168 int num_charger_regulators;
112 struct regulator_bulk_data *charger_regulators;169 struct charger_regulator *charger_regulators;
113 170
114 char *psy_fuel_gauge;171 char *psy_fuel_gauge;
115 172

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t