Merge remote-tracking branch 'regulator/topic/gpio' into v3.9-rc8
authorMark Brown <broonie@sirena.org.uk>
Sun, 28 Apr 2013 01:13:40 +0000 (02:13 +0100)
committerMark Brown <broonie@sirena.org.uk>
Sun, 28 Apr 2013 01:13:40 +0000 (02:13 +0100)
1  2 
drivers/regulator/core.c
include/linux/regulator/driver.h

diff --combined drivers/regulator/core.c
index 2434e2e1afcc20b56549f239cd9253e7ad4d9724,6c8c82406cd9b5e3a8a77e90168953c6e64d7080..6e501784158266d990fc6cad8fb6e0ee7733d923
@@@ -51,6 -51,7 +51,7 @@@
  static DEFINE_MUTEX(regulator_list_mutex);
  static LIST_HEAD(regulator_list);
  static LIST_HEAD(regulator_map_list);
+ static LIST_HEAD(regulator_ena_gpio_list);
  static bool has_full_constraints;
  static bool board_wants_dummy_regulator;
  
@@@ -68,6 -69,19 +69,19 @@@ struct regulator_map 
        struct regulator_dev *regulator;
  };
  
+ /*
+  * struct regulator_enable_gpio
+  *
+  * Management for shared enable GPIO pin
+  */
+ struct regulator_enable_gpio {
+       struct list_head list;
+       int gpio;
+       u32 enable_count;       /* a number of enabled shared GPIO */
+       u32 request_count;      /* a number of requested shared GPIO */
+       unsigned int ena_gpio_invert:1;
+ };
  /*
   * struct regulator
   *
@@@ -116,7 -130,7 +130,7 @@@ static const char *rdev_get_name(struc
   * @supply: regulator supply name
   *
   * Extract the regulator device node corresponding to the supply name.
 - * retruns the device node corresponding to the regulator if found, else
 + * returns the device node corresponding to the regulator if found, else
   * returns NULL.
   */
  static struct device_node *of_get_regulator(struct device *dev, const char *supply)
@@@ -1229,7 -1243,7 +1243,7 @@@ static struct regulator *_regulator_get
        struct regulator_dev *rdev;
        struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
        const char *devname = NULL;
 -      int ret;
 +      int ret = 0;
  
        if (id == NULL) {
                pr_err("get() with no identifier\n");
        if (rdev)
                goto found;
  
 +      /*
 +       * If we have return value from dev_lookup fail, we do not expect to
 +       * succeed, so, quit with appropriate error value
 +       */
 +      if (ret) {
 +              regulator = ERR_PTR(ret);
 +              goto out;
 +      }
 +
        if (board_wants_dummy_regulator) {
                rdev = dummy_regulator_rdev;
                goto found;
@@@ -1465,6 -1470,101 +1479,101 @@@ void devm_regulator_put(struct regulato
  }
  EXPORT_SYMBOL_GPL(devm_regulator_put);
  
+ /* Manage enable GPIO list. Same GPIO pin can be shared among regulators */
+ static int regulator_ena_gpio_request(struct regulator_dev *rdev,
+                               const struct regulator_config *config)
+ {
+       struct regulator_enable_gpio *pin;
+       int ret;
+       list_for_each_entry(pin, &regulator_ena_gpio_list, list) {
+               if (pin->gpio == config->ena_gpio) {
+                       rdev_dbg(rdev, "GPIO %d is already used\n",
+                               config->ena_gpio);
+                       goto update_ena_gpio_to_rdev;
+               }
+       }
+       ret = gpio_request_one(config->ena_gpio,
+                               GPIOF_DIR_OUT | config->ena_gpio_flags,
+                               rdev_get_name(rdev));
+       if (ret)
+               return ret;
+       pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
+       if (pin == NULL) {
+               gpio_free(config->ena_gpio);
+               return -ENOMEM;
+       }
+       pin->gpio = config->ena_gpio;
+       pin->ena_gpio_invert = config->ena_gpio_invert;
+       list_add(&pin->list, &regulator_ena_gpio_list);
+ update_ena_gpio_to_rdev:
+       pin->request_count++;
+       rdev->ena_pin = pin;
+       return 0;
+ }
+ static void regulator_ena_gpio_free(struct regulator_dev *rdev)
+ {
+       struct regulator_enable_gpio *pin, *n;
+       if (!rdev->ena_pin)
+               return;
+       /* Free the GPIO only in case of no use */
+       list_for_each_entry_safe(pin, n, &regulator_ena_gpio_list, list) {
+               if (pin->gpio == rdev->ena_pin->gpio) {
+                       if (pin->request_count <= 1) {
+                               pin->request_count = 0;
+                               gpio_free(pin->gpio);
+                               list_del(&pin->list);
+                               kfree(pin);
+                       } else {
+                               pin->request_count--;
+                       }
+               }
+       }
+ }
+ /**
+  * Balance enable_count of each GPIO and actual GPIO pin control.
+  * GPIO is enabled in case of initial use. (enable_count is 0)
+  * GPIO is disabled when it is not shared any more. (enable_count <= 1)
+  */
+ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
+ {
+       struct regulator_enable_gpio *pin = rdev->ena_pin;
+       if (!pin)
+               return -EINVAL;
+       if (enable) {
+               /* Enable GPIO at initial use */
+               if (pin->enable_count == 0)
+                       gpio_set_value_cansleep(pin->gpio,
+                                               !pin->ena_gpio_invert);
+               pin->enable_count++;
+       } else {
+               if (pin->enable_count > 1) {
+                       pin->enable_count--;
+                       return 0;
+               }
+               /* Disable GPIO if not used */
+               if (pin->enable_count <= 1) {
+                       gpio_set_value_cansleep(pin->gpio,
+                                               pin->ena_gpio_invert);
+                       pin->enable_count = 0;
+               }
+       }
+       return 0;
+ }
  static int _regulator_do_enable(struct regulator_dev *rdev)
  {
        int ret, delay;
  
        trace_regulator_enable(rdev_get_name(rdev));
  
-       if (rdev->ena_gpio) {
-               gpio_set_value_cansleep(rdev->ena_gpio,
-                                       !rdev->ena_gpio_invert);
+       if (rdev->ena_pin) {
+               ret = regulator_ena_gpio_ctrl(rdev, true);
+               if (ret < 0)
+                       return ret;
                rdev->ena_gpio_state = 1;
        } else if (rdev->desc->ops->enable) {
                ret = rdev->desc->ops->enable(rdev);
@@@ -1584,9 -1685,10 +1694,10 @@@ static int _regulator_do_disable(struc
  
        trace_regulator_disable(rdev_get_name(rdev));
  
-       if (rdev->ena_gpio) {
-               gpio_set_value_cansleep(rdev->ena_gpio,
-                                       rdev->ena_gpio_invert);
+       if (rdev->ena_pin) {
+               ret = regulator_ena_gpio_ctrl(rdev, false);
+               if (ret < 0)
+                       return ret;
                rdev->ena_gpio_state = 0;
  
        } else if (rdev->desc->ops->disable) {
@@@ -1803,10 -1905,7 +1914,10 @@@ int regulator_is_enabled_regmap(struct 
        if (ret != 0)
                return ret;
  
 -      return (val & rdev->desc->enable_mask) != 0;
 +      if (rdev->desc->enable_is_inverted)
 +              return (val & rdev->desc->enable_mask) == 0;
 +      else
 +              return (val & rdev->desc->enable_mask) != 0;
  }
  EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
  
   */
  int regulator_enable_regmap(struct regulator_dev *rdev)
  {
 +      unsigned int val;
 +
 +      if (rdev->desc->enable_is_inverted)
 +              val = 0;
 +      else
 +              val = rdev->desc->enable_mask;
 +
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
 -                                rdev->desc->enable_mask,
 -                                rdev->desc->enable_mask);
 +                                rdev->desc->enable_mask, val);
  }
  EXPORT_SYMBOL_GPL(regulator_enable_regmap);
  
   */
  int regulator_disable_regmap(struct regulator_dev *rdev)
  {
 +      unsigned int val;
 +
 +      if (rdev->desc->enable_is_inverted)
 +              val = rdev->desc->enable_mask;
 +      else
 +              val = 0;
 +
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
 -                                rdev->desc->enable_mask, 0);
 +                                rdev->desc->enable_mask, val);
  }
  EXPORT_SYMBOL_GPL(regulator_disable_regmap);
  
  static int _regulator_is_enabled(struct regulator_dev *rdev)
  {
        /* A GPIO control always takes precedence */
-       if (rdev->ena_gpio)
+       if (rdev->ena_pin)
                return rdev->ena_gpio_state;
  
        /* If we don't know then assume that the regulator is always on */
@@@ -2162,37 -2248,6 +2273,37 @@@ int regulator_map_voltage_iterate(struc
  }
  EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate);
  
 +/**
 + * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list
 + *
 + * @rdev: Regulator to operate on
 + * @min_uV: Lower bound for voltage
 + * @max_uV: Upper bound for voltage
 + *
 + * Drivers that have ascendant voltage list can use this as their
 + * map_voltage() operation.
 + */
 +int regulator_map_voltage_ascend(struct regulator_dev *rdev,
 +                               int min_uV, int max_uV)
 +{
 +      int i, ret;
 +
 +      for (i = 0; i < rdev->desc->n_voltages; i++) {
 +              ret = rdev->desc->ops->list_voltage(rdev, i);
 +              if (ret < 0)
 +                      continue;
 +
 +              if (ret > max_uV)
 +                      break;
 +
 +              if (ret >= min_uV && ret <= max_uV)
 +                      return i;
 +      }
 +
 +      return -EINVAL;
 +}
 +EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend);
 +
  /**
   * regulator_map_voltage_linear - map_voltage() for simple linear mappings
   *
@@@ -2886,7 -2941,7 +2997,7 @@@ EXPORT_SYMBOL_GPL(regulator_get_bypass_
   * regulator_allow_bypass - allow the regulator to go into bypass mode
   *
   * @regulator: Regulator to configure
 - * @allow: enable or disable bypass mode
 + * @enable: enable or disable bypass mode
   *
   * Allow the regulator to go into bypass mode if all other consumers
   * for the regulator also enable bypass mode and the machine
@@@ -3113,13 -3168,9 +3224,13 @@@ int regulator_bulk_enable(int num_consu
        return 0;
  
  err:
 -      pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret);
 -      while (--i >= 0)
 -              regulator_disable(consumers[i].consumer);
 +      for (i = 0; i < num_consumers; i++) {
 +              if (consumers[i].ret < 0)
 +                      pr_err("Failed to enable %s: %d\n", consumers[i].supply,
 +                             consumers[i].ret);
 +              else
 +                      regulator_disable(consumers[i].consumer);
 +      }
  
        return ret;
  }
@@@ -3293,7 -3344,7 +3404,7 @@@ static int add_regulator_attributes(str
                if (status < 0)
                        return status;
        }
-       if (rdev->ena_gpio || ops->is_enabled) {
+       if (rdev->ena_pin || ops->is_enabled) {
                status = device_create_file(dev, &dev_attr_state);
                if (status < 0)
                        return status;
@@@ -3495,22 -3546,17 +3606,17 @@@ regulator_register(const struct regulat
        dev_set_drvdata(&rdev->dev, rdev);
  
        if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
-               ret = gpio_request_one(config->ena_gpio,
-                                      GPIOF_DIR_OUT | config->ena_gpio_flags,
-                                      rdev_get_name(rdev));
+               ret = regulator_ena_gpio_request(rdev, config);
                if (ret != 0) {
                        rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
                                 config->ena_gpio, ret);
                        goto wash;
                }
  
-               rdev->ena_gpio = config->ena_gpio;
-               rdev->ena_gpio_invert = config->ena_gpio_invert;
                if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
                        rdev->ena_gpio_state = 1;
  
-               if (rdev->ena_gpio_invert)
+               if (config->ena_gpio_invert)
                        rdev->ena_gpio_state = !rdev->ena_gpio_state;
        }
  
  
                r = regulator_dev_lookup(dev, supply, &ret);
  
 -              if (!r) {
 +              if (ret == -ENODEV) {
 +                      /*
 +                       * No supply was specified for this regulator and
 +                       * there will never be one.
 +                       */
 +                      ret = 0;
 +                      goto add_dev;
 +              } else if (!r) {
                        dev_err(dev, "Failed to find supply %s\n", supply);
                        ret = -EPROBE_DEFER;
                        goto scrub;
                }
        }
  
 +add_dev:
        /* add consumers devices */
        if (init_data) {
                for (i = 0; i < init_data->num_consumer_supplies; i++) {
@@@ -3590,8 -3628,7 +3696,7 @@@ unset_supplies
  scrub:
        if (rdev->supply)
                _regulator_put(rdev->supply);
-       if (rdev->ena_gpio)
-               gpio_free(rdev->ena_gpio);
+       regulator_ena_gpio_free(rdev);
        kfree(rdev->constraints);
  wash:
        device_unregister(&rdev->dev);
@@@ -3626,8 -3663,7 +3731,7 @@@ void regulator_unregister(struct regula
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
        kfree(rdev->constraints);
-       if (rdev->ena_gpio)
-               gpio_free(rdev->ena_gpio);
+       regulator_ena_gpio_free(rdev);
        device_unregister(&rdev->dev);
        mutex_unlock(&regulator_list_mutex);
  }
index 0dccc91b8ab41cefa39fa9b3007f8be07b1b9e41,7b7aeec04f869aea735163145ac99519b341a5ae..6700cc94bdd12275df1b8be822939c298b811aff
@@@ -22,6 -22,7 +22,7 @@@
  struct regmap;
  struct regulator_dev;
  struct regulator_init_data;
+ struct regulator_enable_gpio;
  
  enum regulator_status {
        REGULATOR_STATUS_OFF,
@@@ -199,10 -200,6 +200,10 @@@ enum regulator_type 
   *                output when using regulator_set_voltage_sel_regmap
   * @enable_reg: Register for control when using regmap enable/disable ops
   * @enable_mask: Mask for control when using regmap enable/disable ops
 + * @enable_is_inverted: A flag to indicate set enable_mask bits to disable
 + *                      when using regulator_enable_regmap and friends APIs.
 + * @bypass_reg: Register for control when using regmap set_bypass
 + * @bypass_mask: Mask for control when using regmap set_bypass
   *
   * @enable_time: Time taken for initial enable of regulator (in uS).
   */
@@@ -230,7 -227,6 +231,7 @@@ struct regulator_desc 
        unsigned int apply_bit;
        unsigned int enable_reg;
        unsigned int enable_mask;
 +      bool enable_is_inverted;
        unsigned int bypass_reg;
        unsigned int bypass_mask;
  
@@@ -305,8 -301,7 +306,7 @@@ struct regulator_dev 
  
        struct dentry *debugfs;
  
-       int ena_gpio;
-       unsigned int ena_gpio_invert:1;
+       struct regulator_enable_gpio *ena_pin;
        unsigned int ena_gpio_state:1;
  };
  
@@@ -332,8 -327,6 +332,8 @@@ int regulator_map_voltage_linear(struc
                                  int min_uV, int max_uV);
  int regulator_map_voltage_iterate(struct regulator_dev *rdev,
                                  int min_uV, int max_uV);
 +int regulator_map_voltage_ascend(struct regulator_dev *rdev,
 +                                int min_uV, int max_uV);
  int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev);
  int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel);
  int regulator_is_enabled_regmap(struct regulator_dev *rdev);