Thanks Mark,

Series looks good to me and works for the palmas. I can now add the
bypass support without the side hack I currently have to do it.

Reviewed-by: Graeme Gregory <g...@slimlogic.co.uk>

On 28/08/12 06:31, Mark Brown wrote:
> Many regulators support a bypass mode where they simply switch their
> input supply to the output. This is mainly used in low power retention
> states where power consumption is extremely low so higher voltage or
> less clean supplies can be used.
>
> This is not supported as a mode since the existing modes are rarely used
> due to fuzzy definition and mostly redundant with modern hardware which is
> able to respond promptly to load changes.
>
> Signed-off-by: Mark Brown <broo...@opensource.wolfsonmicro.com>
> ---
>  Documentation/ABI/testing/sysfs-class-regulator |   21 ++++++
>  drivers/regulator/core.c                        |   84 
> +++++++++++++++++++++++
>  include/linux/regulator/consumer.h              |    8 +++
>  include/linux/regulator/driver.h                |   10 +++
>  include/linux/regulator/machine.h               |    2 +
>  5 files changed, 125 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-regulator 
> b/Documentation/ABI/testing/sysfs-class-regulator
> index e091fa8..bc578bc 100644
> --- a/Documentation/ABI/testing/sysfs-class-regulator
> +++ b/Documentation/ABI/testing/sysfs-class-regulator
> @@ -349,3 +349,24 @@ Description:
>  
>               This will be one of the same strings reported by
>               the "state" attribute.
> +
> +What:                /sys/class/regulator/.../bypass
> +Date:                September 2012
> +KernelVersion:       3.7
> +Contact:     Mark Brown <broo...@opensource.wolfsonmicro.com>
> +Description:
> +             Some regulator directories will contain a field called
> +             bypass.  This indicates if the device is in bypass mode.
> +
> +             This will be one of the following strings:
> +
> +             'enabled'
> +             'disabled'
> +             'unknown'
> +
> +             'enabled' means the regulator is in bypass mode.
> +
> +             'disabled' means that the regulator is regulating.
> +
> +             'unknown' means software cannot determine the state, or
> +             the reported state is invalid.
> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
> index db7d59a..d06a82e 100644
> --- a/drivers/regulator/core.c
> +++ b/drivers/regulator/core.c
> @@ -77,6 +77,7 @@ struct regulator {
>       struct device *dev;
>       struct list_head list;
>       unsigned int always_on:1;
> +     unsigned int bypass:1;
>       int uA_load;
>       int min_uV;
>       int max_uV;
> @@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev,
>       case REGULATOR_STATUS_STANDBY:
>               label = "standby";
>               break;
> +     case REGULATOR_STATUS_BYPASS:
> +             label = "bypass";
> +             break;
>       case REGULATOR_STATUS_UNDEFINED:
>               label = "undefined";
>               break;
> @@ -585,6 +589,27 @@ static ssize_t 
> regulator_suspend_standby_state_show(struct device *dev,
>  static DEVICE_ATTR(suspend_standby_state, 0444,
>               regulator_suspend_standby_state_show, NULL);
>  
> +static ssize_t regulator_bypass_show(struct device *dev,
> +                                  struct device_attribute *attr, char *buf)
> +{
> +     struct regulator_dev *rdev = dev_get_drvdata(dev);
> +     const char *report;
> +     bool bypass;
> +     int ret;
> +
> +     ret = rdev->desc->ops->get_bypass(rdev, &bypass);
> +
> +     if (ret != 0)
> +             report = "unknown";
> +     else if (bypass)
> +             report = "enabled";
> +     else
> +             report = "disabled";
> +
> +     return sprintf(buf, "%s\n", report);
> +}
> +static DEVICE_ATTR(bypass, 0444,
> +                regulator_bypass_show, NULL);
>  
>  /*
>   * These are the only attributes are present for all regulators.
> @@ -2683,6 +2708,58 @@ out:
>  EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
>  
>  /**
> + * regulator_allow_bypass - allow the regulator to go into bypass mode
> + *
> + * @regulator: Regulator to configure
> + * @allow: 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
> + * constraints allow this.  Bypass mode means that the regulator is
> + * simply passing the input directly to the output with no regulation.
> + */
> +int regulator_allow_bypass(struct regulator *regulator, bool enable)
> +{
> +     struct regulator_dev *rdev = regulator->rdev;
> +     int ret = 0;
> +
> +     if (!rdev->desc->ops->set_bypass)
> +             return 0;
> +
> +     if (rdev->constraints &&
> +         !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS))
> +             return 0;
> +
> +     mutex_lock(&rdev->mutex);
> +
> +     if (enable && !regulator->bypass) {
> +             rdev->bypass_count++;
> +
> +             if (rdev->bypass_count == rdev->open_count) {
> +                     ret = rdev->desc->ops->set_bypass(rdev, enable);
> +                     if (ret != 0)
> +                             rdev->bypass_count--;
> +             }
> +
> +     } else if (!enable && regulator->bypass) {
> +             rdev->bypass_count--;
> +
> +             if (rdev->bypass_count != rdev->open_count) {
> +                     ret = rdev->desc->ops->set_bypass(rdev, enable);
> +                     if (ret != 0)
> +                             rdev->bypass_count++;
> +             }
> +     }
> +
> +     if (ret == 0)
> +             regulator->bypass = enable;
> +
> +     mutex_unlock(&rdev->mutex);
> +
> +     return ret;
> +}
> +
> +/**
>   * regulator_register_notifier - register regulator event notifier
>   * @regulator: regulator source
>   * @nb: notifier block
> @@ -3046,6 +3123,11 @@ static int add_regulator_attributes(struct 
> regulator_dev *rdev)
>               if (status < 0)
>                       return status;
>       }
> +     if (ops->get_bypass) {
> +             status = device_create_file(dev, &dev_attr_bypass);
> +             if (status < 0)
> +                     return status;
> +     }
>  
>       /* some attributes are type-specific */
>       if (rdev->desc->type == REGULATOR_CURRENT) {
> @@ -3134,6 +3216,8 @@ static void rdev_init_debugfs(struct regulator_dev 
> *rdev)
>                          &rdev->use_count);
>       debugfs_create_u32("open_count", 0444, rdev->debugfs,
>                          &rdev->open_count);
> +     debugfs_create_u32("bypass_count", 0444, rdev->debugfs,
> +                        &rdev->bypass_count);
>  }
>  
>  /**
> diff --git a/include/linux/regulator/consumer.h 
> b/include/linux/regulator/consumer.h
> index b987bcc..07838c9 100644
> --- a/include/linux/regulator/consumer.h
> +++ b/include/linux/regulator/consumer.h
> @@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, 
> unsigned int mode);
>  unsigned int regulator_get_mode(struct regulator *regulator);
>  int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
>  
> +int regulator_allow_bypass(struct regulator *regulator, bool allow);
> +
>  /* regulator notifier block */
>  int regulator_register_notifier(struct regulator *regulator,
>                             struct notifier_block *nb);
> @@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct 
> regulator *regulator,
>       return REGULATOR_MODE_NORMAL;
>  }
>  
> +static inline int regulator_allow_bypass(struct regulator *regulator,
> +                                      bool allow)
> +{
> +     return 0;
> +}
> +
>  static inline int regulator_register_notifier(struct regulator *regulator,
>                             struct notifier_block *nb)
>  {
> diff --git a/include/linux/regulator/driver.h 
> b/include/linux/regulator/driver.h
> index c10012f..2b2670b 100644
> --- a/include/linux/regulator/driver.h
> +++ b/include/linux/regulator/driver.h
> @@ -32,6 +32,8 @@ enum regulator_status {
>       REGULATOR_STATUS_NORMAL,
>       REGULATOR_STATUS_IDLE,
>       REGULATOR_STATUS_STANDBY,
> +     /* The regulator is enabled but not regulating */
> +     REGULATOR_STATUS_BYPASS,
>       /* in case that any other status doesn't apply */
>       REGULATOR_STATUS_UNDEFINED,
>  };
> @@ -68,6 +70,9 @@ enum regulator_status {
>   * @get_optimum_mode: Get the most efficient operating mode for the regulator
>   *                    when running with the specified parameters.
>   *
> + * @set_bypass: Set the regulator in bypass mode.
> + * @get_bypass: Get the regulator bypass mode state.
> + *
>   * @enable_time: Time taken for the regulator voltage output voltage to
>   *               stabilise after being enabled, in microseconds.
>   * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
> @@ -134,6 +139,10 @@ struct regulator_ops {
>       unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
>                                         int output_uV, int load_uA);
>  
> +     /* control and report on bypass mode */
> +     int (*set_bypass)(struct regulator_dev *dev, bool enable);
> +     int (*get_bypass)(struct regulator_dev *dev, bool *enable);
> +
>       /* the operations below are for configuration of regulator state when
>        * its parent PMIC enters a global STANDBY/HIBERNATE state */
>  
> @@ -254,6 +263,7 @@ struct regulator_dev {
>       int exclusive;
>       u32 use_count;
>       u32 open_count;
> +     u32 bypass_count;
>  
>       /* lists we belong to */
>       struct list_head list; /* list of all regulators */
> diff --git a/include/linux/regulator/machine.h 
> b/include/linux/regulator/machine.h
> index 40dd0a3..36adbc8 100644
> --- a/include/linux/regulator/machine.h
> +++ b/include/linux/regulator/machine.h
> @@ -32,6 +32,7 @@ struct regulator;
>   *           board/machine.
>   * STATUS:   Regulator can be enabled and disabled.
>   * DRMS:     Dynamic Regulator Mode Switching is enabled for this regulator.
> + * BYPASS:   Regulator can be put into bypass mode
>   */
>  
>  #define REGULATOR_CHANGE_VOLTAGE     0x1
> @@ -39,6 +40,7 @@ struct regulator;
>  #define REGULATOR_CHANGE_MODE                0x4
>  #define REGULATOR_CHANGE_STATUS              0x8
>  #define REGULATOR_CHANGE_DRMS                0x10
> +#define REGULATOR_CHANGE_BYPASS              0x20
>  
>  /**
>   * struct regulator_state - regulator state during low power system states

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to