regulator: add 88PM8607 PMIC driver
[safe/jmp/linux-2.6] / drivers / regulator / core.c
index 2f14c16..efe568d 100644 (file)
@@ -37,7 +37,7 @@ static int has_full_constraints;
  */
 struct regulator_map {
        struct list_head list;
-       struct device *dev;
+       const char *dev_name;   /* The dev_name() for the consumer */
        const char *supply;
        struct regulator_dev *regulator;
 };
@@ -232,7 +232,7 @@ static ssize_t regulator_name_show(struct device *dev,
        struct regulator_dev *rdev = dev_get_drvdata(dev);
        const char *name;
 
-       if (rdev->constraints->name)
+       if (rdev->constraints && rdev->constraints->name)
                name = rdev->constraints->name;
        else if (rdev->desc->name)
                name = rdev->desc->name;
@@ -280,8 +280,13 @@ static ssize_t regulator_state_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
+       ssize_t ret;
+
+       mutex_lock(&rdev->mutex);
+       ret = regulator_print_state(buf, _regulator_is_enabled(rdev));
+       mutex_unlock(&rdev->mutex);
 
-       return regulator_print_state(buf, _regulator_is_enabled(rdev));
+       return ret;
 }
 static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
 
@@ -703,10 +708,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 */
@@ -854,23 +862,39 @@ out:
  * set_consumer_device_supply: Bind a regulator to a symbolic supply
  * @rdev:         regulator source
  * @consumer_dev: device the supply applies to
+ * @consumer_dev_name: dev_name() string for device supply applies to
  * @supply:       symbolic name for supply
  *
  * Allows platform initialisation code to map physical regulator
  * sources to symbolic names for supplies for use by devices.  Devices
  * should use these symbolic names to request regulators, avoiding the
  * need to provide board-specific regulator names as platform data.
+ *
+ * Only one of consumer_dev and consumer_dev_name may be specified.
  */
 static int set_consumer_device_supply(struct regulator_dev *rdev,
-       struct device *consumer_dev, const char *supply)
+       struct device *consumer_dev, const char *consumer_dev_name,
+       const char *supply)
 {
        struct regulator_map *node;
+       int has_dev;
+
+       if (consumer_dev && consumer_dev_name)
+               return -EINVAL;
+
+       if (!consumer_dev_name && consumer_dev)
+               consumer_dev_name = dev_name(consumer_dev);
 
        if (supply == NULL)
                return -EINVAL;
 
+       if (consumer_dev_name != NULL)
+               has_dev = 1;
+       else
+               has_dev = 0;
+
        list_for_each_entry(node, &regulator_map_list, list) {
-               if (consumer_dev != node->dev)
+               if (consumer_dev_name != node->dev_name)
                        continue;
                if (strcmp(node->supply, supply) != 0)
                        continue;
@@ -883,30 +907,45 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
                return -EBUSY;
        }
 
-       node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
+       node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
        if (node == NULL)
                return -ENOMEM;
 
        node->regulator = rdev;
-       node->dev = consumer_dev;
        node->supply = supply;
 
+       if (has_dev) {
+               node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
+               if (node->dev_name == NULL) {
+                       kfree(node);
+                       return -ENOMEM;
+               }
+       }
+
        list_add(&node->list, &regulator_map_list);
        return 0;
 }
 
 static void unset_consumer_device_supply(struct regulator_dev *rdev,
-       struct device *consumer_dev)
+       const char *consumer_dev_name, struct device *consumer_dev)
 {
        struct regulator_map *node, *n;
 
+       if (consumer_dev && !consumer_dev_name)
+               consumer_dev_name = dev_name(consumer_dev);
+
        list_for_each_entry_safe(node, n, &regulator_map_list, list) {
-               if (rdev == node->regulator &&
-                       consumer_dev == node->dev) {
-                       list_del(&node->list);
-                       kfree(node);
-                       return;
-               }
+               if (rdev != node->regulator)
+                       continue;
+
+               if (consumer_dev_name && node->dev_name &&
+                   strcmp(consumer_dev_name, node->dev_name))
+                       continue;
+
+               list_del(&node->list);
+               kfree(node->dev_name);
+               kfree(node);
+               return;
        }
 }
 
@@ -917,6 +956,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
        list_for_each_entry_safe(node, n, &regulator_map_list, list) {
                if (rdev == node->regulator) {
                        list_del(&node->list);
+                       kfree(node->dev_name);
                        kfree(node);
                        return;
                }
@@ -998,35 +1038,33 @@ overflow_err:
        return NULL;
 }
 
-/**
- * regulator_get - lookup and obtain a reference to a regulator.
- * @dev: device for regulator "consumer"
- * @id: Supply name or regulator ID.
- *
- * Returns a struct regulator corresponding to the regulator producer,
- * or IS_ERR() condition containing errno.
- *
- * Use of supply names configured via regulator_set_device_supply() is
- * strongly encouraged.  It is recommended that the supply name used
- * should match the name used for the supply and/or the relevant
- * device pins in the datasheet.
- */
-struct regulator *regulator_get(struct device *dev, const char *id)
+/* Internal regulator request function */
+static struct regulator *_regulator_get(struct device *dev, const char *id,
+                                       int exclusive)
 {
        struct regulator_dev *rdev;
        struct regulator_map *map;
        struct regulator *regulator = ERR_PTR(-ENODEV);
+       const char *devname = NULL;
+       int ret;
 
        if (id == NULL) {
                printk(KERN_ERR "regulator: get() with no identifier\n");
                return regulator;
        }
 
+       if (dev)
+               devname = dev_name(dev);
+
        mutex_lock(&regulator_list_mutex);
 
        list_for_each_entry(map, &regulator_map_list, list) {
-               if (dev == map->dev &&
-                   strcmp(map->supply, id) == 0) {
+               /* If the mapping has a device set up it must match */
+               if (map->dev_name &&
+                   (!devname || strcmp(map->dev_name, devname)))
+                       continue;
+
+               if (strcmp(map->supply, id) == 0) {
                        rdev = map->regulator;
                        goto found;
                }
@@ -1035,6 +1073,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
        return regulator;
 
 found:
+       if (rdev->exclusive) {
+               regulator = ERR_PTR(-EPERM);
+               goto out;
+       }
+
+       if (exclusive && rdev->open_count) {
+               regulator = ERR_PTR(-EBUSY);
+               goto out;
+       }
+
        if (!try_module_get(rdev->owner))
                goto out;
 
@@ -1044,13 +1092,70 @@ found:
                module_put(rdev->owner);
        }
 
+       rdev->open_count++;
+       if (exclusive) {
+               rdev->exclusive = 1;
+
+               ret = _regulator_is_enabled(rdev);
+               if (ret > 0)
+                       rdev->use_count = 1;
+               else
+                       rdev->use_count = 0;
+       }
+
 out:
        mutex_unlock(&regulator_list_mutex);
+
        return regulator;
 }
+
+/**
+ * regulator_get - lookup and obtain a reference to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged.  It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get(struct device *dev, const char *id)
+{
+       return _regulator_get(dev, id, 0);
+}
 EXPORT_SYMBOL_GPL(regulator_get);
 
 /**
+ * regulator_get_exclusive - obtain exclusive access to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno.  Other consumers will be
+ * unable to obtain this reference is held and the use count for the
+ * regulator will be initialised to reflect the current state of the
+ * regulator.
+ *
+ * This is intended for use by consumers which cannot tolerate shared
+ * use of the regulator such as those which need to force the
+ * regulator off for correct operation of the hardware they are
+ * controlling.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged.  It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
+{
+       return _regulator_get(dev, id, 1);
+}
+EXPORT_SYMBOL_GPL(regulator_get_exclusive);
+
+/**
  * regulator_put - "free" the regulator source
  * @regulator: regulator source
  *
@@ -1078,21 +1183,29 @@ void regulator_put(struct regulator *regulator)
        list_del(&regulator->list);
        kfree(regulator);
 
+       rdev->open_count--;
+       rdev->exclusive = 0;
+
        module_put(rdev->owner);
        mutex_unlock(&regulator_list_mutex);
 }
 EXPORT_SYMBOL_GPL(regulator_put);
 
+static int _regulator_can_change_status(struct regulator_dev *rdev)
+{
+       if (!rdev->constraints)
+               return 0;
+
+       if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
+               return 1;
+       else
+               return 0;
+}
+
 /* locks held by regulator_enable() */
 static int _regulator_enable(struct regulator_dev *rdev)
 {
-       int ret = -EINVAL;
-
-       if (!rdev->constraints) {
-               printk(KERN_ERR "%s: %s has no constraints\n",
-                      __func__, rdev->desc->name);
-               return ret;
-       }
+       int ret;
 
        /* do we need to enable the supply regulator first */
        if (rdev->supply) {
@@ -1105,24 +1218,35 @@ static int _regulator_enable(struct regulator_dev *rdev)
        }
 
        /* check voltage and requested load before enabling */
-       if (rdev->desc->ops->enable) {
-
-               if (rdev->constraints &&
-                       (rdev->constraints->valid_ops_mask &
-                       REGULATOR_CHANGE_DRMS))
-                       drms_uA_update(rdev);
-
-               ret = rdev->desc->ops->enable(rdev);
-               if (ret < 0) {
-                       printk(KERN_ERR "%s: failed to enable %s: %d\n",
+       if (rdev->constraints &&
+           (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
+               drms_uA_update(rdev);
+
+       if (rdev->use_count == 0) {
+               /* The regulator may on if it's not switchable or left on */
+               ret = _regulator_is_enabled(rdev);
+               if (ret == -EINVAL || ret == 0) {
+                       if (!_regulator_can_change_status(rdev))
+                               return -EPERM;
+
+                       if (rdev->desc->ops->enable) {
+                               ret = rdev->desc->ops->enable(rdev);
+                               if (ret < 0)
+                                       return ret;
+                       } else {
+                               return -EINVAL;
+                       }
+               } else if (ret < 0) {
+                       printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
                               __func__, rdev->desc->name, ret);
                        return ret;
                }
-               rdev->use_count++;
-               return ret;
+               /* Fallthrough on positive return values - already enabled */
        }
 
-       return ret;
+       rdev->use_count++;
+
+       return 0;
 }
 
 /**
@@ -1159,10 +1283,12 @@ static int _regulator_disable(struct regulator_dev *rdev)
                return -EIO;
 
        /* are we the last user and permitted to disable ? */
-       if (rdev->use_count == 1 && !rdev->constraints->always_on) {
+       if (rdev->use_count == 1 &&
+           (rdev->constraints && !rdev->constraints->always_on)) {
 
                /* we are last user */
-               if (rdev->desc->ops->disable) {
+               if (_regulator_can_change_status(rdev) &&
+                   rdev->desc->ops->disable) {
                        ret = rdev->desc->ops->disable(rdev);
                        if (ret < 0) {
                                printk(KERN_ERR "%s: failed to disable %s\n",
@@ -1262,20 +1388,11 @@ EXPORT_SYMBOL_GPL(regulator_force_disable);
 
 static int _regulator_is_enabled(struct regulator_dev *rdev)
 {
-       int ret;
-
-       mutex_lock(&rdev->mutex);
-
        /* sanity check */
-       if (!rdev->desc->ops->is_enabled) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (!rdev->desc->ops->is_enabled)
+               return -EINVAL;
 
-       ret = rdev->desc->ops->is_enabled(rdev);
-out:
-       mutex_unlock(&rdev->mutex);
-       return ret;
+       return rdev->desc->ops->is_enabled(rdev);
 }
 
 /**
@@ -1292,7 +1409,13 @@ out:
  */
 int regulator_is_enabled(struct regulator *regulator)
 {
-       return _regulator_is_enabled(regulator->rdev);
+       int ret;
+
+       mutex_lock(&regulator->rdev->mutex);
+       ret = _regulator_is_enabled(regulator->rdev);
+       mutex_unlock(&regulator->rdev->mutex);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_is_enabled);
 
@@ -1347,6 +1470,35 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)
 EXPORT_SYMBOL_GPL(regulator_list_voltage);
 
 /**
+ * regulator_is_supported_voltage - check if a voltage range can be supported
+ *
+ * @regulator: Regulator to check.
+ * @min_uV: Minimum required voltage in uV.
+ * @max_uV: Maximum required voltage in uV.
+ *
+ * Returns a boolean or a negative error code.
+ */
+int regulator_is_supported_voltage(struct regulator *regulator,
+                                  int min_uV, int max_uV)
+{
+       int i, voltages, ret;
+
+       ret = regulator_count_voltages(regulator);
+       if (ret < 0)
+               return ret;
+       voltages = ret;
+
+       for (i = 0; i < voltages; i++) {
+               ret = regulator_list_voltage(regulator, i);
+
+               if (ret >= min_uV && ret <= max_uV)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/**
  * regulator_set_voltage - set regulator output voltage
  * @regulator: regulator source
  * @min_uV: Minimum required voltage in uV
@@ -1861,6 +2013,30 @@ int regulator_notifier_call_chain(struct regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
 
+/**
+ * regulator_mode_to_status - convert a regulator mode into a status
+ *
+ * @mode: Mode to convert
+ *
+ * Convert a regulator mode into a status.
+ */
+int regulator_mode_to_status(unsigned int mode)
+{
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               return REGULATOR_STATUS_FAST;
+       case REGULATOR_MODE_NORMAL:
+               return REGULATOR_STATUS_NORMAL;
+       case REGULATOR_MODE_IDLE:
+               return REGULATOR_STATUS_IDLE;
+       case REGULATOR_STATUS_STANDBY:
+               return REGULATOR_STATUS_STANDBY;
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(regulator_mode_to_status);
+
 /*
  * To avoid cluttering sysfs (and memory) with useless state, only
  * create attributes that can be meaningfully displayed.
@@ -2064,11 +2240,13 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        for (i = 0; i < init_data->num_consumer_supplies; i++) {
                ret = set_consumer_device_supply(rdev,
                        init_data->consumer_supplies[i].dev,
+                       init_data->consumer_supplies[i].dev_name,
                        init_data->consumer_supplies[i].supply);
                if (ret < 0) {
                        for (--i; i >= 0; i--)
                                unset_consumer_device_supply(rdev,
-                                       init_data->consumer_supplies[i].dev);
+                                   init_data->consumer_supplies[i].dev_name,
+                                   init_data->consumer_supplies[i].dev);
                        goto scrub;
                }
        }
@@ -2103,6 +2281,7 @@ void regulator_unregister(struct regulator_dev *rdev)
                return;
 
        mutex_lock(&regulator_list_mutex);
+       WARN_ON(rdev->open_count);
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
        if (rdev->supply)
@@ -2250,14 +2429,14 @@ static int __init regulator_init_complete(void)
                ops = rdev->desc->ops;
                c = rdev->constraints;
 
-               if (c->name)
+               if (c && c->name)
                        name = c->name;
                else if (rdev->desc->name)
                        name = rdev->desc->name;
                else
                        name = "regulator";
 
-               if (!ops->disable || c->always_on)
+               if (!ops->disable || (c && c->always_on))
                        continue;
 
                mutex_lock(&rdev->mutex);