From 69d588392b057c0cedb1ba58d7973b77a65997ec Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 4 Jun 2014 14:53:25 -0500 Subject: regulator: core: print error value when constraints are not applied With commit 064d5cd110f94ce41ca5681dcda8b77fa63d5b95 (regulator: core: Fix the init of DT defined fixed regulators) We ensure that regulator must be capable of providing it's current voltage when constraints are used, however adding the return value in the print is a little more informative to explain the nature of the failure involved. So, instead of providing message such as: smps9: failed to get the current voltage having error value added to the message such as: smps9: failed to get the current voltage(-22) is a little more informative for debugging the error. Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown --- drivers/regulator/core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/regulator/core.c') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 4c1f999041dd..b4902ab64abe 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -846,7 +846,9 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->min_uV == rdev->constraints->max_uV) { int current_uV = _regulator_get_voltage(rdev); if (current_uV < 0) { - rdev_err(rdev, "failed to get the current voltage\n"); + rdev_err(rdev, + "failed to get the current voltage(%d)\n", + current_uV); return current_uV; } if (current_uV < rdev->constraints->min_uV || @@ -856,8 +858,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->max_uV); if (ret < 0) { rdev_err(rdev, - "failed to apply %duV constraint\n", - rdev->constraints->min_uV); + "failed to apply %duV constraint(%d)\n", + rdev->constraints->min_uV, ret); return ret; } } -- cgit v1.2.3 From 778b28b4348af9c72bb5ac0dc129363a706325ef Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Jun 2014 17:55:54 +0100 Subject: regulator: core: convert to use gpio_desc internally Convert the regulator GPIO handling to use a gpio descriptor rather than numbers. This allows us to revise the interfaces to permit all GPIOs to be used with the regulator core. Signed-off-by: Russell King Signed-off-by: Mark Brown --- drivers/regulator/core.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/regulator/core.c') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 4c1f999041dd..03ce33387a5d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,7 @@ struct regulator_map { */ struct regulator_enable_gpio { struct list_head list; - int gpio; + struct gpio_desc *gpiod; u32 enable_count; /* a number of enabled shared GPIO */ u32 request_count; /* a number of requested shared GPIO */ unsigned int ena_gpio_invert:1; @@ -1660,10 +1661,13 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev, const struct regulator_config *config) { struct regulator_enable_gpio *pin; + struct gpio_desc *gpiod; int ret; + gpiod = gpio_to_desc(config->ena_gpio); + list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { - if (pin->gpio == config->ena_gpio) { + if (pin->gpiod == gpiod) { rdev_dbg(rdev, "GPIO %d is already used\n", config->ena_gpio); goto update_ena_gpio_to_rdev; @@ -1682,7 +1686,7 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev, return -ENOMEM; } - pin->gpio = config->ena_gpio; + pin->gpiod = gpiod; pin->ena_gpio_invert = config->ena_gpio_invert; list_add(&pin->list, ®ulator_ena_gpio_list); @@ -1701,10 +1705,10 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev) /* Free the GPIO only in case of no use */ list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { - if (pin->gpio == rdev->ena_pin->gpio) { + if (pin->gpiod == rdev->ena_pin->gpiod) { if (pin->request_count <= 1) { pin->request_count = 0; - gpio_free(pin->gpio); + gpiod_put(pin->gpiod); list_del(&pin->list); kfree(pin); } else { @@ -1732,8 +1736,8 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) if (enable) { /* Enable GPIO at initial use */ if (pin->enable_count == 0) - gpio_set_value_cansleep(pin->gpio, - !pin->ena_gpio_invert); + gpiod_set_value_cansleep(pin->gpiod, + !pin->ena_gpio_invert); pin->enable_count++; } else { @@ -1744,8 +1748,8 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) /* Disable GPIO if not used */ if (pin->enable_count <= 1) { - gpio_set_value_cansleep(pin->gpio, - pin->ena_gpio_invert); + gpiod_set_value_cansleep(pin->gpiod, + pin->ena_gpio_invert); pin->enable_count = 0; } } -- cgit v1.2.3 From 04eca28cde52cdf9eb91e127cc358ad79a8ec53b Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 21 Jul 2014 18:38:48 +0300 Subject: regulator: Add helpers for low-level register access Add helper functions that allow regulator consumers to obtain low-level details about the regulator hardware, like the voltage selector register address and such. These details can be useful when configuring hardware or firmware that want to do low-level access to regulators, with no involvement from the kernel. The use-case for Tegra is a voltage-controlled oscillator clocksource which has control logic to change the supply voltage via I2C to achieve a desired output clock rate. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mark Brown --- Documentation/power/regulator/consumer.txt | 35 +++++++++++++++ drivers/regulator/core.c | 71 ++++++++++++++++++++++++++++++ include/linux/regulator/consumer.h | 26 +++++++++++ 3 files changed, 132 insertions(+) (limited to 'drivers/regulator/core.c') diff --git a/Documentation/power/regulator/consumer.txt b/Documentation/power/regulator/consumer.txt index 55c4175d8099..81c0e2b49cd8 100644 --- a/Documentation/power/regulator/consumer.txt +++ b/Documentation/power/regulator/consumer.txt @@ -180,3 +180,38 @@ int regulator_unregister_notifier(struct regulator *regulator, Regulators use the kernel notifier framework to send event to their interested consumers. + +7. Regulator Direct Register Access +=================================== +Some kinds of power management hardware or firmware are designed such that +they need to do low-level hardware access to regulators, with no involvement +from the kernel. Examples of such devices are: + +- clocksource with a voltage-controlled oscillator and control logic to change + the supply voltage over I2C to achieve a desired output clock rate +- thermal management firmware that can issue an arbitrary I2C transaction to + perform system poweroff during overtemperature conditions + +To set up such a device/firmware, various parameters like I2C address of the +regulator, addresses of various regulator registers etc. need to be configured +to it. The regulator framework provides the following helpers for querying +these details. + +Bus-specific details, like I2C addresses or transfer rates are handled by the +regmap framework. To get the regulator's regmap (if supported), use :- + +struct regmap *regulator_get_regmap(struct regulator *regulator); + +To obtain the hardware register offset and bitmask for the regulator's voltage +selector register, use :- + +int regulator_get_hardware_vsel_register(struct regulator *regulator, + unsigned *vsel_reg, + unsigned *vsel_mask); + +To convert a regulator framework voltage selector code (used by +regulator_list_voltage) to a hardware-specific voltage selector that can be +directly written to the voltage selector register, use :- + +int regulator_list_hardware_vsel(struct regulator *regulator, + unsigned selector); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 4c1f999041dd..486b5908469e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2221,6 +2221,77 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) } EXPORT_SYMBOL_GPL(regulator_list_voltage); +/** + * regulator_get_regmap - get the regulator's register map + * @regulator: regulator source + * + * Returns the register map for the given regulator, or an ERR_PTR value + * if the regulator doesn't use regmap. + */ +struct regmap *regulator_get_regmap(struct regulator *regulator) +{ + struct regmap *map = regulator->rdev->regmap; + + return map ? map : ERR_PTR(-EOPNOTSUPP); +} + +/** + * regulator_get_hardware_vsel_register - get the HW voltage selector register + * @regulator: regulator source + * @vsel_reg: voltage selector register, output parameter + * @vsel_mask: mask for voltage selector bitfield, output parameter + * + * Returns the hardware register offset and bitmask used for setting the + * regulator voltage. This might be useful when configuring voltage-scaling + * hardware or firmware that can make I2C requests behind the kernel's back, + * for example. + * + * On success, the output parameters @vsel_reg and @vsel_mask are filled in + * and 0 is returned, otherwise a negative errno is returned. + */ +int regulator_get_hardware_vsel_register(struct regulator *regulator, + unsigned *vsel_reg, + unsigned *vsel_mask) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator_ops *ops = rdev->desc->ops; + + if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) + return -EOPNOTSUPP; + + *vsel_reg = rdev->desc->vsel_reg; + *vsel_mask = rdev->desc->vsel_mask; + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); + +/** + * regulator_list_hardware_vsel - get the HW-specific register value for a selector + * @regulator: regulator source + * @selector: identify voltage to list + * + * Converts the selector to a hardware-specific voltage selector that can be + * directly written to the regulator registers. The address of the voltage + * register can be determined by calling @regulator_get_hardware_vsel_register. + * + * On error a negative errno is returned. + */ +int regulator_list_hardware_vsel(struct regulator *regulator, + unsigned selector) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator_ops *ops = rdev->desc->ops; + + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) + return -EOPNOTSUPP; + + return selector; +} +EXPORT_SYMBOL_GPL(regulator_list_hardware_vsel); + /** * regulator_get_linear_step - return the voltage step size between VSEL values * @regulator: regulator source diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index a2d9d81038d1..0b1c8d09a6b1 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -37,6 +37,7 @@ struct device; struct notifier_block; +struct regmap; /* * Regulator operating modes. @@ -215,6 +216,13 @@ int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); int regulator_allow_bypass(struct regulator *regulator, bool allow); +struct regmap *regulator_get_regmap(struct regulator *regulator); +int regulator_get_hardware_vsel_register(struct regulator *regulator, + unsigned *vsel_reg, + unsigned *vsel_mask); +int regulator_list_hardware_vsel(struct regulator *regulator, + unsigned selector); + /* regulator notifier block */ int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb); @@ -452,6 +460,24 @@ static inline int regulator_allow_bypass(struct regulator *regulator, return 0; } +struct regmap *regulator_get_regmap(struct regulator *regulator) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +int regulator_get_hardware_vsel_register(struct regulator *regulator, + unsigned *vsel_reg, + unsigned *vsel_mask) +{ + return -EOPNOTSUPP; +} + +int regulator_list_hardware_vsel(struct regulator *regulator, + unsigned selector) +{ + return -EOPNOTSUPP; +} + static inline int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb) { -- cgit v1.2.3 From e303996e94b8705c85f3d78f3c094d05b0620c9d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 29 Jul 2014 18:28:55 +0200 Subject: regulator: core: Get voltage from parent if not available Load switches are modeled as regulators but they just provide the voltage of their parent input supply. So the drivers for these switches usually don't provide a .get_voltage function handler but there is code in the kernel that assumes that all regulators should be able to provide its current voltage rail. So, if the output voltage for a regulator is not available and it has a parent supply, then pass the voltage of its parent. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/regulator/core.c') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b4902ab64abe..57fe446fabce 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2620,6 +2620,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) 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 if (rdev->supply) { + ret = regulator_get_voltage(rdev->supply); } else { return -EINVAL; } -- cgit v1.2.3 From 26988efe11b1dc44853035122927ced25578f302 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 29 Jul 2014 18:28:56 +0200 Subject: regulator: core: Allow to get voltage count and list from parent Load switches are modeled as regulators but they just provide the voltage of their parent input supply. So, the drivers for these switches usually neither provide a .list_voltage handler not set a .n_voltages count. But there is code in the kernel that assumes that all regulators should be able to provide this information (e.g: cpufreq and mmc subsystems). If the voltage count and list are not available for a regulator and it has a parent input supply, then use the parent values. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/core.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/regulator/core.c') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 57fe446fabce..5299456d07ee 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2182,7 +2182,13 @@ int regulator_count_voltages(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; - return rdev->desc->n_voltages ? : -EINVAL; + if (rdev->desc->n_voltages) + return rdev->desc->n_voltages; + + if (!rdev->supply) + return -EINVAL; + + return regulator_count_voltages(rdev->supply); } EXPORT_SYMBOL_GPL(regulator_count_voltages); @@ -2205,12 +2211,17 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) return rdev->desc->fixed_uV; - if (!ops->list_voltage || selector >= rdev->desc->n_voltages) + if (ops->list_voltage) { + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + mutex_lock(&rdev->mutex); + ret = ops->list_voltage(rdev, selector); + mutex_unlock(&rdev->mutex); + } else if (rdev->supply) { + ret = regulator_list_voltage(rdev->supply, selector); + } else { return -EINVAL; - - mutex_lock(&rdev->mutex); - ret = ops->list_voltage(rdev, selector); - mutex_unlock(&rdev->mutex); + } if (ret > 0) { if (ret < rdev->constraints->min_uV) -- cgit v1.2.3