power_supply: Add power_supply notifier
authorPali Rohár <pali.rohar@gmail.com>
Tue, 19 Nov 2013 10:18:03 +0000 (11:18 +0100)
committerAnton Vorontsov <anton@enomsg.org>
Sun, 1 Dec 2013 22:27:24 +0000 (14:27 -0800)
This patch adds a notifier chain to the power_supply, this helps drivers
in other subsystem to listen to changes in power supply subsystem.

This would help to take some actions in those drivers on changing the
power supply properties. One such scenario is to increase/decrease system
performance based on the battery capacity/voltage. Another scenario is to
adjust the h/w peak current detection voltage/current thresholds based on
battery voltage/capacity. The notifier helps drivers to listen to changes
in power_suppy susbystem without polling the power_supply properties

Signed-off-by: Jenny TC <jenny.tc@intel.com>
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
Acked-by: Jenny TC <jenny.tc@intel.com>
Signed-off-by: Anton Vorontsov <anton@enomsg.org>
drivers/power/power_supply_core.c
include/linux/power_supply.h

index 557af943b2f53d0a3ee2a280122e42e69db94c67..6aac23cc65663ada046958869dc6d5b8b32e9648 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/device.h>
+#include <linux/notifier.h>
 #include <linux/err.h>
 #include <linux/power_supply.h>
 #include <linux/thermal.h>
@@ -24,6 +25,9 @@
 struct class *power_supply_class;
 EXPORT_SYMBOL_GPL(power_supply_class);
 
+ATOMIC_NOTIFIER_HEAD(power_supply_notifier);
+EXPORT_SYMBOL_GPL(power_supply_notifier);
+
 static struct device_type power_supply_dev_type;
 
 static bool __power_supply_is_supplied_by(struct power_supply *supplier,
@@ -80,6 +84,8 @@ static void power_supply_changed_work(struct work_struct *work)
                class_for_each_device(power_supply_class, NULL, psy,
                                      __power_supply_changed_work);
                power_supply_update_leds(psy);
+               atomic_notifier_call_chain(&power_supply_notifier,
+                               PSY_EVENT_PROP_CHANGED, psy);
                kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
                spin_lock_irqsave(&psy->changed_lock, flags);
        }
@@ -347,6 +353,18 @@ static void power_supply_dev_release(struct device *dev)
        kfree(dev);
 }
 
+int power_supply_reg_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&power_supply_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(power_supply_reg_notifier);
+
+void power_supply_unreg_notifier(struct notifier_block *nb)
+{
+       atomic_notifier_chain_unregister(&power_supply_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(power_supply_unreg_notifier);
+
 #ifdef CONFIG_THERMAL
 static int power_supply_read_temp(struct thermal_zone_device *tzd,
                unsigned long *temp)
index 5c2600630dc99ace79f3d001416db6d37f568806..3e28fe188d171a11f224fcdc36975a031c7146b2 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/workqueue.h>
 #include <linux/leds.h>
 #include <linux/spinlock.h>
+#include <linux/notifier.h>
 
 struct device;
 
@@ -158,6 +159,10 @@ enum power_supply_type {
        POWER_SUPPLY_TYPE_USB_ACA,      /* Accessory Charger Adapters */
 };
 
+enum power_supply_notifier_events {
+       PSY_EVENT_PROP_CHANGED,
+};
+
 union power_supply_propval {
        int intval;
        const char *strval;
@@ -235,6 +240,9 @@ struct power_supply_info {
        int use_for_apm;
 };
 
+extern struct atomic_notifier_head power_supply_notifier;
+extern int power_supply_reg_notifier(struct notifier_block *nb);
+extern void power_supply_unreg_notifier(struct notifier_block *nb);
 extern struct power_supply *power_supply_get_by_name(const char *name);
 extern void power_supply_changed(struct power_supply *psy);
 extern int power_supply_am_i_supplied(struct power_supply *psy);