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>
This commit is contained in:
parent
d829dc75ba
commit
dfeccb12b4
@ -50,6 +50,10 @@ Charger Manager supports the following:
|
|||||||
restarts charging. This check is also performed while suspended by
|
restarts charging. This check is also performed while suspended by
|
||||||
setting wakeup time accordingly and using suspend_again.
|
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
|
2. Global Charger-Manager Data related with suspend_again
|
||||||
========================================================
|
========================================================
|
||||||
In order to setup Charger Manager with suspend-again feature
|
In order to setup Charger Manager with suspend-again feature
|
||||||
@ -174,7 +178,17 @@ bool measure_battery_temp;
|
|||||||
the value of 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,
|
At the charger/battery-related events such as battery-pulled-out,
|
||||||
|
@ -23,6 +23,16 @@
|
|||||||
#include <linux/power/charger-manager.h>
|
#include <linux/power/charger-manager.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
|
static const char * const default_event_names[] = {
|
||||||
|
[CM_EVENT_UNKNOWN] = "Unknown",
|
||||||
|
[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
|
* Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for
|
||||||
* delayed works so that we can run delayed works with CM_JIFFIES_SMALL
|
* 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)
|
|||||||
schedule_work(&setup_polling);
|
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)
|
||||||
|
device_set_wakeup_capable(cm->dev, true);
|
||||||
|
|
||||||
|
if (delayed_work_pending(&cm->fullbatt_vchk_work))
|
||||||
|
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)
|
||||||
|
device_set_wakeup_capable(cm->dev, 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)
|
||||||
|
device_set_wakeup_capable(cm->dev, 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,
|
static int charger_get_property(struct power_supply *psy,
|
||||||
enum power_supply_property psp,
|
enum power_supply_property psp,
|
||||||
union power_supply_propval *val)
|
union power_supply_propval *val)
|
||||||
@ -1112,6 +1185,13 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||||||
list_add(&cm->entry, &cm_list);
|
list_add(&cm->entry, &cm_list);
|
||||||
mutex_unlock(&cm_list_mtx);
|
mutex_unlock(&cm_list_mtx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Charger-manager is capable of waking up the systme from sleep
|
||||||
|
* when event is happend through cm_notify_event()
|
||||||
|
*/
|
||||||
|
device_init_wakeup(&pdev->dev, true);
|
||||||
|
device_set_wakeup_capable(&pdev->dev, false);
|
||||||
|
|
||||||
schedule_work(&setup_polling);
|
schedule_work(&setup_polling);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1169,6 +1249,18 @@ static const struct platform_device_id charger_manager_id[] = {
|
|||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(platform, charger_manager_id);
|
MODULE_DEVICE_TABLE(platform, charger_manager_id);
|
||||||
|
|
||||||
|
static int cm_suspend_noirq(struct device *dev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev)) {
|
||||||
|
device_set_wakeup_capable(dev, false);
|
||||||
|
ret = -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int cm_suspend_prepare(struct device *dev)
|
static int cm_suspend_prepare(struct device *dev)
|
||||||
{
|
{
|
||||||
struct charger_manager *cm = dev_get_drvdata(dev);
|
struct charger_manager *cm = dev_get_drvdata(dev);
|
||||||
@ -1250,11 +1342,13 @@ static void cm_suspend_complete(struct device *dev)
|
|||||||
queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
|
queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
|
||||||
msecs_to_jiffies(delay));
|
msecs_to_jiffies(delay));
|
||||||
}
|
}
|
||||||
|
device_set_wakeup_capable(cm->dev, false);
|
||||||
uevent_notify(cm, NULL);
|
uevent_notify(cm, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops charger_manager_pm = {
|
static const struct dev_pm_ops charger_manager_pm = {
|
||||||
.prepare = cm_suspend_prepare,
|
.prepare = cm_suspend_prepare,
|
||||||
|
.suspend_noirq = cm_suspend_noirq,
|
||||||
.complete = cm_suspend_complete,
|
.complete = cm_suspend_complete,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1287,6 +1381,75 @@ static void __exit charger_manager_cleanup(void)
|
|||||||
}
|
}
|
||||||
module_exit(charger_manager_cleanup);
|
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_UNKNOWN:
|
||||||
|
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@samsung.com>");
|
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
|
||||||
MODULE_DESCRIPTION("Charger Manager");
|
MODULE_DESCRIPTION("Charger Manager");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -31,6 +31,16 @@ enum polling_modes {
|
|||||||
CM_POLL_CHARGING_ONLY,
|
CM_POLL_CHARGING_ONLY,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum cm_event_types {
|
||||||
|
CM_EVENT_UNKNOWN = 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
|
* struct charger_global_desc
|
||||||
* @rtc_name: the name of RTC used to wake up the system from suspend.
|
* @rtc_name: the name of RTC used to wake up the system from suspend.
|
||||||
@ -159,14 +169,13 @@ struct charger_manager {
|
|||||||
#ifdef CONFIG_CHARGER_MANAGER
|
#ifdef CONFIG_CHARGER_MANAGER
|
||||||
extern int setup_charger_manager(struct charger_global_desc *gd);
|
extern int setup_charger_manager(struct charger_global_desc *gd);
|
||||||
extern bool cm_suspend_again(void);
|
extern bool cm_suspend_again(void);
|
||||||
|
extern void cm_notify_event(struct power_supply *psy,
|
||||||
|
enum cm_event_types type, char *msg);
|
||||||
#else
|
#else
|
||||||
static void __maybe_unused setup_charger_manager(struct charger_global_desc *gd)
|
static inline int setup_charger_manager(struct charger_global_desc *gd)
|
||||||
{ }
|
{ return 0; }
|
||||||
|
static inline bool cm_suspend_again(void) { return false; }
|
||||||
static bool __maybe_unused cm_suspend_again(void)
|
static inline void cm_notify_event(struct power_supply *psy,
|
||||||
{
|
enum cm_event_types type, char *msg) { }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _CHARGER_MANAGER_H */
|
#endif /* _CHARGER_MANAGER_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user