[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-id: <1329972300-19335-3-git-send-email-dg77.kim@samsung.com>
Date: Thu, 23 Feb 2012 13:45:00 +0900
From: Donggeun Kim <dg77.kim@...sung.com>
To: linux-kernel@...r.kernel.org
Cc: cbouatmailru@...il.com, len.brown@...el.com, pavel@....cz,
rjw@...k.pl, rdunlap@...otime.net, myungjoo.ham@...sung.com,
kyungmin.park@...sung.com, dg77.kim@...sung.com
Subject: [PATCH 2/2] power_supply: Charger-Manager: provide 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@...sung.com>
Signed-off-by: Donggeun Kim <dg77.kim@...sung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@...sung.com>
---
Documentation/power/charger-manager.txt | 16 +++-
drivers/power/charger-manager.c | 157 +++++++++++++++++++++++++++++++
include/linux/power/charger-manager.h | 18 ++++
3 files changed, 190 insertions(+), 1 deletions(-)
diff --git a/Documentation/power/charger-manager.txt b/Documentation/power/charger-manager.txt
index 47f7fdc..f6566c7 100644
--- a/Documentation/power/charger-manager.txt
+++ b/Documentation/power/charger-manager.txt
@@ -50,6 +50,10 @@ Charger Manager supports the following:
restarts charging. This check is also performed while suspended by
setting wakeup time accordingly and using suspend_again.
+* Support for uevent-notify
+ With the charger-related events, the device sends
+ notification to users with UEVENT.
+
2. Global Charger-Manager Data related with suspend_again
========================================================
In order to setup Charger Manager with suspend-again feature
@@ -174,7 +178,17 @@ bool measure_battery_temp;
the value of measure_battery_temp.
};
-5. Other Considerations
+5. Notify Charger-Manager of charger events: cm_notify_event()
+=========================================================
+If there is an charger event is required to notify
+Charger Manager, a charger device driver that triggers the event can call
+cm_notify_event(psy, type, msg) to notify the corresponding Charger Manager.
+In the function, psy is the charger driver's power_supply pointer, which is
+associated with Charger-Manager. The parameter "type"
+is the same as irq's type (enum cm_event_types). The event message "msg" is
+optional and is effective only if the event type is "UNDESCRIBED" or "OTHERS".
+
+6. Other Considerations
=======================
At the charger/battery-related events such as battery-pulled-out,
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 9ecde4c..8cf0d42 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -23,6 +23,16 @@
#include <linux/power/charger-manager.h>
#include <linux/regulator/consumer.h>
+static const char * const default_event_names[] = {
+ [CM_EVENT_UNDESCRIBED] = "Undescribed",
+ [CM_EVENT_BATT_FULL] = "Battery Full",
+ [CM_EVENT_BATT_IN] = "Battery Inserted",
+ [CM_EVENT_BATT_OUT] = "Battery Pulled Out",
+ [CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach",
+ [CM_EVENT_CHG_START_STOP] = "Charging Start/Stop",
+ [CM_EVENT_OTHERS] = "Other battery events"
+};
+
/*
* Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for
* delayed works so that we can run delayed works with CM_JIFFIES_SMALL
@@ -530,6 +540,68 @@ static void cm_monitor_poller(struct work_struct *work)
schedule_work(&setup_polling);
}
+/**
+ * fullbatt_handler - Event handler for CM_EVENT_BATT_FULL
+ * @cm: the Charger Manager representing the battery.
+ */
+static void fullbatt_handler(struct charger_manager *cm)
+{
+ struct charger_desc *desc = cm->desc;
+
+ if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms)
+ goto out;
+
+ if (cm_suspended)
+ cm->cancel_suspend = true;
+
+ cancel_delayed_work(&cm->fullbatt_vchk_work);
+ queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
+ msecs_to_jiffies(desc->fullbatt_vchkdrop_ms));
+ cm->fullbatt_vchk_jiffies_at = jiffies + msecs_to_jiffies(
+ desc->fullbatt_vchkdrop_ms);
+
+ if (cm->fullbatt_vchk_jiffies_at == 0)
+ cm->fullbatt_vchk_jiffies_at = 1;
+
+out:
+ dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n");
+ uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]);
+}
+
+/**
+ * battout_handler - Event handler for CM_EVENT_BATT_OUT
+ * @cm: the Charger Manager representing the battery.
+ */
+static void battout_handler(struct charger_manager *cm)
+{
+ if (cm_suspended)
+ cm->cancel_suspend = true;
+
+ if (!is_batt_present(cm)) {
+ dev_emerg(cm->dev, "Battery Pulled Out!\n");
+ uevent_notify(cm, default_event_names[CM_EVENT_BATT_OUT]);
+ } else {
+ uevent_notify(cm, "Battery Reinserted?");
+ }
+}
+
+/**
+ * misc_event_handler - Handler for other evnets
+ * @cm: the Charger Manager representing the battery.
+ * @type: the Charger Manager representing the battery.
+ */
+static void misc_event_handler(struct charger_manager *cm,
+ enum cm_event_types type)
+{
+ if (cm_suspended)
+ cm->cancel_suspend = true;
+
+ if (!delayed_work_pending(&cm_monitor_work) &&
+ is_polling_required(cm) && cm->desc->polling_interval_ms)
+ schedule_work(&setup_polling);
+ uevent_notify(cm, default_event_names[type]);
+}
+
static int charger_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -1175,6 +1247,20 @@ static const struct platform_device_id charger_manager_id[] = {
};
MODULE_DEVICE_TABLE(platform, charger_manager_id);
+static int cm_suspend_noirq(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct charger_manager *cm = platform_get_drvdata(pdev);
+
+ if (cm->cancel_suspend) {
+ cm->cancel_suspend = false;
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
static int cm_suspend_prepare(struct device *dev)
{
struct platform_device *pdev = container_of(dev, struct platform_device,
@@ -1260,11 +1346,13 @@ static void cm_suspend_complete(struct device *dev)
queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
msecs_to_jiffies(delay));
}
+ cm->cancel_suspend = false;
uevent_notify(cm, NULL);
}
static const struct dev_pm_ops charger_manager_pm = {
.prepare = cm_suspend_prepare,
+ .suspend_noirq = cm_suspend_noirq,
.complete = cm_suspend_complete,
};
@@ -1297,6 +1385,75 @@ static void __exit charger_manager_cleanup(void)
}
module_exit(charger_manager_cleanup);
+/**
+ * find_power_supply - find the associated power_supply of charger
+ * @cm: the Charger Manager representing the battery
+ * @psy: pointer to instance of charger's power_supply
+ */
+static bool find_power_supply(struct charger_manager *cm,
+ struct power_supply *psy)
+{
+ int i;
+ bool found = false;
+
+ for (i = 0; cm->charger_stat[i]; i++) {
+ if (psy == cm->charger_stat[i]) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
+/**
+ * cm_notify_event - charger driver notify Charger Manager of charger event
+ * @psy: pointer to instance of charger's power_supply
+ * @type: type of charger event
+ * @msg: optional message passed to uevent_notify fuction
+ */
+void cm_notify_event(struct power_supply *psy, enum cm_event_types type,
+ char *msg)
+{
+ struct charger_manager *cm;
+ bool found_power_supply = false;
+
+ if (psy == NULL)
+ return;
+
+ mutex_lock(&cm_list_mtx);
+ list_for_each_entry(cm, &cm_list, entry) {
+ found_power_supply = find_power_supply(cm, psy);
+ if (found_power_supply)
+ break;
+ }
+ mutex_unlock(&cm_list_mtx);
+
+ if (!found_power_supply)
+ return;
+
+ switch (type) {
+ case CM_EVENT_BATT_FULL:
+ fullbatt_handler(cm);
+ break;
+ case CM_EVENT_BATT_OUT:
+ battout_handler(cm);
+ break;
+ case CM_EVENT_BATT_IN:
+ case CM_EVENT_EXT_PWR_IN_OUT ... CM_EVENT_CHG_START_STOP:
+ misc_event_handler(cm, type);
+ break;
+ case CM_EVENT_UNDESCRIBED:
+ case CM_EVENT_OTHERS:
+ uevent_notify(cm, msg ? msg : default_event_names[type]);
+ break;
+ default:
+ dev_err(cm->dev, "%s type not specified.\n", __func__);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(cm_notify_event);
+
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@...sung.com>");
MODULE_DESCRIPTION("Charger Manager");
MODULE_LICENSE("GPL");
diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h
index 78b9865..086917c 100644
--- a/include/linux/power/charger-manager.h
+++ b/include/linux/power/charger-manager.h
@@ -31,6 +31,16 @@ enum polling_modes {
CM_POLL_CHARGING_ONLY,
};
+enum cm_event_types {
+ CM_EVENT_UNDESCRIBED = 0,
+ CM_EVENT_BATT_FULL,
+ CM_EVENT_BATT_IN,
+ CM_EVENT_BATT_OUT,
+ CM_EVENT_EXT_PWR_IN_OUT,
+ CM_EVENT_CHG_START_STOP,
+ CM_EVENT_OTHERS,
+};
+
/**
* struct charger_global_desc
* @rtc_name: the name of RTC used to wake up the system from suspend.
@@ -116,6 +126,7 @@ struct charger_desc {
* @desc: instance of charger_desc
* @fuel_gauge: power_supply for fuel gauge
* @charger_stat: array of power_supply for chargers
+ * @cancel_suspend: true if there is a pending charger event
* @charger_enabled: the state of charger
* @fullbatt_vchk_jiffies_at:
* jiffies at the time full battery check will occur.
@@ -140,6 +151,7 @@ struct charger_manager {
struct power_supply *fuel_gauge;
struct power_supply **charger_stat;
+ bool cancel_suspend;
bool charger_enabled;
unsigned long fullbatt_vchk_jiffies_at;
@@ -159,6 +171,8 @@ struct charger_manager {
#ifdef CONFIG_CHARGER_MANAGER
extern int setup_charger_manager(struct charger_global_desc *gd);
extern bool cm_suspend_again(void);
+extern void cm_notify_event(struct power_supply *psy, enum cm_event_types type,
+ char *msg); /* msg: optional */
#else
static void __maybe_unused setup_charger_manager(struct charger_global_desc *gd)
{ }
@@ -167,6 +181,10 @@ static bool __maybe_unused cm_suspend_again(void)
{
return false;
}
+
+static void __maybe_unused cm_notify_event(struct power_supply *psy,
+ enum cm_event_types type, char *msg)
+{ }
#endif
#endif /* _CHARGER_MANAGER_H */
--
1.7.4.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists