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.
Unified · Split
| @@ -271,16 +271,13 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) · 270 unmodified lines | ||
| 271 | 271 | if (enable) { |
| 272 | 272 | if (cm->emergency_stop) |
| 273 | 273 | return -EAGAIN; |
| 274 | − err = regulator_bulk_enable(desc->num_charger_regulators, | |
| 275 | − desc->charger_regulators); | |
| 274 | + for (i = 0 ; i < desc->num_charger_regulators ; i++) | |
| 275 | + regulator_enable(desc->charger_regulators[i].consumer); | |
| 276 | 276 | } else { |
| 277 | 277 | /* |
| 278 | 278 | * Abnormal battery state - Stop charging forcibly, |
| 279 | 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 | 281 | for (i = 0; i < desc->num_charger_regulators; i++) { |
| 285 | 282 | if (regulator_is_enabled( |
| 286 | 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 | 285 | desc->charger_regulators[i].consumer); |
| 289 | 286 | dev_warn(cm->dev, |
| 290 | 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 | } |
| 995 | 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 | 1059 | static int charger_manager_probe(struct platform_device *pdev) |
| 998 | 1060 | { |
| 999 | 1061 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); |
| 1000 | 1062 | struct charger_manager *cm; |
| 1001 | 1063 | int ret = 0, i = 0; |
| 1064 | + int j = 0; | |
| 1002 | 1065 | union power_supply_propval val; |
| 1003 | 1066 | |
| 1004 | 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 | 1230 | goto err_register; |
| 1168 | 1231 | } |
| 1169 | 1232 | |
| 1170 | − ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators, | |
| 1171 | − desc->charger_regulators); | |
| 1172 | − if (ret) { | |
| 1173 | − dev_err(&pdev->dev, "Cannot get charger regulators.\n"); | |
| 1174 | − goto err_bulk_get; | |
| 1233 | + for (i = 0 ; i < desc->num_charger_regulators ; i++) { | |
| 1234 | + struct charger_regulator *charger | |
| 1235 | + = &desc->charger_regulators[i]; | |
| 1236 | + | |
| 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 | 1260 | ret = try_charger_enable(cm, true); |
| @@ -1197,9 +1280,19 @@ static int charger_manager_probe(struct platform_device *pdev) · 19 unmodified lines | ||
| 1197 | 1280 | return 0; |
| 1198 | 1281 | |
| 1199 | 1282 | err_chg_enable: |
| 1200 | − regulator_bulk_free(desc->num_charger_regulators, | |
| 1201 | − desc->charger_regulators); | |
| 1202 | −err_bulk_get: | |
| 1283 | +err_extcon: | |
| 1284 | + for (i = 0 ; i < desc->num_charger_regulators ; i++) { | |
| 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 | 1296 | power_supply_unregister(&cm->charger_psy); |
| 1204 | 1297 | err_register: |
| 1205 | 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 | 1312 | struct charger_manager *cm = platform_get_drvdata(pdev); |
| 1220 | 1313 | struct charger_desc *desc = cm->desc; |
| 1314 | + int i = 0; | |
| 1315 | + int j = 0; | |
| 1221 | 1316 | |
| 1222 | 1317 | /* Remove from the list */ |
| 1223 | 1318 | mutex_lock(&cm_list_mtx); |
| @@ -1229,8 +1324,18 @@ static int __devexit charger_manager_remove(struct platform_device *pdev) · 5 unmodified lines | ||
| 1229 | 1324 | if (delayed_work_pending(&cm_monitor_work)) |
| 1230 | 1325 | cancel_delayed_work_sync(&cm_monitor_work); |
| 1231 | 1326 | |
| 1232 | − regulator_bulk_free(desc->num_charger_regulators, | |
| 1233 | − desc->charger_regulators); | |
| 1327 | + for (i = 0 ; i < desc->num_charger_regulators ; i++) { | |
| 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 | 1339 | power_supply_unregister(&cm->charger_psy); |
| 1235 | 1340 | |
| 1236 | 1341 | try_charger_enable(cm, false); |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | #define _CHARGER_MANAGER_H |
| 17 | 17 | |
| 18 | 18 | #include <linux/power_supply.h> |
| 19 | +#include <linux/extcon.h> | |
| 19 | 20 | |
| 20 | 21 | enum data_source { |
| 21 | 22 | CM_BATTERY_PRESENT, |
| @@ -64,6 +65,62 @@ struct charger_global_desc { · 42 unmodified lines | ||
| 64 | 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 | + */ | |
| 84 | +struct 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 | + */ | |
| 111 | +struct 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 | 125 | * struct charger_desc |
| 69 | 126 | * @psy_name: the name of power-supply-class for charger manager |
| @@ -109,7 +166,7 @@ struct charger_desc { · 39 unmodified lines | ||
| 109 | 166 | char **psy_charger_stat; |
| 110 | 167 | |
| 111 | 168 | int num_charger_regulators; |
| 112 | − struct regulator_bulk_data *charger_regulators; | |
| 169 | + struct charger_regulator *charger_regulators; | |
| 113 | 170 | |
| 114 | 171 | char *psy_fuel_gauge; |
| 115 | 172 | |