aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/charger-manager.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 959062d16bac..86935ec18954 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -23,6 +23,16 @@
23#include <linux/power/charger-manager.h> 23#include <linux/power/charger-manager.h>
24#include <linux/regulator/consumer.h> 24#include <linux/regulator/consumer.h>
25 25
26static 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 * Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for 37 * Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for
28 * delayed works so that we can run delayed works with CM_JIFFIES_SMALL 38 * delayed works so that we can run delayed works with CM_JIFFIES_SMALL
@@ -525,6 +535,69 @@ static void cm_monitor_poller(struct work_struct *work)
525 schedule_work(&setup_polling); 535 schedule_work(&setup_polling);
526} 536}
527 537
538/**
539 * fullbatt_handler - Event handler for CM_EVENT_BATT_FULL
540 * @cm: the Charger Manager representing the battery.
541 */
542static void fullbatt_handler(struct charger_manager *cm)
543{
544 struct charger_desc *desc = cm->desc;
545
546 if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms)
547 goto out;
548
549 if (cm_suspended)
550 device_set_wakeup_capable(cm->dev, true);
551
552 if (delayed_work_pending(&cm->fullbatt_vchk_work))
553 cancel_delayed_work(&cm->fullbatt_vchk_work);
554 queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
555 msecs_to_jiffies(desc->fullbatt_vchkdrop_ms));
556 cm->fullbatt_vchk_jiffies_at = jiffies + msecs_to_jiffies(
557 desc->fullbatt_vchkdrop_ms);
558
559 if (cm->fullbatt_vchk_jiffies_at == 0)
560 cm->fullbatt_vchk_jiffies_at = 1;
561
562out:
563 dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n");
564 uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]);
565}
566
567/**
568 * battout_handler - Event handler for CM_EVENT_BATT_OUT
569 * @cm: the Charger Manager representing the battery.
570 */
571static void battout_handler(struct charger_manager *cm)
572{
573 if (cm_suspended)
574 device_set_wakeup_capable(cm->dev, true);
575
576 if (!is_batt_present(cm)) {
577 dev_emerg(cm->dev, "Battery Pulled Out!\n");
578 uevent_notify(cm, default_event_names[CM_EVENT_BATT_OUT]);
579 } else {
580 uevent_notify(cm, "Battery Reinserted?");
581 }
582}
583
584/**
585 * misc_event_handler - Handler for other evnets
586 * @cm: the Charger Manager representing the battery.
587 * @type: the Charger Manager representing the battery.
588 */
589static void misc_event_handler(struct charger_manager *cm,
590 enum cm_event_types type)
591{
592 if (cm_suspended)
593 device_set_wakeup_capable(cm->dev, true);
594
595 if (!delayed_work_pending(&cm_monitor_work) &&
596 is_polling_required(cm) && cm->desc->polling_interval_ms)
597 schedule_work(&setup_polling);
598 uevent_notify(cm, default_event_names[type]);
599}
600
528static int charger_get_property(struct power_supply *psy, 601static int charger_get_property(struct power_supply *psy,
529 enum power_supply_property psp, 602 enum power_supply_property psp,
530 union power_supply_propval *val) 603 union power_supply_propval *val)
@@ -1112,6 +1185,13 @@ static int charger_manager_probe(struct platform_device *pdev)
1112 list_add(&cm->entry, &cm_list); 1185 list_add(&cm->entry, &cm_list);
1113 mutex_unlock(&cm_list_mtx); 1186 mutex_unlock(&cm_list_mtx);
1114 1187
1188 /*
1189 * Charger-manager is capable of waking up the systme from sleep
1190 * when event is happend through cm_notify_event()
1191 */
1192 device_init_wakeup(&pdev->dev, true);
1193 device_set_wakeup_capable(&pdev->dev, false);
1194
1115 schedule_work(&setup_polling); 1195 schedule_work(&setup_polling);
1116 1196
1117 return 0; 1197 return 0;
@@ -1169,6 +1249,18 @@ static const struct platform_device_id charger_manager_id[] = {
1169}; 1249};
1170MODULE_DEVICE_TABLE(platform, charger_manager_id); 1250MODULE_DEVICE_TABLE(platform, charger_manager_id);
1171 1251
1252static int cm_suspend_noirq(struct device *dev)
1253{
1254 int ret = 0;
1255
1256 if (device_may_wakeup(dev)) {
1257 device_set_wakeup_capable(dev, false);
1258 ret = -EAGAIN;
1259 }
1260
1261 return ret;
1262}
1263
1172static int cm_suspend_prepare(struct device *dev) 1264static int cm_suspend_prepare(struct device *dev)
1173{ 1265{
1174 struct charger_manager *cm = dev_get_drvdata(dev); 1266 struct charger_manager *cm = dev_get_drvdata(dev);
@@ -1250,11 +1342,13 @@ static void cm_suspend_complete(struct device *dev)
1250 queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work, 1342 queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
1251 msecs_to_jiffies(delay)); 1343 msecs_to_jiffies(delay));
1252 } 1344 }
1345 device_set_wakeup_capable(cm->dev, false);
1253 uevent_notify(cm, NULL); 1346 uevent_notify(cm, NULL);
1254} 1347}
1255 1348
1256static const struct dev_pm_ops charger_manager_pm = { 1349static const struct dev_pm_ops charger_manager_pm = {
1257 .prepare = cm_suspend_prepare, 1350 .prepare = cm_suspend_prepare,
1351 .suspend_noirq = cm_suspend_noirq,
1258 .complete = cm_suspend_complete, 1352 .complete = cm_suspend_complete,
1259}; 1353};
1260 1354
@@ -1287,6 +1381,75 @@ static void __exit charger_manager_cleanup(void)
1287} 1381}
1288module_exit(charger_manager_cleanup); 1382module_exit(charger_manager_cleanup);
1289 1383
1384/**
1385 * find_power_supply - find the associated power_supply of charger
1386 * @cm: the Charger Manager representing the battery
1387 * @psy: pointer to instance of charger's power_supply
1388 */
1389static bool find_power_supply(struct charger_manager *cm,
1390 struct power_supply *psy)
1391{
1392 int i;
1393 bool found = false;
1394
1395 for (i = 0; cm->charger_stat[i]; i++) {
1396 if (psy == cm->charger_stat[i]) {
1397 found = true;
1398 break;
1399 }
1400 }
1401
1402 return found;
1403}
1404
1405/**
1406 * cm_notify_event - charger driver notify Charger Manager of charger event
1407 * @psy: pointer to instance of charger's power_supply
1408 * @type: type of charger event
1409 * @msg: optional message passed to uevent_notify fuction
1410 */
1411void cm_notify_event(struct power_supply *psy, enum cm_event_types type,
1412 char *msg)
1413{
1414 struct charger_manager *cm;
1415 bool found_power_supply = false;
1416
1417 if (psy == NULL)
1418 return;
1419
1420 mutex_lock(&cm_list_mtx);
1421 list_for_each_entry(cm, &cm_list, entry) {
1422 found_power_supply = find_power_supply(cm, psy);
1423 if (found_power_supply)
1424 break;
1425 }
1426 mutex_unlock(&cm_list_mtx);
1427
1428 if (!found_power_supply)
1429 return;
1430
1431 switch (type) {
1432 case CM_EVENT_BATT_FULL:
1433 fullbatt_handler(cm);
1434 break;
1435 case CM_EVENT_BATT_OUT:
1436 battout_handler(cm);
1437 break;
1438 case CM_EVENT_BATT_IN:
1439 case CM_EVENT_EXT_PWR_IN_OUT ... CM_EVENT_CHG_START_STOP:
1440 misc_event_handler(cm, type);
1441 break;
1442 case CM_EVENT_UNKNOWN:
1443 case CM_EVENT_OTHERS:
1444 uevent_notify(cm, msg ? msg : default_event_names[type]);
1445 break;
1446 default:
1447 dev_err(cm->dev, "%s type not specified.\n", __func__);
1448 break;
1449 }
1450}
1451EXPORT_SYMBOL_GPL(cm_notify_event);
1452
1290MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 1453MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
1291MODULE_DESCRIPTION("Charger Manager"); 1454MODULE_DESCRIPTION("Charger Manager");
1292MODULE_LICENSE("GPL"); 1455MODULE_LICENSE("GPL");