Merge tag 'media/v4.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[cascardo/linux.git] / drivers / power / power_supply_core.c
index 2ed4a4a..869284c 100644 (file)
@@ -30,6 +30,8 @@ EXPORT_SYMBOL_GPL(power_supply_notifier);
 
 static struct device_type power_supply_dev_type;
 
+#define POWER_SUPPLY_DEFERRED_REGISTER_TIME    msecs_to_jiffies(10)
+
 static bool __power_supply_is_supplied_by(struct power_supply *supplier,
                                         struct power_supply *supply)
 {
@@ -121,6 +123,30 @@ void power_supply_changed(struct power_supply *psy)
 }
 EXPORT_SYMBOL_GPL(power_supply_changed);
 
+/*
+ * Notify that power supply was registered after parent finished the probing.
+ *
+ * Often power supply is registered from driver's probe function. However
+ * calling power_supply_changed() directly from power_supply_register()
+ * would lead to execution of get_property() function provided by the driver
+ * too early - before the probe ends.
+ *
+ * Avoid that by waiting on parent's mutex.
+ */
+static void power_supply_deferred_register_work(struct work_struct *work)
+{
+       struct power_supply *psy = container_of(work, struct power_supply,
+                                               deferred_register_work.work);
+
+       if (psy->dev.parent)
+               mutex_lock(&psy->dev.parent->mutex);
+
+       power_supply_changed(psy);
+
+       if (psy->dev.parent)
+               mutex_unlock(&psy->dev.parent->mutex);
+}
+
 #ifdef CONFIG_OF
 #include <linux/of.h>
 
@@ -420,6 +446,45 @@ struct power_supply *power_supply_get_by_phandle(struct device_node *np,
        return psy;
 }
 EXPORT_SYMBOL_GPL(power_supply_get_by_phandle);
+
+static void devm_power_supply_put(struct device *dev, void *res)
+{
+       struct power_supply **psy = res;
+
+       power_supply_put(*psy);
+}
+
+/**
+ * devm_power_supply_get_by_phandle() - Resource managed version of
+ *  power_supply_get_by_phandle()
+ * @dev: Pointer to device holding phandle property
+ * @phandle_name: Name of property holding a power supply phandle
+ *
+ * Return: On success returns a reference to a power supply with
+ * matching name equals to value under @property, NULL or ERR_PTR otherwise.
+ */
+struct power_supply *devm_power_supply_get_by_phandle(struct device *dev,
+                                                     const char *property)
+{
+       struct power_supply **ptr, *psy;
+
+       if (!dev->of_node)
+               return ERR_PTR(-ENODEV);
+
+       ptr = devres_alloc(devm_power_supply_put, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       psy = power_supply_get_by_phandle(dev->of_node, property);
+       if (IS_ERR_OR_NULL(psy)) {
+               devres_free(ptr);
+       } else {
+               *ptr = psy;
+               devres_add(dev, ptr);
+       }
+       return psy;
+}
+EXPORT_SYMBOL_GPL(devm_power_supply_get_by_phandle);
 #endif /* CONFIG_OF */
 
 int power_supply_get_property(struct power_supply *psy,
@@ -645,6 +710,10 @@ __power_supply_register(struct device *parent,
        struct power_supply *psy;
        int rc;
 
+       if (!parent)
+               pr_warn("%s: Expected proper parent device for '%s'\n",
+                       __func__, desc->name);
+
        psy = kzalloc(sizeof(*psy), GFP_KERNEL);
        if (!psy)
                return ERR_PTR(-ENOMEM);
@@ -659,7 +728,6 @@ __power_supply_register(struct device *parent,
        dev->release = power_supply_dev_release;
        dev_set_drvdata(dev, psy);
        psy->desc = desc;
-       atomic_inc(&psy->use_cnt);
        if (cfg) {
                psy->drv_data = cfg->drv_data;
                psy->of_node = cfg->of_node;
@@ -672,6 +740,8 @@ __power_supply_register(struct device *parent,
                goto dev_set_name_failed;
 
        INIT_WORK(&psy->changed_work, power_supply_changed_work);
+       INIT_DELAYED_WORK(&psy->deferred_register_work,
+                         power_supply_deferred_register_work);
 
        rc = power_supply_check_supplies(psy);
        if (rc) {
@@ -700,7 +770,20 @@ __power_supply_register(struct device *parent,
        if (rc)
                goto create_triggers_failed;
 
-       power_supply_changed(psy);
+       /*
+        * Update use_cnt after any uevents (most notably from device_add()).
+        * We are here still during driver's probe but
+        * the power_supply_uevent() calls back driver's get_property
+        * method so:
+        * 1. Driver did not assigned the returned struct power_supply,
+        * 2. Driver could not finish initialization (anything in its probe
+        *    after calling power_supply_register()).
+        */
+       atomic_inc(&psy->use_cnt);
+
+       queue_delayed_work(system_power_efficient_wq,
+                          &psy->deferred_register_work,
+                          POWER_SUPPLY_DEFERRED_REGISTER_TIME);
 
        return psy;
 
@@ -720,7 +803,8 @@ dev_set_name_failed:
 
 /**
  * power_supply_register() - Register new power supply
- * @parent:    Device to be a parent of power supply's device
+ * @parent:    Device to be a parent of power supply's device, usually
+ *             the device which probe function calls this
  * @desc:      Description of power supply, must be valid through whole
  *             lifetime of this power supply
  * @cfg:       Run-time specific configuration accessed during registering,
@@ -740,8 +824,9 @@ struct power_supply *__must_check power_supply_register(struct device *parent,
 EXPORT_SYMBOL_GPL(power_supply_register);
 
 /**
- * power_supply_register() - Register new non-waking-source power supply
- * @parent:    Device to be a parent of power supply's device
+ * power_supply_register_no_ws() - Register new non-waking-source power supply
+ * @parent:    Device to be a parent of power supply's device, usually
+ *             the device which probe function calls this
  * @desc:      Description of power supply, must be valid through whole
  *             lifetime of this power supply
  * @cfg:       Run-time specific configuration accessed during registering,
@@ -769,8 +854,9 @@ static void devm_power_supply_release(struct device *dev, void *res)
 }
 
 /**
- * power_supply_register() - Register managed power supply
- * @parent:    Device to be a parent of power supply's device
+ * devm_power_supply_register() - Register managed power supply
+ * @parent:    Device to be a parent of power supply's device, usually
+ *             the device which probe function calls this
  * @desc:      Description of power supply, must be valid through whole
  *             lifetime of this power supply
  * @cfg:       Run-time specific configuration accessed during registering,
@@ -804,8 +890,9 @@ devm_power_supply_register(struct device *parent,
 EXPORT_SYMBOL_GPL(devm_power_supply_register);
 
 /**
- * power_supply_register() - Register managed non-waking-source power supply
- * @parent:    Device to be a parent of power supply's device
+ * devm_power_supply_register_no_ws() - Register managed non-waking-source power supply
+ * @parent:    Device to be a parent of power supply's device, usually
+ *             the device which probe function calls this
  * @desc:      Description of power supply, must be valid through whole
  *             lifetime of this power supply
  * @cfg:       Run-time specific configuration accessed during registering,
@@ -849,6 +936,7 @@ void power_supply_unregister(struct power_supply *psy)
 {
        WARN_ON(atomic_dec_return(&psy->use_cnt));
        cancel_work_sync(&psy->changed_work);
+       cancel_delayed_work_sync(&psy->deferred_register_work);
        sysfs_remove_link(&psy->dev.kobj, "powers");
        power_supply_remove_triggers(psy);
        psy_unregister_cooler(psy);