Skip to content

Commit

Permalink
Merge remote-tracking branches 'regulator/topic/da9211', 'regulator/t…
Browse files Browse the repository at this point in the history
…opic/getreg', 'regulator/topic/gpio' and 'regulator/topic/lp872x' into regulator-next
  • Loading branch information
broonie committed Aug 5, 2014
5 parents 862f9f8 + 516c151 + 3bc0312 + 778b28b + 404d4df commit a627506
Show file tree
Hide file tree
Showing 9 changed files with 827 additions and 18 deletions.
35 changes: 35 additions & 0 deletions Documentation/power/regulator/consumer.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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);
10 changes: 10 additions & 0 deletions drivers/regulator/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,16 @@ config REGULATOR_DA9210
converter 12A DC-DC Buck controlled through an I2C
interface.

config REGULATOR_DA9211
tristate "Dialog Semiconductor DA9211/DA9212 regulator"
depends on I2C
select REGMAP_I2C
help
Say y here to support for the Dialog Semiconductor DA9211/DA9212.
The DA9211/DA9212 is a multi-phase synchronous step down
converter 12A DC-DC Buck controlled through an I2C
interface.

config REGULATOR_DBX500_PRCMU
bool

Expand Down
1 change: 1 addition & 0 deletions drivers/regulator/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
obj-$(CONFIG_REGULATOR_DA9063) += da9063-regulator.o
obj-$(CONFIG_REGULATOR_DA9210) += da9210-regulator.o
obj-$(CONFIG_REGULATOR_DA9211) += da9211-regulator.o
obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
Expand Down
93 changes: 84 additions & 9 deletions drivers/regulator/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/suspend.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1662,10 +1663,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, &regulator_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;
Expand All @@ -1684,7 +1688,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, &regulator_ena_gpio_list);

Expand All @@ -1703,10 +1707,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, &regulator_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 {
Expand Down Expand Up @@ -1734,8 +1738,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 {
Expand All @@ -1746,8 +1750,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;
}
}
Expand Down Expand Up @@ -2234,6 +2238,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
Expand Down
Loading

0 comments on commit a627506

Please sign in to comment.