]> Git Repo - linux.git/commitdiff
Merge remote-tracking branch 'regulator/topic/fixed' into regulator-next
authorMark Brown <[email protected]>
Thu, 24 Oct 2013 10:11:36 +0000 (11:11 +0100)
committerMark Brown <[email protected]>
Thu, 24 Oct 2013 10:11:36 +0000 (11:11 +0100)
1  2 
drivers/regulator/core.c
include/linux/regulator/driver.h

diff --combined drivers/regulator/core.c
index 916cadf45279289e1fc6b6106b7ff3f7ee580308,abc899ed1ebf12dc8a6640ef91d16d61d347fb27..960103a6100041e008ce6793304c82299ca59b16
@@@ -36,7 -36,6 +36,7 @@@
  #include <trace/events/regulator.h>
  
  #include "dummy.h"
 +#include "internal.h"
  
  #define rdev_crit(rdev, fmt, ...)                                     \
        pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
@@@ -53,7 -52,6 +53,7 @@@ static DEFINE_MUTEX(regulator_list_mute
  static LIST_HEAD(regulator_list);
  static LIST_HEAD(regulator_map_list);
  static LIST_HEAD(regulator_ena_gpio_list);
 +static LIST_HEAD(regulator_supply_alias_list);
  static bool has_full_constraints;
  static bool board_wants_dummy_regulator;
  
@@@ -85,16 -83,22 +85,16 @@@ struct regulator_enable_gpio 
  };
  
  /*
 - * struct regulator
 + * struct regulator_supply_alias
   *
 - * One for each consumer device.
 + * Used to map lookups for a supply onto an alternative device.
   */
 -struct regulator {
 -      struct device *dev;
 +struct regulator_supply_alias {
        struct list_head list;
 -      unsigned int always_on:1;
 -      unsigned int bypass:1;
 -      int uA_load;
 -      int min_uV;
 -      int max_uV;
 -      char *supply_name;
 -      struct device_attribute dev_attr;
 -      struct regulator_dev *rdev;
 -      struct dentry *debugfs;
 +      struct device *src_dev;
 +      const char *src_supply;
 +      struct device *alias_dev;
 +      const char *alias_supply;
  };
  
  static int _regulator_is_enabled(struct regulator_dev *rdev);
@@@ -919,36 -923,6 +919,36 @@@ static int machine_constraints_voltage(
        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
@@@ -979,10 -953,6 +979,10 @@@ static int set_machine_constraints(stru
        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);
@@@ -1216,39 -1186,11 +1216,39 @@@ 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);
  }
  
 +static struct regulator_supply_alias *regulator_find_supply_alias(
 +              struct device *dev, const char *supply)
 +{
 +      struct regulator_supply_alias *map;
 +
 +      list_for_each_entry(map, &regulator_supply_alias_list, list)
 +              if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0)
 +                      return map;
 +
 +      return NULL;
 +}
 +
 +static void regulator_supply_alias(struct device **dev, const char **supply)
 +{
 +      struct regulator_supply_alias *map;
 +
 +      map = regulator_find_supply_alias(*dev, *supply);
 +      if (map) {
 +              dev_dbg(*dev, "Mapping supply %s to %s,%s\n",
 +                              *supply, map->alias_supply,
 +                              dev_name(map->alias_dev));
 +              *dev = map->alias_dev;
 +              *supply = map->alias_supply;
 +      }
 +}
 +
  static struct regulator_dev *regulator_dev_lookup(struct device *dev,
                                                  const char *supply,
                                                  int *ret)
        struct regulator_map *map;
        const char *devname = NULL;
  
 +      regulator_supply_alias(&dev, &supply);
 +
        /* first do a dt based lookup */
        if (dev && dev->of_node) {
                node = of_get_regulator(dev, supply);
@@@ -1312,7 -1252,7 +1312,7 @@@ static struct regulator *_regulator_get
  
        if (id == NULL) {
                pr_err("get() with no identifier\n");
 -              return regulator;
 +              return ERR_PTR(-EINVAL);
        }
  
        if (dev)
@@@ -1413,6 -1353,40 +1413,6 @@@ struct regulator *regulator_get(struct 
  }
  EXPORT_SYMBOL_GPL(regulator_get);
  
 -static void devm_regulator_release(struct device *dev, void *res)
 -{
 -      regulator_put(*(struct regulator **)res);
 -}
 -
 -/**
 - * devm_regulator_get - Resource managed regulator_get()
 - * @dev: device for regulator "consumer"
 - * @id: Supply name or regulator ID.
 - *
 - * Managed regulator_get(). Regulators returned from this function are
 - * automatically regulator_put() on driver detach. See regulator_get() for more
 - * information.
 - */
 -struct regulator *devm_regulator_get(struct device *dev, const char *id)
 -{
 -      struct regulator **ptr, *regulator;
 -
 -      ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
 -      if (!ptr)
 -              return ERR_PTR(-ENOMEM);
 -
 -      regulator = regulator_get(dev, id);
 -      if (!IS_ERR(regulator)) {
 -              *ptr = regulator;
 -              devres_add(dev, ptr);
 -      } else {
 -              devres_free(ptr);
 -      }
 -
 -      return regulator;
 -}
 -EXPORT_SYMBOL_GPL(devm_regulator_get);
 -
  /**
   * regulator_get_exclusive - obtain exclusive access to a regulator.
   * @dev: device for regulator "consumer"
@@@ -1469,6 -1443,36 +1469,6 @@@ struct regulator *regulator_get_optiona
  }
  EXPORT_SYMBOL_GPL(regulator_get_optional);
  
 -/**
 - * devm_regulator_get_optional - Resource managed regulator_get_optional()
 - * @dev: device for regulator "consumer"
 - * @id: Supply name or regulator ID.
 - *
 - * Managed regulator_get_optional(). Regulators returned from this
 - * function are automatically regulator_put() on driver detach. See
 - * regulator_get_optional() for more information.
 - */
 -struct regulator *devm_regulator_get_optional(struct device *dev,
 -                                            const char *id)
 -{
 -      struct regulator **ptr, *regulator;
 -
 -      ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
 -      if (!ptr)
 -              return ERR_PTR(-ENOMEM);
 -
 -      regulator = regulator_get_optional(dev, id);
 -      if (!IS_ERR(regulator)) {
 -              *ptr = regulator;
 -              devres_add(dev, ptr);
 -      } else {
 -              devres_free(ptr);
 -      }
 -
 -      return regulator;
 -}
 -EXPORT_SYMBOL_GPL(devm_regulator_get_optional);
 -
  /* Locks held by regulator_put() */
  static void _regulator_put(struct regulator *regulator)
  {
        module_put(rdev->owner);
  }
  
 -/**
 - * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive()
 - * @dev: device for regulator "consumer"
 - * @id: Supply name or regulator ID.
 - *
 - * Managed regulator_get_exclusive(). Regulators returned from this function
 - * are automatically regulator_put() on driver detach. See regulator_get() for
 - * more information.
 - */
 -struct regulator *devm_regulator_get_exclusive(struct device *dev,
 -                                             const char *id)
 -{
 -      struct regulator **ptr, *regulator;
 -
 -      ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
 -      if (!ptr)
 -              return ERR_PTR(-ENOMEM);
 -
 -      regulator = _regulator_get(dev, id, 1);
 -      if (!IS_ERR(regulator)) {
 -              *ptr = regulator;
 -              devres_add(dev, ptr);
 -      } else {
 -              devres_free(ptr);
 -      }
 -
 -      return regulator;
 -}
 -EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive);
 -
  /**
   * regulator_put - "free" the regulator source
   * @regulator: regulator source
@@@ -1510,133 -1544,34 +1510,133 @@@ void regulator_put(struct regulator *re
  }
  EXPORT_SYMBOL_GPL(regulator_put);
  
 -static int devm_regulator_match(struct device *dev, void *res, void *data)
 +/**
 + * regulator_register_supply_alias - Provide device alias for supply lookup
 + *
 + * @dev: device that will be given as the regulator "consumer"
 + * @id: Supply name or regulator ID
 + * @alias_dev: device that should be used to lookup the supply
 + * @alias_id: Supply name or regulator ID that should be used to lookup the
 + * supply
 + *
 + * All lookups for id on dev will instead be conducted for alias_id on
 + * alias_dev.
 + */
 +int regulator_register_supply_alias(struct device *dev, const char *id,
 +                                  struct device *alias_dev,
 +                                  const char *alias_id)
  {
 -      struct regulator **r = res;
 -      if (!r || !*r) {
 -              WARN_ON(!r || !*r);
 -              return 0;
 +      struct regulator_supply_alias *map;
 +
 +      map = regulator_find_supply_alias(dev, id);
 +      if (map)
 +              return -EEXIST;
 +
 +      map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
 +      if (!map)
 +              return -ENOMEM;
 +
 +      map->src_dev = dev;
 +      map->src_supply = id;
 +      map->alias_dev = alias_dev;
 +      map->alias_supply = alias_id;
 +
 +      list_add(&map->list, &regulator_supply_alias_list);
 +
 +      pr_info("Adding alias for supply %s,%s -> %s,%s\n",
 +              id, dev_name(dev), alias_id, dev_name(alias_dev));
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(regulator_register_supply_alias);
 +
 +/**
 + * regulator_unregister_supply_alias - Remove device alias
 + *
 + * @dev: device that will be given as the regulator "consumer"
 + * @id: Supply name or regulator ID
 + *
 + * Remove a lookup alias if one exists for id on dev.
 + */
 +void regulator_unregister_supply_alias(struct device *dev, const char *id)
 +{
 +      struct regulator_supply_alias *map;
 +
 +      map = regulator_find_supply_alias(dev, id);
 +      if (map) {
 +              list_del(&map->list);
 +              kfree(map);
 +      }
 +}
 +EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);
 +
 +/**
 + * regulator_bulk_register_supply_alias - register multiple aliases
 + *
 + * @dev: device that will be given as the regulator "consumer"
 + * @id: List of supply names or regulator IDs
 + * @alias_dev: device that should be used to lookup the supply
 + * @alias_id: List of supply names or regulator IDs that should be used to
 + * lookup the supply
 + * @num_id: Number of aliases to register
 + *
 + * @return 0 on success, an errno on failure.
 + *
 + * This helper function allows drivers to register several supply
 + * aliases in one operation.  If any of the aliases cannot be
 + * registered any aliases that were registered will be removed
 + * before returning to the caller.
 + */
 +int regulator_bulk_register_supply_alias(struct device *dev, const char **id,
 +                                       struct device *alias_dev,
 +                                       const char **alias_id,
 +                                       int num_id)
 +{
 +      int i;
 +      int ret;
 +
 +      for (i = 0; i < num_id; ++i) {
 +              ret = regulator_register_supply_alias(dev, id[i], alias_dev,
 +                                                    alias_id[i]);
 +              if (ret < 0)
 +                      goto err;
        }
 -      return *r == data;
 +
 +      return 0;
 +
 +err:
 +      dev_err(dev,
 +              "Failed to create supply alias %s,%s -> %s,%s\n",
 +              id[i], dev_name(dev), alias_id[i], dev_name(alias_dev));
 +
 +      while (--i >= 0)
 +              regulator_unregister_supply_alias(dev, id[i]);
 +
 +      return ret;
  }
 +EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias);
  
  /**
 - * devm_regulator_put - Resource managed regulator_put()
 - * @regulator: regulator to free
 + * regulator_bulk_unregister_supply_alias - unregister multiple aliases
   *
 - * Deallocate a regulator allocated with devm_regulator_get(). Normally
 - * this function will not need to be called and the resource management
 - * code will ensure that the resource is freed.
 + * @dev: device that will be given as the regulator "consumer"
 + * @id: List of supply names or regulator IDs
 + * @num_id: Number of aliases to unregister
 + *
 + * This helper function allows drivers to unregister several supply
 + * aliases in one operation.
   */
 -void devm_regulator_put(struct regulator *regulator)
 +void regulator_bulk_unregister_supply_alias(struct device *dev,
 +                                          const char **id,
 +                                          int num_id)
  {
 -      int rc;
 +      int i;
  
 -      rc = devres_release(regulator->dev, devm_regulator_release,
 -                          devm_regulator_match, regulator);
 -      if (rc != 0)
 -              WARN_ON(rc);
 +      for (i = 0; i < num_id; ++i)
 +              regulator_unregister_supply_alias(dev, id[i]);
  }
 -EXPORT_SYMBOL_GPL(devm_regulator_put);
 +EXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias);
 +
  
  /* Manage enable GPIO list. Same GPIO pin can be shared among regulators */
  static int regulator_ena_gpio_request(struct regulator_dev *rdev,
@@@ -1769,39 -1704,11 +1769,39 @@@ static int _regulator_do_enable(struct 
         * 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));
@@@ -2582,6 -2489,8 +2582,8 @@@ static int _regulator_get_voltage(struc
                ret = rdev->desc->ops->get_voltage(rdev);
        } else if (rdev->desc->ops->list_voltage) {
                ret = rdev->desc->ops->list_voltage(rdev, 0);
+       } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) {
+               ret = rdev->desc->fixed_uV;
        } else {
                return -EINVAL;
        }
@@@ -3005,6 -2914,52 +3007,6 @@@ err
  }
  EXPORT_SYMBOL_GPL(regulator_bulk_get);
  
 -/**
 - * devm_regulator_bulk_get - managed get multiple regulator consumers
 - *
 - * @dev:           Device to supply
 - * @num_consumers: Number of consumers to register
 - * @consumers:     Configuration of consumers; clients are stored here.
 - *
 - * @return 0 on success, an errno on failure.
 - *
 - * This helper function allows drivers to get several regulator
 - * consumers in one operation with management, the regulators will
 - * automatically be freed when the device is unbound.  If any of the
 - * regulators cannot be acquired then any regulators that were
 - * allocated will be freed before returning to the caller.
 - */
 -int devm_regulator_bulk_get(struct device *dev, int num_consumers,
 -                          struct regulator_bulk_data *consumers)
 -{
 -      int i;
 -      int ret;
 -
 -      for (i = 0; i < num_consumers; i++)
 -              consumers[i].consumer = NULL;
 -
 -      for (i = 0; i < num_consumers; i++) {
 -              consumers[i].consumer = devm_regulator_get(dev,
 -                                                         consumers[i].supply);
 -              if (IS_ERR(consumers[i].consumer)) {
 -                      ret = PTR_ERR(consumers[i].consumer);
 -                      dev_err(dev, "Failed to get supply '%s': %d\n",
 -                              consumers[i].supply, ret);
 -                      consumers[i].consumer = NULL;
 -                      goto err;
 -              }
 -      }
 -
 -      return 0;
 -
 -err:
 -      for (i = 0; i < num_consumers && consumers[i].consumer; i++)
 -              devm_regulator_put(consumers[i].consumer);
 -
 -      return ret;
 -}
 -EXPORT_SYMBOL_GPL(devm_regulator_bulk_get);
 -
  static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)
  {
        struct regulator_bulk_data *bulk = data;
@@@ -3217,7 -3172,8 +3219,8 @@@ static int add_regulator_attributes(str
        /* some attributes need specific methods to be displayed */
        if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
            (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) ||
-           (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0)) {
+           (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) ||
+               (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) {
                status = device_create_file(dev, &dev_attr_microvolts);
                if (status < 0)
                        return status;
index 779b877e0fa12de1331e3584694d82951a9476fc,9e8241a9f28f3535d0b3397890cd57ae5745922b..c8b492c6b6a8a2693abbc5ae37c0befe92e61af3
@@@ -40,8 -40,6 +40,8 @@@ enum regulator_status 
  };
  
  /**
 + * struct regulator_linear_range - specify linear voltage ranges
 + *
   * Specify a range of voltages for regulator_map_linar_range() and
   * regulator_list_linear_range().
   *
@@@ -209,6 -207,7 +209,7 @@@ enum regulator_type 
   * @min_uV: Voltage given by the lowest selector (if linear mapping)
   * @uV_step: Voltage increase with each selector (if linear mapping)
   * @linear_min_sel: Minimal selector for starting linear mapping
+  * @fixed_uV: Fixed voltage of rails.
   * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
   * @volt_table: Voltage mapping table (if table based mapping)
   *
@@@ -241,6 -240,7 +242,7 @@@ struct regulator_desc 
        unsigned int min_uV;
        unsigned int uV_step;
        unsigned int linear_min_sel;
+       int fixed_uV;
        unsigned int ramp_delay;
  
        const struct regulator_linear_range *linear_ranges;
@@@ -336,12 -336,7 +338,12 @@@ struct regulator_dev 
  struct regulator_dev *
  regulator_register(const struct regulator_desc *regulator_desc,
                   const struct regulator_config *config);
 +struct regulator_dev *
 +devm_regulator_register(struct device *dev,
 +                      const struct regulator_desc *regulator_desc,
 +                      const struct regulator_config *config);
  void regulator_unregister(struct regulator_dev *rdev);
 +void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev);
  
  int regulator_notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data);
This page took 0.086115 seconds and 4 git commands to generate.