]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/regulator/core.c
Merge remote-tracking branch 'regulator/topic/core' into regulator-next
[karo-tx-linux.git] / drivers / regulator / core.c
index 16427de56ce83513883797fdb5f900245634b51a..916cadf45279289e1fc6b6106b7ff3f7ee580308 100644 (file)
@@ -919,6 +919,36 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
        return 0;
 }
 
+static int machine_constraints_current(struct regulator_dev *rdev,
+       struct regulation_constraints *constraints)
+{
+       struct regulator_ops *ops = rdev->desc->ops;
+       int ret;
+
+       if (!constraints->min_uA && !constraints->max_uA)
+               return 0;
+
+       if (constraints->min_uA > constraints->max_uA) {
+               rdev_err(rdev, "Invalid current constraints\n");
+               return -EINVAL;
+       }
+
+       if (!ops->set_current_limit || !ops->get_current_limit) {
+               rdev_warn(rdev, "Operation of current configuration missing\n");
+               return 0;
+       }
+
+       /* Set regulator current in constraints range */
+       ret = ops->set_current_limit(rdev, constraints->min_uA,
+                       constraints->max_uA);
+       if (ret < 0) {
+               rdev_err(rdev, "Failed to set current constraint, %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -949,6 +979,10 @@ static int set_machine_constraints(struct regulator_dev *rdev,
        if (ret != 0)
                goto out;
 
+       ret = machine_constraints_current(rdev, rdev->constraints);
+       if (ret != 0)
+               goto out;
+
        /* do we need to setup our suspend state */
        if (rdev->constraints->initial_state) {
                ret = suspend_prepare(rdev, rdev->constraints->initial_state);
@@ -1182,6 +1216,8 @@ overflow_err:
 
 static int _regulator_get_enable_time(struct regulator_dev *rdev)
 {
+       if (rdev->constraints && rdev->constraints->enable_time)
+               return rdev->constraints->enable_time;
        if (!rdev->desc->ops->enable_time)
                return rdev->desc->enable_time;
        return rdev->desc->ops->enable_time(rdev);
@@ -1276,7 +1312,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
 
        if (id == NULL) {
                pr_err("get() with no identifier\n");
-               return regulator;
+               return ERR_PTR(-EINVAL);
        }
 
        if (dev)
@@ -1733,11 +1769,39 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
         * together.  */
        trace_regulator_enable_delay(rdev_get_name(rdev));
 
-       if (delay >= 1000) {
-               mdelay(delay / 1000);
-               udelay(delay % 1000);
-       } else if (delay) {
-               udelay(delay);
+       /*
+        * Delay for the requested amount of time as per the guidelines in:
+        *
+        *     Documentation/timers/timers-howto.txt
+        *
+        * The assumption here is that regulators will never be enabled in
+        * atomic context and therefore sleeping functions can be used.
+        */
+       if (delay) {
+               unsigned int ms = delay / 1000;
+               unsigned int us = delay % 1000;
+
+               if (ms > 0) {
+                       /*
+                        * For small enough values, handle super-millisecond
+                        * delays in the usleep_range() call below.
+                        */
+                       if (ms < 20)
+                               us += ms * 1000;
+                       else
+                               msleep(ms);
+               }
+
+               /*
+                * Give the scheduler some room to coalesce with any other
+                * wakeup sources. For delays shorter than 10 us, don't even
+                * bother setting up high-resolution timers and just busy-
+                * loop.
+                */
+               if (us >= 10)
+                       usleep_range(us, us + 100);
+               else
+                       udelay(us);
        }
 
        trace_regulator_enable_complete(rdev_get_name(rdev));