Staging: hv: clean up NetVsc.h
[safe/jmp/linux-2.6] / drivers / regulator / core.c
index 019a8a4..98c3a74 100644 (file)
@@ -28,6 +28,7 @@
 static DEFINE_MUTEX(regulator_list_mutex);
 static LIST_HEAD(regulator_list);
 static LIST_HEAD(regulator_map_list);
+static int has_full_constraints;
 
 /*
  * struct regulator_map
@@ -52,7 +53,6 @@ struct regulator {
        int uA_load;
        int min_uV;
        int max_uV;
-       int enabled; /* count of client enables */
        char *supply_name;
        struct device_attribute dev_attr;
        struct regulator_dev *rdev;
@@ -540,8 +540,8 @@ static void drms_uA_update(struct regulator_dev *rdev)
 
        err = regulator_check_drms(rdev);
        if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
-           !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode);
-       return;
+           !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode)
+               return;
 
        /* get output voltage */
        output_uV = rdev->desc->ops->get_voltage(rdev);
@@ -703,10 +703,13 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                int     cmin = constraints->min_uV;
                int     cmax = constraints->max_uV;
 
-               /* it's safe to autoconfigure fixed-voltage supplies */
+               /* it's safe to autoconfigure fixed-voltage supplies
+                  and the constraints are used by list_voltage. */
                if (count == 1 && !cmin) {
-                       cmin = INT_MIN;
+                       cmin = 1;
                        cmax = INT_MAX;
+                       constraints->min_uV = cmin;
+                       constraints->max_uV = cmax;
                }
 
                /* voltage constraints are optional */
@@ -1068,10 +1071,6 @@ void regulator_put(struct regulator *regulator)
        mutex_lock(&regulator_list_mutex);
        rdev = regulator->rdev;
 
-       if (WARN(regulator->enabled, "Releasing supply %s while enabled\n",
-                              regulator->supply_name))
-               _regulator_disable(rdev);
-
        /* remove any sysfs entries */
        if (regulator->dev) {
                sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
@@ -1146,12 +1145,7 @@ int regulator_enable(struct regulator *regulator)
        int ret = 0;
 
        mutex_lock(&rdev->mutex);
-       if (regulator->enabled == 0)
-               ret = _regulator_enable(rdev);
-       else if (regulator->enabled < 0)
-               ret = -EIO;
-       if (ret == 0)
-               regulator->enabled++;
+       ret = _regulator_enable(rdev);
        mutex_unlock(&rdev->mutex);
        return ret;
 }
@@ -1162,6 +1156,11 @@ static int _regulator_disable(struct regulator_dev *rdev)
 {
        int ret = 0;
 
+       if (WARN(rdev->use_count <= 0,
+                       "unbalanced disables for %s\n",
+                       rdev->desc->name))
+               return -EIO;
+
        /* are we the last user and permitted to disable ? */
        if (rdev->use_count == 1 && !rdev->constraints->always_on) {
 
@@ -1210,16 +1209,7 @@ int regulator_disable(struct regulator *regulator)
        int ret = 0;
 
        mutex_lock(&rdev->mutex);
-       if (regulator->enabled == 1) {
-               ret = _regulator_disable(rdev);
-               if (ret == 0)
-                       regulator->uA_load = 0;
-       } else if (WARN(regulator->enabled <= 0,
-                       "unbalanced disables for supply %s\n",
-                       regulator->supply_name))
-               ret = -EIO;
-       if (ret == 0)
-               regulator->enabled--;
+       ret = _regulator_disable(rdev);
        mutex_unlock(&rdev->mutex);
        return ret;
 }
@@ -1266,7 +1256,6 @@ int regulator_force_disable(struct regulator *regulator)
        int ret;
 
        mutex_lock(&regulator->rdev->mutex);
-       regulator->enabled = 0;
        regulator->uA_load = 0;
        ret = _regulator_force_disable(regulator->rdev);
        mutex_unlock(&regulator->rdev->mutex);
@@ -2015,8 +2004,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
                return ERR_PTR(-EINVAL);
 
-       if (!regulator_desc->type == REGULATOR_VOLTAGE &&
-           !regulator_desc->type == REGULATOR_CURRENT)
+       if (regulator_desc->type != REGULATOR_VOLTAGE &&
+           regulator_desc->type != REGULATOR_CURRENT)
                return ERR_PTR(-EINVAL);
 
        if (!init_data)
@@ -2094,6 +2083,10 @@ out:
 
 scrub:
        device_unregister(&rdev->dev);
+       /* device core frees rdev */
+       rdev = ERR_PTR(ret);
+       goto out;
+
 clean:
        kfree(rdev);
        rdev = ERR_PTR(ret);
@@ -2158,6 +2151,23 @@ out:
 EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
 
 /**
+ * regulator_has_full_constraints - the system has fully specified constraints
+ *
+ * Calling this function will cause the regulator API to disable all
+ * regulators which have a zero use count and don't have an always_on
+ * constraint in a late_initcall.
+ *
+ * The intention is that this will become the default behaviour in a
+ * future kernel release so users are encouraged to use this facility
+ * now.
+ */
+void regulator_has_full_constraints(void)
+{
+       has_full_constraints = 1;
+}
+EXPORT_SYMBOL_GPL(regulator_has_full_constraints);
+
+/**
  * rdev_get_drvdata - get rdev regulator driver data
  * @rdev: regulator
  *
@@ -2224,3 +2234,77 @@ static int __init regulator_init(void)
 
 /* init early to allow our consumers to complete system booting */
 core_initcall(regulator_init);
+
+static int __init regulator_init_complete(void)
+{
+       struct regulator_dev *rdev;
+       struct regulator_ops *ops;
+       struct regulation_constraints *c;
+       int enabled, ret;
+       const char *name;
+
+       mutex_lock(&regulator_list_mutex);
+
+       /* If we have a full configuration then disable any regulators
+        * which are not in use or always_on.  This will become the
+        * default behaviour in the future.
+        */
+       list_for_each_entry(rdev, &regulator_list, list) {
+               ops = rdev->desc->ops;
+               c = rdev->constraints;
+
+               if (c->name)
+                       name = c->name;
+               else if (rdev->desc->name)
+                       name = rdev->desc->name;
+               else
+                       name = "regulator";
+
+               if (!ops->disable || c->always_on)
+                       continue;
+
+               mutex_lock(&rdev->mutex);
+
+               if (rdev->use_count)
+                       goto unlock;
+
+               /* If we can't read the status assume it's on. */
+               if (ops->is_enabled)
+                       enabled = ops->is_enabled(rdev);
+               else
+                       enabled = 1;
+
+               if (!enabled)
+                       goto unlock;
+
+               if (has_full_constraints) {
+                       /* We log since this may kill the system if it
+                        * goes wrong. */
+                       printk(KERN_INFO "%s: disabling %s\n",
+                              __func__, name);
+                       ret = ops->disable(rdev);
+                       if (ret != 0) {
+                               printk(KERN_ERR
+                                      "%s: couldn't disable %s: %d\n",
+                                      __func__, name, ret);
+                       }
+               } else {
+                       /* The intention is that in future we will
+                        * assume that full constraints are provided
+                        * so warn even if we aren't going to do
+                        * anything here.
+                        */
+                       printk(KERN_WARNING
+                              "%s: incomplete constraints, leaving %s on\n",
+                              __func__, name);
+               }
+
+unlock:
+               mutex_unlock(&rdev->mutex);
+       }
+
+       mutex_unlock(&regulator_list_mutex);
+
+       return 0;
+}
+late_initcall(regulator_init_complete);