Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

charger-manager: Provide cm_notify_event function for in-kernel use

By using cm_notify_event function, charger driver can report several
charger events (e.g. battery full and external power in/out, etc) to
Charger-Manager. Charger-Manager can properly and immediately control
chargers by the reported event.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Donggeun Kim <dg77.kim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>

authored by

Chanwoo Choi and committed by
Anton Vorontsov
dfeccb12 d829dc75

+195 -9
+15 -1
Documentation/power/charger-manager.txt
··· 50 50 restarts charging. This check is also performed while suspended by 51 51 setting wakeup time accordingly and using suspend_again. 52 52 53 + * Support for uevent-notify 54 + With the charger-related events, the device sends 55 + notification to users with UEVENT. 56 + 53 57 2. Global Charger-Manager Data related with suspend_again 54 58 ======================================================== 55 59 In order to setup Charger Manager with suspend-again feature ··· 178 174 the value of measure_battery_temp. 179 175 }; 180 176 181 - 5. Other Considerations 177 + 5. Notify Charger-Manager of charger events: cm_notify_event() 178 + ========================================================= 179 + If there is an charger event is required to notify 180 + Charger Manager, a charger device driver that triggers the event can call 181 + cm_notify_event(psy, type, msg) to notify the corresponding Charger Manager. 182 + In the function, psy is the charger driver's power_supply pointer, which is 183 + associated with Charger-Manager. The parameter "type" 184 + is the same as irq's type (enum cm_event_types). The event message "msg" is 185 + optional and is effective only if the event type is "UNDESCRIBED" or "OTHERS". 186 + 187 + 6. Other Considerations 182 188 ======================= 183 189 184 190 At the charger/battery-related events such as battery-pulled-out,
+163
drivers/power/charger-manager.c
··· 23 23 #include <linux/power/charger-manager.h> 24 24 #include <linux/regulator/consumer.h> 25 25 26 + static const char * const default_event_names[] = { 27 + [CM_EVENT_UNKNOWN] = "Unknown", 28 + [CM_EVENT_BATT_FULL] = "Battery Full", 29 + [CM_EVENT_BATT_IN] = "Battery Inserted", 30 + [CM_EVENT_BATT_OUT] = "Battery Pulled Out", 31 + [CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", 32 + [CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", 33 + [CM_EVENT_OTHERS] = "Other battery events" 34 + }; 35 + 26 36 /* 27 37 * Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for 28 38 * delayed works so that we can run delayed works with CM_JIFFIES_SMALL ··· 533 523 { 534 524 cm_monitor(); 535 525 schedule_work(&setup_polling); 526 + } 527 + 528 + /** 529 + * fullbatt_handler - Event handler for CM_EVENT_BATT_FULL 530 + * @cm: the Charger Manager representing the battery. 531 + */ 532 + static void fullbatt_handler(struct charger_manager *cm) 533 + { 534 + struct charger_desc *desc = cm->desc; 535 + 536 + if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms) 537 + goto out; 538 + 539 + if (cm_suspended) 540 + device_set_wakeup_capable(cm->dev, true); 541 + 542 + if (delayed_work_pending(&cm->fullbatt_vchk_work)) 543 + cancel_delayed_work(&cm->fullbatt_vchk_work); 544 + queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work, 545 + msecs_to_jiffies(desc->fullbatt_vchkdrop_ms)); 546 + cm->fullbatt_vchk_jiffies_at = jiffies + msecs_to_jiffies( 547 + desc->fullbatt_vchkdrop_ms); 548 + 549 + if (cm->fullbatt_vchk_jiffies_at == 0) 550 + cm->fullbatt_vchk_jiffies_at = 1; 551 + 552 + out: 553 + dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n"); 554 + uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]); 555 + } 556 + 557 + /** 558 + * battout_handler - Event handler for CM_EVENT_BATT_OUT 559 + * @cm: the Charger Manager representing the battery. 560 + */ 561 + static void battout_handler(struct charger_manager *cm) 562 + { 563 + if (cm_suspended) 564 + device_set_wakeup_capable(cm->dev, true); 565 + 566 + if (!is_batt_present(cm)) { 567 + dev_emerg(cm->dev, "Battery Pulled Out!\n"); 568 + uevent_notify(cm, default_event_names[CM_EVENT_BATT_OUT]); 569 + } else { 570 + uevent_notify(cm, "Battery Reinserted?"); 571 + } 572 + } 573 + 574 + /** 575 + * misc_event_handler - Handler for other evnets 576 + * @cm: the Charger Manager representing the battery. 577 + * @type: the Charger Manager representing the battery. 578 + */ 579 + static void misc_event_handler(struct charger_manager *cm, 580 + enum cm_event_types type) 581 + { 582 + if (cm_suspended) 583 + device_set_wakeup_capable(cm->dev, true); 584 + 585 + if (!delayed_work_pending(&cm_monitor_work) && 586 + is_polling_required(cm) && cm->desc->polling_interval_ms) 587 + schedule_work(&setup_polling); 588 + uevent_notify(cm, default_event_names[type]); 536 589 } 537 590 538 591 static int charger_get_property(struct power_supply *psy, ··· 1185 1112 list_add(&cm->entry, &cm_list); 1186 1113 mutex_unlock(&cm_list_mtx); 1187 1114 1115 + /* 1116 + * Charger-manager is capable of waking up the systme from sleep 1117 + * when event is happend through cm_notify_event() 1118 + */ 1119 + device_init_wakeup(&pdev->dev, true); 1120 + device_set_wakeup_capable(&pdev->dev, false); 1121 + 1188 1122 schedule_work(&setup_polling); 1189 1123 1190 1124 return 0; ··· 1248 1168 { }, 1249 1169 }; 1250 1170 MODULE_DEVICE_TABLE(platform, charger_manager_id); 1171 + 1172 + static int cm_suspend_noirq(struct device *dev) 1173 + { 1174 + int ret = 0; 1175 + 1176 + if (device_may_wakeup(dev)) { 1177 + device_set_wakeup_capable(dev, false); 1178 + ret = -EAGAIN; 1179 + } 1180 + 1181 + return ret; 1182 + } 1251 1183 1252 1184 static int cm_suspend_prepare(struct device *dev) 1253 1185 { ··· 1342 1250 queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work, 1343 1251 msecs_to_jiffies(delay)); 1344 1252 } 1253 + device_set_wakeup_capable(cm->dev, false); 1345 1254 uevent_notify(cm, NULL); 1346 1255 } 1347 1256 1348 1257 static const struct dev_pm_ops charger_manager_pm = { 1349 1258 .prepare = cm_suspend_prepare, 1259 + .suspend_noirq = cm_suspend_noirq, 1350 1260 .complete = cm_suspend_complete, 1351 1261 }; 1352 1262 ··· 1380 1286 platform_driver_unregister(&charger_manager_driver); 1381 1287 } 1382 1288 module_exit(charger_manager_cleanup); 1289 + 1290 + /** 1291 + * find_power_supply - find the associated power_supply of charger 1292 + * @cm: the Charger Manager representing the battery 1293 + * @psy: pointer to instance of charger's power_supply 1294 + */ 1295 + static bool find_power_supply(struct charger_manager *cm, 1296 + struct power_supply *psy) 1297 + { 1298 + int i; 1299 + bool found = false; 1300 + 1301 + for (i = 0; cm->charger_stat[i]; i++) { 1302 + if (psy == cm->charger_stat[i]) { 1303 + found = true; 1304 + break; 1305 + } 1306 + } 1307 + 1308 + return found; 1309 + } 1310 + 1311 + /** 1312 + * cm_notify_event - charger driver notify Charger Manager of charger event 1313 + * @psy: pointer to instance of charger's power_supply 1314 + * @type: type of charger event 1315 + * @msg: optional message passed to uevent_notify fuction 1316 + */ 1317 + void cm_notify_event(struct power_supply *psy, enum cm_event_types type, 1318 + char *msg) 1319 + { 1320 + struct charger_manager *cm; 1321 + bool found_power_supply = false; 1322 + 1323 + if (psy == NULL) 1324 + return; 1325 + 1326 + mutex_lock(&cm_list_mtx); 1327 + list_for_each_entry(cm, &cm_list, entry) { 1328 + found_power_supply = find_power_supply(cm, psy); 1329 + if (found_power_supply) 1330 + break; 1331 + } 1332 + mutex_unlock(&cm_list_mtx); 1333 + 1334 + if (!found_power_supply) 1335 + return; 1336 + 1337 + switch (type) { 1338 + case CM_EVENT_BATT_FULL: 1339 + fullbatt_handler(cm); 1340 + break; 1341 + case CM_EVENT_BATT_OUT: 1342 + battout_handler(cm); 1343 + break; 1344 + case CM_EVENT_BATT_IN: 1345 + case CM_EVENT_EXT_PWR_IN_OUT ... CM_EVENT_CHG_START_STOP: 1346 + misc_event_handler(cm, type); 1347 + break; 1348 + case CM_EVENT_UNKNOWN: 1349 + case CM_EVENT_OTHERS: 1350 + uevent_notify(cm, msg ? msg : default_event_names[type]); 1351 + break; 1352 + default: 1353 + dev_err(cm->dev, "%s type not specified.\n", __func__); 1354 + break; 1355 + } 1356 + } 1357 + EXPORT_SYMBOL_GPL(cm_notify_event); 1383 1358 1384 1359 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 1385 1360 MODULE_DESCRIPTION("Charger Manager");
+17 -8
include/linux/power/charger-manager.h
··· 31 31 CM_POLL_CHARGING_ONLY, 32 32 }; 33 33 34 + enum cm_event_types { 35 + CM_EVENT_UNKNOWN = 0, 36 + CM_EVENT_BATT_FULL, 37 + CM_EVENT_BATT_IN, 38 + CM_EVENT_BATT_OUT, 39 + CM_EVENT_EXT_PWR_IN_OUT, 40 + CM_EVENT_CHG_START_STOP, 41 + CM_EVENT_OTHERS, 42 + }; 43 + 34 44 /** 35 45 * struct charger_global_desc 36 46 * @rtc_name: the name of RTC used to wake up the system from suspend. ··· 169 159 #ifdef CONFIG_CHARGER_MANAGER 170 160 extern int setup_charger_manager(struct charger_global_desc *gd); 171 161 extern bool cm_suspend_again(void); 162 + extern void cm_notify_event(struct power_supply *psy, 163 + enum cm_event_types type, char *msg); 172 164 #else 173 - static void __maybe_unused setup_charger_manager(struct charger_global_desc *gd) 174 - { } 175 - 176 - static bool __maybe_unused cm_suspend_again(void) 177 - { 178 - return false; 179 - } 165 + static inline int setup_charger_manager(struct charger_global_desc *gd) 166 + { return 0; } 167 + static inline bool cm_suspend_again(void) { return false; } 168 + static inline void cm_notify_event(struct power_supply *psy, 169 + enum cm_event_types type, char *msg) { } 180 170 #endif 181 - 182 171 #endif /* _CHARGER_MANAGER_H */