]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/base/power/opp/core.c
PM / OPP: Add infrastructure to manage multiple regulators
[mirror_ubuntu-artful-kernel.git] / drivers / base / power / opp / core.c
index 4c7c6da7a989187e32efbb284f3daeb518ca0435..b4da31c5a5eb4a27dc25ce214420f0f9833bca32 100644 (file)
@@ -93,6 +93,8 @@ struct opp_table *_find_opp_table(struct device *dev)
  * Return: voltage in micro volt corresponding to the opp, else
  * return 0
  *
+ * This is useful only for devices with single power supply.
+ *
  * Locking: This function must be called under rcu_read_lock(). opp is a rcu
  * protected pointer. This means that opp which could have been fetched by
  * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
@@ -112,7 +114,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
        if (IS_ERR_OR_NULL(tmp_opp))
                pr_err("%s: Invalid parameters\n", __func__);
        else
-               v = tmp_opp->u_volt;
+               v = tmp_opp->supplies[0].u_volt;
 
        return v;
 }
@@ -210,6 +212,24 @@ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
 
+static int _get_regulator_count(struct device *dev)
+{
+       struct opp_table *opp_table;
+       int count;
+
+       rcu_read_lock();
+
+       opp_table = _find_opp_table(dev);
+       if (!IS_ERR(opp_table))
+               count = opp_table->regulator_count;
+       else
+               count = 0;
+
+       rcu_read_unlock();
+
+       return count;
+}
+
 /**
  * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
  * @dev: device for which we do this operation
@@ -222,34 +242,51 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
 {
        struct opp_table *opp_table;
        struct dev_pm_opp *opp;
-       struct regulator *reg;
+       struct regulator *reg, **regulators;
        unsigned long latency_ns = 0;
-       unsigned long min_uV = ~0, max_uV = 0;
-       int ret;
+       int ret, i, count;
+       struct {
+               unsigned long min;
+               unsigned long max;
+       } *uV;
+
+       count = _get_regulator_count(dev);
+
+       /* Regulator may not be required for the device */
+       if (!count)
+               return 0;
+
+       regulators = kmalloc_array(count, sizeof(*regulators), GFP_KERNEL);
+       if (!regulators)
+               return 0;
+
+       uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
+       if (!uV)
+               goto free_regulators;
 
        rcu_read_lock();
 
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table)) {
                rcu_read_unlock();
-               return 0;
+               goto free_uV;
        }
 
-       reg = opp_table->regulator;
-       if (IS_ERR(reg)) {
-               /* Regulator may not be required for device */
-               rcu_read_unlock();
-               return 0;
-       }
+       memcpy(regulators, opp_table->regulators, count * sizeof(*regulators));
 
-       list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
-               if (!opp->available)
-                       continue;
+       for (i = 0; i < count; i++) {
+               uV[i].min = ~0;
+               uV[i].max = 0;
 
-               if (opp->u_volt_min < min_uV)
-                       min_uV = opp->u_volt_min;
-               if (opp->u_volt_max > max_uV)
-                       max_uV = opp->u_volt_max;
+               list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
+                       if (!opp->available)
+                               continue;
+
+                       if (opp->supplies[i].u_volt_min < uV[i].min)
+                               uV[i].min = opp->supplies[i].u_volt_min;
+                       if (opp->supplies[i].u_volt_max > uV[i].max)
+                               uV[i].max = opp->supplies[i].u_volt_max;
+               }
        }
 
        rcu_read_unlock();
@@ -258,9 +295,16 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
         * The caller needs to ensure that opp_table (and hence the regulator)
         * isn't freed, while we are executing this routine.
         */
-       ret = regulator_set_voltage_time(reg, min_uV, max_uV);
-       if (ret > 0)
-               latency_ns = ret * 1000;
+       for (i = 0; reg = regulators[i], i < count; i++) {
+               ret = regulator_set_voltage_time(reg, uV[i].min, uV[i].max);
+               if (ret > 0)
+                       latency_ns += ret * 1000;
+       }
+
+free_uV:
+       kfree(uV);
+free_regulators:
+       kfree(regulators);
 
        return latency_ns;
 }
@@ -542,8 +586,7 @@ unlock:
 }
 
 static int _set_opp_voltage(struct device *dev, struct regulator *reg,
-                           unsigned long u_volt, unsigned long u_volt_min,
-                           unsigned long u_volt_max)
+                           struct dev_pm_opp_supply *supply)
 {
        int ret;
 
@@ -554,14 +597,15 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
                return 0;
        }
 
-       dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, u_volt_min,
-               u_volt, u_volt_max);
+       dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__,
+               supply->u_volt_min, supply->u_volt, supply->u_volt_max);
 
-       ret = regulator_set_voltage_triplet(reg, u_volt_min, u_volt,
-                                           u_volt_max);
+       ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
+                                           supply->u_volt, supply->u_volt_max);
        if (ret)
                dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n",
-                       __func__, u_volt_min, u_volt, u_volt_max, ret);
+                       __func__, supply->u_volt_min, supply->u_volt,
+                       supply->u_volt_max, ret);
 
        return ret;
 }
@@ -580,10 +624,10 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 {
        struct opp_table *opp_table;
        struct dev_pm_opp *old_opp, *opp;
-       struct regulator *reg;
+       struct regulator *reg = ERR_PTR(-ENXIO);
        struct clk *clk;
        unsigned long freq, old_freq;
-       unsigned long u_volt, u_volt_min, u_volt_max;
+       struct dev_pm_opp_supply old_supply, new_supply;
        int ret;
 
        if (unlikely(!target_freq)) {
@@ -633,18 +677,29 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                return ret;
        }
 
-       u_volt = opp->u_volt;
-       u_volt_min = opp->u_volt_min;
-       u_volt_max = opp->u_volt_max;
+       if (opp_table->regulators) {
+               /* This function only supports single regulator per device */
+               if (WARN_ON(opp_table->regulator_count > 1)) {
+                       dev_err(dev, "multiple regulators not supported\n");
+                       rcu_read_unlock();
+                       return -EINVAL;
+               }
+
+               reg = opp_table->regulators[0];
+       }
+
+       if (IS_ERR(old_opp))
+               old_supply.u_volt = 0;
+       else
+               memcpy(&old_supply, old_opp->supplies, sizeof(old_supply));
 
-       reg = opp_table->regulator;
+       memcpy(&new_supply, opp->supplies, sizeof(new_supply));
 
        rcu_read_unlock();
 
        /* Scaling up? Scale voltage before frequency */
        if (freq > old_freq) {
-               ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
-                                      u_volt_max);
+               ret = _set_opp_voltage(dev, reg, &new_supply);
                if (ret)
                        goto restore_voltage;
        }
@@ -663,8 +718,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 
        /* Scaling down? Scale voltage after frequency */
        if (freq < old_freq) {
-               ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
-                                      u_volt_max);
+               ret = _set_opp_voltage(dev, reg, &new_supply);
                if (ret)
                        goto restore_freq;
        }
@@ -677,9 +731,8 @@ restore_freq:
                        __func__, old_freq);
 restore_voltage:
        /* This shouldn't harm even if the voltages weren't updated earlier */
-       if (!IS_ERR(old_opp))
-               _set_opp_voltage(dev, reg, old_opp->u_volt,
-                                old_opp->u_volt_min, old_opp->u_volt_max);
+       if (old_supply.u_volt)
+               _set_opp_voltage(dev, reg, &old_supply);
 
        return ret;
 }
@@ -764,9 +817,6 @@ static struct opp_table *_add_opp_table(struct device *dev)
 
        _of_init_opp_table(opp_table, dev);
 
-       /* Set regulator to a non-NULL error value */
-       opp_table->regulator = ERR_PTR(-ENXIO);
-
        /* Find clk for the device */
        opp_table->clk = clk_get(dev, NULL);
        if (IS_ERR(opp_table->clk)) {
@@ -815,7 +865,7 @@ static void _remove_opp_table(struct opp_table *opp_table)
        if (opp_table->prop_name)
                return;
 
-       if (!IS_ERR(opp_table->regulator))
+       if (opp_table->regulators)
                return;
 
        /* Release clk */
@@ -924,34 +974,50 @@ struct dev_pm_opp *_allocate_opp(struct device *dev,
                                 struct opp_table **opp_table)
 {
        struct dev_pm_opp *opp;
+       int count, supply_size;
+       struct opp_table *table;
 
-       /* allocate new OPP node */
-       opp = kzalloc(sizeof(*opp), GFP_KERNEL);
-       if (!opp)
+       table = _add_opp_table(dev);
+       if (!table)
                return NULL;
 
-       INIT_LIST_HEAD(&opp->node);
+       /* Allocate space for at least one supply */
+       count = table->regulator_count ? table->regulator_count : 1;
+       supply_size = sizeof(*opp->supplies) * count;
 
-       *opp_table = _add_opp_table(dev);
-       if (!*opp_table) {
-               kfree(opp);
+       /* allocate new OPP node and supplies structures */
+       opp = kzalloc(sizeof(*opp) + supply_size, GFP_KERNEL);
+       if (!opp) {
+               kfree(table);
                return NULL;
        }
 
+       /* Put the supplies at the end of the OPP structure as an empty array */
+       opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
+       INIT_LIST_HEAD(&opp->node);
+
+       *opp_table = table;
+
        return opp;
 }
 
 static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
                                         struct opp_table *opp_table)
 {
-       struct regulator *reg = opp_table->regulator;
-
-       if (!IS_ERR(reg) &&
-           !regulator_is_supported_voltage(reg, opp->u_volt_min,
-                                           opp->u_volt_max)) {
-               pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
-                       __func__, opp->u_volt_min, opp->u_volt_max);
-               return false;
+       struct regulator *reg;
+       int i;
+
+       for (i = 0; i < opp_table->regulator_count; i++) {
+               reg = opp_table->regulators[i];
+
+               if (!regulator_is_supported_voltage(reg,
+                                       opp->supplies[i].u_volt_min,
+                                       opp->supplies[i].u_volt_max)) {
+                       pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
+                               __func__, opp->supplies[i].u_volt_min,
+                               opp->supplies[i].u_volt_max);
+                       return false;
+               }
        }
 
        return true;
@@ -983,11 +1049,13 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
 
                /* Duplicate OPPs */
                dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
-                        __func__, opp->rate, opp->u_volt, opp->available,
-                        new_opp->rate, new_opp->u_volt, new_opp->available);
+                        __func__, opp->rate, opp->supplies[0].u_volt,
+                        opp->available, new_opp->rate,
+                        new_opp->supplies[0].u_volt, new_opp->available);
 
-               return opp->available && new_opp->u_volt == opp->u_volt ?
-                       0 : -EEXIST;
+               /* Should we compare voltages for all regulators here ? */
+               return opp->available &&
+                      new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 0 : -EEXIST;
        }
 
        new_opp->opp_table = opp_table;
@@ -1054,9 +1122,9 @@ int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
        /* populate the opp table */
        new_opp->rate = freq;
        tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
-       new_opp->u_volt = u_volt;
-       new_opp->u_volt_min = u_volt - tol;
-       new_opp->u_volt_max = u_volt + tol;
+       new_opp->supplies[0].u_volt = u_volt;
+       new_opp->supplies[0].u_volt_min = u_volt - tol;
+       new_opp->supplies[0].u_volt_max = u_volt + tol;
        new_opp->available = true;
        new_opp->dynamic = dynamic;
 
@@ -1301,12 +1369,14 @@ unlock:
 EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
 
 /**
- * dev_pm_opp_set_regulator() - Set regulator name for the device
+ * dev_pm_opp_set_regulators() - Set regulator names for the device
  * @dev: Device for which regulator name is being set.
- * @name: Name of the regulator.
+ * @names: Array of pointers to the names of the regulator.
+ * @count: Number of regulators.
  *
  * In order to support OPP switching, OPP layer needs to know the name of the
- * device's regulator, as the core would be required to switch voltages as well.
+ * device's regulators, as the core would be required to switch voltages as
+ * well.
  *
  * This must be called before any OPPs are initialized for the device.
  *
@@ -1316,11 +1386,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
  * that this function is *NOT* called under RCU protection or in contexts where
  * mutex cannot be locked.
  */
-int dev_pm_opp_set_regulator(struct device *dev, const char *name)
+struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
+                                           const char * const names[],
+                                           unsigned int count)
 {
        struct opp_table *opp_table;
        struct regulator *reg;
-       int ret;
+       int ret, i;
 
        mutex_lock(&opp_table_lock);
 
@@ -1336,38 +1408,56 @@ int dev_pm_opp_set_regulator(struct device *dev, const char *name)
                goto err;
        }
 
-       /* Already have a regulator set */
-       if (WARN_ON(!IS_ERR(opp_table->regulator))) {
+       /* Already have regulators set */
+       if (WARN_ON(opp_table->regulators)) {
                ret = -EBUSY;
                goto err;
        }
-       /* Allocate the regulator */
-       reg = regulator_get_optional(dev, name);
-       if (IS_ERR(reg)) {
-               ret = PTR_ERR(reg);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "%s: no regulator (%s) found: %d\n",
-                               __func__, name, ret);
+
+       opp_table->regulators = kmalloc_array(count,
+                                             sizeof(*opp_table->regulators),
+                                             GFP_KERNEL);
+       if (!opp_table->regulators) {
+               ret = -ENOMEM;
                goto err;
        }
 
-       opp_table->regulator = reg;
+       for (i = 0; i < count; i++) {
+               reg = regulator_get_optional(dev, names[i]);
+               if (IS_ERR(reg)) {
+                       ret = PTR_ERR(reg);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "%s: no regulator (%s) found: %d\n",
+                                       __func__, names[i], ret);
+                       goto free_regulators;
+               }
+
+               opp_table->regulators[i] = reg;
+       }
+
+       opp_table->regulator_count = count;
 
        mutex_unlock(&opp_table_lock);
-       return 0;
+       return opp_table;
+
+free_regulators:
+       while (i != 0)
+               regulator_put(opp_table->regulators[--i]);
 
+       kfree(opp_table->regulators);
+       opp_table->regulators = NULL;
 err:
        _remove_opp_table(opp_table);
 unlock:
        mutex_unlock(&opp_table_lock);
 
-       return ret;
+       return ERR_PTR(ret);
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
 
 /**
- * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
- * @dev: Device for which regulator was set.
+ * dev_pm_opp_put_regulators() - Releases resources blocked for regulator
+ * @opp_table: OPP table returned from dev_pm_opp_set_regulators().
  *
  * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function internally uses RCU updater strategy with mutex locks
@@ -1375,30 +1465,26 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
  * that this function is *NOT* called under RCU protection or in contexts where
  * mutex cannot be locked.
  */
-void dev_pm_opp_put_regulator(struct device *dev)
+void dev_pm_opp_put_regulators(struct opp_table *opp_table)
 {
-       struct opp_table *opp_table;
+       int i;
 
        mutex_lock(&opp_table_lock);
 
-       /* Check for existing table for 'dev' first */
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               dev_err(dev, "Failed to find opp_table: %ld\n",
-                       PTR_ERR(opp_table));
-               goto unlock;
-       }
-
-       if (IS_ERR(opp_table->regulator)) {
-               dev_err(dev, "%s: Doesn't have regulator set\n", __func__);
+       if (!opp_table->regulators) {
+               pr_err("%s: Doesn't have regulators set\n", __func__);
                goto unlock;
        }
 
        /* Make sure there are no concurrent readers while updating opp_table */
        WARN_ON(!list_empty(&opp_table->opp_list));
 
-       regulator_put(opp_table->regulator);
-       opp_table->regulator = ERR_PTR(-ENXIO);
+       for (i = opp_table->regulator_count - 1; i >= 0; i--)
+               regulator_put(opp_table->regulators[i]);
+
+       kfree(opp_table->regulators);
+       opp_table->regulators = NULL;
+       opp_table->regulator_count = 0;
 
        /* Try freeing opp_table if this was the last blocking resource */
        _remove_opp_table(opp_table);
@@ -1406,7 +1492,7 @@ void dev_pm_opp_put_regulator(struct device *dev)
 unlock:
        mutex_unlock(&opp_table_lock);
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
 
 /**
  * dev_pm_opp_add()  - Add an OPP table from a table definitions