regulator: Updates for v4.4

This is quite a quiet release in terms of volume of patches but it
 includes a couple of really nice core changes - the work Sascha has done
 in particular is something I've wanted to get done for a long time but
 just never got round to myself.  Highlights include:
 
  - Support from Sascha Hauer for setting the voltage of parent supplies
    based on requests from their children.  This is used both to allow
    set_voltage() to work through a dumb switch and to improve the
    efficiency of systems where DCDCs are used to supply LDOs by minimising
    the voltage drop over the LDOs.
  - Removal of regulator_list by Tomeu Vizoso, meaning we're not
    duplicating the device list maintained by the driver core.
  - Support for Wolfson/Cirrus WM8998 and WM1818.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJWOez1AAoJECTWi3JdVIfQZSoH/jk2EQCG7hSIY6qVviHh+zQI
 TWULXDnldyfT4eCYNAhwe/oQjFs7ngPXz9UpMAQwtWfWNoLBifF+Y5+X413nHY82
 pKoRd+DQ1sIzGZb2YB0kS22Zg49Jilgv3y2Cw0aZuL7aqq7CEUGN3itEeWxqW9j8
 a1ORD4d2zgki4gK9fUBTiur/dIhMn+8Gi4CmBvujsSCQR4Z5UNOjiodTU0NONiBX
 znejoAoLJXzAyAoWN+p6sEvi9Gpx4QTV6tBOo56WPlzBgTX2qOFhhmJiQQ1rIJOv
 MucgNn+cocarWfMyQwvqa0CL4ufjJm2DcYoIhfc2jZip/mAeqcbxpj5bxWzaLec=
 =CX2S
 -----END PGP SIGNATURE-----

Merge tag 'regulator-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator

Pull regulator updates from Mark Brown:
 "This is quite a quiet release in terms of volume of patches but it
  includes a couple of really nice core changes - the work Sascha has
  done in particular is something I've wanted to get done for a long
  time but just never got round to myself.

  Highlights include:

   - Support from Sascha Hauer for setting the voltage of parent
     supplies based on requests from their children.  This is used both
     to allow set_voltage() to work through a dumb switch and to improve
     the efficiency of systems where DCDCs are used to supply LDOs by
     minimising the voltage drop over the LDOs.

   - Removal of regulator_list by Tomeu Vizoso, meaning we're not
     duplicating the device list maintained by the driver core.

   - Support for Wolfson/Cirrus WM8998 and WM1818"

* tag 'regulator-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (29 commits)
  regulator: Use regulator_lock_supply() for get_voltage() too
  regulator: arizona: Add regulator specific device tree binding document
  regulator: stw481x: compile on COMPILE_TEST
  regulator: qcom-smd: Correct set_load() unit
  regulator: core: Propagate voltage changes to supply regulators
  regulator: core: Factor out regulator_map_voltage
  regulator: i.MX anatop: Allow supply regulator
  regulator: introduce min_dropout_uV
  regulator: core: create unlocked version of regulator_set_voltage
  regulator: arizona-ldo1: Fix handling of GPIO 0
  regulator: da9053: Update regulator for DA9053 BC silicon support
  regulator: max77802: Separate sections for nodes and properties
  regulator: max77802: Add input supply properties to DT binding doc
  regulator: axp20x: set supply names for AXP22X DC1SW/DC5LDO internally
  regulator: axp20x: Drop AXP221 DC1SW and DC5LDO regulator supplies from bindings
  mfd: tps6105x: Use i2c regmap to access registers
  regulator: act8865: add DT binding for property "active-semi,vsel-high"
  regulator: act8865: support output voltage by VSET2[] bits
  regulator: arizona: add support for WM8998 and WM1814
  regulator: core: create unlocked version of regulator_list_voltage
  ...
This commit is contained in:
Linus Torvalds 2015-11-05 13:06:22 -08:00
commit 52787e91bf
24 changed files with 733 additions and 460 deletions

View File

@ -60,8 +60,8 @@ DCDC2 : DC-DC buck : vin2-supply
DCDC3 : DC-DC buck : vin3-supply
DCDC4 : DC-DC buck : vin4-supply
DCDC5 : DC-DC buck : vin5-supply
DC1SW : On/Off Switch : dcdc1-supply : DCDC1 secondary output
DC5LDO : LDO : dcdc5-supply : input from DCDC5
DC1SW : On/Off Switch : : DCDC1 secondary output
DC5LDO : LDO : : input from DCDC5
ALDO1 : LDO : aldoin-supply : shared supply
ALDO2 : LDO : aldoin-supply : shared supply
ALDO3 : LDO : aldoin-supply : shared supply

View File

@ -8,6 +8,8 @@ Required properties:
Optional properties:
- system-power-controller: Telling whether or not this pmic is controlling
the system power. See Documentation/devicetree/bindings/power/power-controller.txt .
- active-semi,vsel-high: Indicates the VSEL pin is high.
If this property is missing, assume the VSEL pin is low(0).
Optional input supply properties:
- for act8600:
@ -49,6 +51,7 @@ Example:
pmic: act8865@5b {
compatible = "active-semi,act8865";
reg = <0x5b>;
active-semi,vsel-high;
status = "disabled";
regulators {

View File

@ -13,6 +13,7 @@ Optional properties:
- anatop-delay-reg-offset: Anatop MFD step time register offset
- anatop-delay-bit-shift: Bit shift for the step time register
- anatop-delay-bit-width: Number of bits used in the step time register
- vin-supply: The supply for this regulator
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.

View File

@ -0,0 +1,17 @@
Cirrus Logic Arizona class audio SoCs
These devices are audio SoCs with extensive digital capabilities and a range
of analogue I/O.
This document lists regulator specific bindings, see the primary binding
document:
../mfd/arizona.txt
Optional properties:
- wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA
Optional subnodes:
- ldo1 : Initial data for the LDO1 regulator, as covered in
Documentation/devicetree/bindings/regulator/regulator.txt
- micvdd : Initial data for the MICVDD regulator, as covered in
Documentation/devicetree/bindings/regulator/regulator.txt

View File

@ -8,7 +8,28 @@ regulators that can be controlled over I2C.
Following properties should be present in main device node of the MFD chip.
Optional node:
Optional properties:
- inb1-supply: The input supply for BUCK1
- inb2-supply: The input supply for BUCK2
- inb3-supply: The input supply for BUCK3
- inb4-supply: The input supply for BUCK4
- inb5-supply: The input supply for BUCK5
- inb6-supply: The input supply for BUCK6
- inb7-supply: The input supply for BUCK7
- inb8-supply: The input supply for BUCK8
- inb9-supply: The input supply for BUCK9
- inb10-supply: The input supply for BUCK10
- inl1-supply: The input supply for LDO8 and LDO15
- inl2-supply: The input supply for LDO17, LDO27, LDO30 and LDO35
- inl3-supply: The input supply for LDO3, LDO5, LDO6 and LDO7
- inl4-supply: The input supply for LDO10, LDO11, LDO13 and LDO14
- inl5-supply: The input supply for LDO9 and LDO19
- inl6-supply: The input supply for LDO4, LDO21, LDO24 and LDO33
- inl7-supply: The input supply for LDO18, LDO20, LDO28 and LDO29
- inl9-supply: The input supply for LDO12, LDO23, LDO25, LDO26, LDO32 and LDO34
- inl10-supply: The input supply for LDO1 and LDO2
Optional nodes:
- regulators : The regulators of max77802 have to be instantiated
under subnode named "regulators" using the following format.
@ -58,6 +79,8 @@ Example:
#address-cells = <1>;
#size-cells = <0>;
inb1-supply = <&parent_reg>;
regulators {
ldo1_reg: LDO1 {
regulator-name = "vdd_1v0";

View File

@ -11,6 +11,7 @@ Optional properties:
- regulator-always-on: boolean, regulator should never be disabled
- regulator-boot-on: bootloader/firmware enabled regulator
- regulator-allow-bypass: allow the regulator to go into bypass mode
- regulator-allow-set-load: allow the regulator performance level to be configured
- <name>-supply: phandle to the parent supply/regulator node
- regulator-ramp-delay: ramp delay for regulator(in uV/uS)
For hardware which supports disabling ramp rate, it should be explicitly

View File

@ -0,0 +1,60 @@
TPS65023 family of regulators
Required properties:
- compatible: Must be one of the following.
"ti,tps65020",
"ti,tps65021",
"ti,tps65023",
- reg: I2C slave address
- regulators: list of regulators provided by this controller, must be named
after their hardware counterparts: VDCDC[1-3] and LDO[1-2]
- regulators: This is the list of child nodes that specify the regulator
initialization data for defined regulators. The definition for each of
these nodes is defined using the standard binding for regulators found at
Documentation/devicetree/bindings/regulator/regulator.txt.
Each regulator is defined using the standard binding for regulators.
Example:
tps65023@48 {
compatible = "ti,tps65023";
reg = <0x48>;
regulators {
VDCDC1 {
regulator-name = "vdd_mpu";
regulator-always-on;
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
VDCDC2 {
regulator-name = "vdd_core";
regulator-always-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
VDCDC3 {
regulator-name = "vdd_io";
regulator-always-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
LDO1 {
regulator-name = "vdd_usb18";
regulator-always-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
LDO2 {
regulator-name = "vdd_usb33";
regulator-always-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
};
};

View File

@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@ -25,73 +25,18 @@
#include <linux/mfd/core.h>
#include <linux/mfd/tps6105x.h>
int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value)
{
int ret;
ret = mutex_lock_interruptible(&tps6105x->lock);
if (ret)
return ret;
ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value);
mutex_unlock(&tps6105x->lock);
if (ret < 0)
return ret;
return 0;
}
EXPORT_SYMBOL(tps6105x_set);
int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf)
{
int ret;
ret = mutex_lock_interruptible(&tps6105x->lock);
if (ret)
return ret;
ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
mutex_unlock(&tps6105x->lock);
if (ret < 0)
return ret;
*buf = ret;
return 0;
}
EXPORT_SYMBOL(tps6105x_get);
/*
* Masks off the bits in the mask and sets the bits in the bitvalues
* parameter in one atomic operation
*/
int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
u8 bitmask, u8 bitvalues)
{
int ret;
u8 regval;
ret = mutex_lock_interruptible(&tps6105x->lock);
if (ret)
return ret;
ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
if (ret < 0)
goto fail;
regval = ret;
regval = (~bitmask & regval) | (bitmask & bitvalues);
ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval);
fail:
mutex_unlock(&tps6105x->lock);
if (ret < 0)
return ret;
return 0;
}
EXPORT_SYMBOL(tps6105x_mask_and_set);
static struct regmap_config tps6105x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = TPS6105X_REG_3,
};
static int tps6105x_startup(struct tps6105x *tps6105x)
{
int ret;
u8 regval;
unsigned int regval;
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
if (ret)
return ret;
switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
@ -145,11 +90,14 @@ static int tps6105x_probe(struct i2c_client *client,
if (!tps6105x)
return -ENOMEM;
tps6105x->regmap = devm_regmap_init_i2c(client, &tps6105x_regmap_config);
if (IS_ERR(tps6105x->regmap))
return PTR_ERR(tps6105x->regmap);
i2c_set_clientdata(client, tps6105x);
tps6105x->client = client;
pdata = dev_get_platdata(&client->dev);
tps6105x->pdata = pdata;
mutex_init(&tps6105x->lock);
ret = tps6105x_startup(tps6105x);
if (ret) {
@ -198,7 +146,7 @@ static int tps6105x_remove(struct i2c_client *client)
mfd_remove_devices(&client->dev);
/* Put chip in shutdown mode */
tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_MODE_MASK,
TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);

View File

@ -627,7 +627,7 @@ config REGULATOR_TI_ABB
config REGULATOR_STW481X_VMMC
bool "ST Microelectronics STW481X VMMC regulator"
depends on MFD_STW481X
depends on MFD_STW481X || COMPILE_TEST
default y if MFD_STW481X
help
This driver supports the internal VMMC regulator in the STw481x

View File

@ -261,6 +261,16 @@ static const struct regulator_desc act8865_regulators[] = {
ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
};
static const struct regulator_desc act8865_alt_regulators[] = {
ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET2, "vp1"),
ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET2, "vp2"),
ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET2, "vp3"),
ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
};
#ifdef CONFIG_OF
static const struct of_device_id act8865_dt_ids[] = {
{ .compatible = "active-semi,act8600", .data = (void *)ACT8600 },
@ -413,6 +423,7 @@ static int act8865_pmic_probe(struct i2c_client *client,
struct act8865 *act8865;
unsigned long type;
int off_reg, off_mask;
int voltage_select = 0;
pdata = dev_get_platdata(dev);
@ -424,6 +435,10 @@ static int act8865_pmic_probe(struct i2c_client *client,
return -ENODEV;
type = (unsigned long) id->data;
voltage_select = !!of_get_property(dev->of_node,
"active-semi,vsel-high",
NULL);
} else {
type = i2c_id->driver_data;
}
@ -442,8 +457,13 @@ static int act8865_pmic_probe(struct i2c_client *client,
off_mask = ACT8846_OFF_SYSMASK;
break;
case ACT8865:
regulators = act8865_regulators;
num_regulators = ARRAY_SIZE(act8865_regulators);
if (voltage_select) {
regulators = act8865_alt_regulators;
num_regulators = ARRAY_SIZE(act8865_alt_regulators);
} else {
regulators = act8865_regulators;
num_regulators = ARRAY_SIZE(act8865_regulators);
}
off_reg = ACT8865_SYS_CTRL;
off_mask = ACT8865_MSTROFF;
break;

View File

@ -30,6 +30,7 @@
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
@ -199,6 +200,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
rdesc->owner = THIS_MODULE;
initdata = of_get_regulator_init_data(dev, np, rdesc);
initdata->supply_regulator = "vin";
sreg->initdata = initdata;
anatop_np = of_get_parent(np);
@ -262,6 +264,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
rdesc->vsel_reg = sreg->control_reg;
rdesc->vsel_mask = ((1 << sreg->vol_bit_width) - 1) <<
sreg->vol_bit_shift;
rdesc->min_dropout_uV = 125000;
config.dev = &pdev->dev;
config.init_data = initdata;

View File

@ -17,6 +17,7 @@
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@ -189,13 +190,22 @@ static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
{
struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_ldo1 *ldo1 = config->driver_data;
struct device_node *np = arizona->dev->of_node;
struct device_node *init_node, *dcvdd_node;
struct regulator_init_data *init_data;
pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true);
pdata->ldoena = of_get_named_gpio(np, "wlf,ldoena", 0);
if (pdata->ldoena < 0) {
dev_warn(arizona->dev,
"LDOENA GPIO property missing/malformed: %d\n",
pdata->ldoena);
pdata->ldoena = 0;
} else {
config->ena_gpio_initialized = true;
}
init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1");
dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0);
init_node = of_get_child_by_name(np, "ldo1");
dcvdd_node = of_parse_phandle(np, "DCVDD-supply", 0);
if (init_node) {
config->of_node = init_node;
@ -245,6 +255,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
switch (arizona->type) {
case WM5102:
case WM8997:
case WM8998:
case WM1814:
desc = &arizona_ldo1_hc;
ldo1->init_data = arizona_ldo1_dvfs;
break;
@ -272,8 +284,6 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
ret = arizona_ldo1_of_get_pdata(arizona, &config, desc);
if (ret < 0)
return ret;
config.ena_gpio_initialized = true;
}
}

View File

@ -196,10 +196,10 @@ static const struct regulator_desc axp22x_regulators[] = {
AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50,
AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)),
/* secondary switchable output of DCDC1 */
AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", "dcdc1", 1600, 3400, 100,
AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, 1600, 3400, 100,
AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(7)),
/* LDO regulator internally chained to DCDC5 */
AXP_DESC(AXP22X, DC5LDO, "dc5ldo", "dcdc5", 700, 1400, 100,
AXP_DESC(AXP22X, DC5LDO, "dc5ldo", NULL, 700, 1400, 100,
AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)),
AXP_DESC(AXP22X, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)),
@ -350,6 +350,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
};
int ret, i, nregulators;
u32 workmode;
const char *axp22x_dc1_name = axp22x_regulators[AXP22X_DCDC1].name;
const char *axp22x_dc5_name = axp22x_regulators[AXP22X_DCDC5].name;
switch (axp20x->variant) {
case AXP202_ID:
@ -371,8 +373,37 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
axp20x_regulator_parse_dt(pdev);
for (i = 0; i < nregulators; i++) {
rdev = devm_regulator_register(&pdev->dev, &regulators[i],
&config);
const struct regulator_desc *desc = &regulators[i];
struct regulator_desc *new_desc;
/*
* Regulators DC1SW and DC5LDO are connected internally,
* so we have to handle their supply names separately.
*
* We always register the regulators in proper sequence,
* so the supply names are correctly read. See the last
* part of this loop to see where we save the DT defined
* name.
*/
if (regulators == axp22x_regulators) {
if (i == AXP22X_DC1SW) {
new_desc = devm_kzalloc(&pdev->dev,
sizeof(*desc),
GFP_KERNEL);
*new_desc = regulators[i];
new_desc->supply_name = axp22x_dc1_name;
desc = new_desc;
} else if (i == AXP22X_DC5LDO) {
new_desc = devm_kzalloc(&pdev->dev,
sizeof(*desc),
GFP_KERNEL);
*new_desc = regulators[i];
new_desc->supply_name = axp22x_dc5_name;
desc = new_desc;
}
}
rdev = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "Failed to register %s\n",
regulators[i].name);
@ -388,6 +419,21 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to set workmode on %s\n",
rdev->desc->name);
}
/*
* Save AXP22X DCDC1 / DCDC5 regulator names for later.
*/
if (regulators == axp22x_regulators) {
/* Can we use rdev->constraints->name instead? */
if (i == AXP22X_DCDC1)
of_property_read_string(rdev->dev.of_node,
"regulator-name",
&axp22x_dc1_name);
else if (i == AXP22X_DCDC5)
of_property_read_string(rdev->dev.of_node,
"regulator-name",
&axp22x_dc5_name);
}
}
return 0;

View File

@ -244,7 +244,7 @@ static int bcm590xx_get_enable_register(int id)
break;
case BCM590XX_REG_VBUS:
reg = BCM590XX_OTG_CTRL;
};
}
return reg;

View File

@ -51,7 +51,6 @@
pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
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 LIST_HEAD(regulator_supply_alias_list);
@ -59,6 +58,8 @@ static bool has_full_constraints;
static struct dentry *debugfs_root;
static struct class regulator_class;
/*
* struct regulator_map
*
@ -131,6 +132,45 @@ static bool have_full_constraints(void)
return has_full_constraints || of_have_populated_dt();
}
/**
* regulator_lock_supply - lock a regulator and its supplies
* @rdev: regulator source
*/
static void regulator_lock_supply(struct regulator_dev *rdev)
{
struct regulator *supply;
int i = 0;
while (1) {
mutex_lock_nested(&rdev->mutex, i++);
supply = rdev->supply;
if (!rdev->supply)
return;
rdev = supply->rdev;
}
}
/**
* regulator_unlock_supply - unlock a regulator and its supplies
* @rdev: regulator source
*/
static void regulator_unlock_supply(struct regulator_dev *rdev)
{
struct regulator *supply;
while (1) {
mutex_unlock(&rdev->mutex);
supply = rdev->supply;
if (!rdev->supply)
return;
rdev = supply->rdev;
}
}
/**
* of_get_regulator - get a regulator device node based on supply name
* @dev: Device pointer for the consumer (of regulator) device
@ -180,7 +220,7 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
rdev_err(rdev, "operation not allowed\n");
rdev_err(rdev, "voltage operation not allowed\n");
return -EPERM;
}
@ -240,7 +280,7 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
rdev_err(rdev, "operation not allowed\n");
rdev_err(rdev, "current operation not allowed\n");
return -EPERM;
}
@ -277,7 +317,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
rdev_err(rdev, "operation not allowed\n");
rdev_err(rdev, "mode operation not allowed\n");
return -EPERM;
}
@ -301,7 +341,7 @@ static int regulator_check_drms(struct regulator_dev *rdev)
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
rdev_dbg(rdev, "operation not allowed\n");
rdev_dbg(rdev, "drms operation not allowed\n");
return -EPERM;
}
return 0;
@ -1325,6 +1365,47 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
}
}
static int of_node_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
static struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
{
struct device *dev;
dev = class_find_device(&regulator_class, NULL, np, of_node_match);
return dev ? dev_to_rdev(dev) : NULL;
}
static int regulator_match(struct device *dev, const void *data)
{
struct regulator_dev *r = dev_to_rdev(dev);
return strcmp(rdev_get_name(r), data) == 0;
}
static struct regulator_dev *regulator_lookup_by_name(const char *name)
{
struct device *dev;
dev = class_find_device(&regulator_class, NULL, name, regulator_match);
return dev ? dev_to_rdev(dev) : NULL;
}
/**
* regulator_dev_lookup - lookup a regulator device.
* @dev: device for regulator "consumer".
* @supply: Supply name or regulator ID.
* @ret: 0 on success, -ENODEV if lookup fails permanently, -EPROBE_DEFER if
* lookup could succeed in the future.
*
* If successful, returns a struct regulator_dev that corresponds to the name
* @supply and with the embedded struct device refcount incremented by one,
* or NULL on failure. The refcount must be dropped by calling put_device().
*/
static struct regulator_dev *regulator_dev_lookup(struct device *dev,
const char *supply,
int *ret)
@ -1340,10 +1421,9 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
if (dev && dev->of_node) {
node = of_get_regulator(dev, supply);
if (node) {
list_for_each_entry(r, &regulator_list, list)
if (r->dev.parent &&
node == r->dev.of_node)
return r;
r = of_find_regulator_by_node(node);
if (r)
return r;
*ret = -EPROBE_DEFER;
return NULL;
} else {
@ -1361,20 +1441,24 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
if (dev)
devname = dev_name(dev);
list_for_each_entry(r, &regulator_list, list)
if (strcmp(rdev_get_name(r), supply) == 0)
return r;
r = regulator_lookup_by_name(supply);
if (r)
return r;
mutex_lock(&regulator_list_mutex);
list_for_each_entry(map, &regulator_map_list, list) {
/* If the mapping has a device set up it must match */
if (map->dev_name &&
(!devname || strcmp(map->dev_name, devname)))
continue;
if (strcmp(map->supply, supply) == 0)
if (strcmp(map->supply, supply) == 0 &&
get_device(&map->regulator->dev)) {
mutex_unlock(&regulator_list_mutex);
return map->regulator;
}
}
mutex_unlock(&regulator_list_mutex);
return NULL;
}
@ -1409,6 +1493,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (have_full_constraints()) {
r = dummy_regulator_rdev;
get_device(&r->dev);
} else {
dev_err(dev, "Failed to resolve %s-supply for %s\n",
rdev->supply_name, rdev->desc->name);
@ -1418,12 +1503,16 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
/* Recursively resolve the supply of the supply */
ret = regulator_resolve_supply(r);
if (ret < 0)
if (ret < 0) {
put_device(&r->dev);
return ret;
}
ret = set_supply(rdev, r);
if (ret < 0)
if (ret < 0) {
put_device(&r->dev);
return ret;
}
/* Cascade always-on state to supply */
if (_regulator_is_enabled(rdev) && rdev->supply) {
@ -1459,8 +1548,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
else
ret = -EPROBE_DEFER;
mutex_lock(&regulator_list_mutex);
rdev = regulator_dev_lookup(dev, id, &ret);
if (rdev)
goto found;
@ -1472,7 +1559,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
* succeed, so, quit with appropriate error value
*/
if (ret && ret != -ENODEV)
goto out;
return regulator;
if (!devname)
devname = "deviceless";
@ -1486,40 +1573,46 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
devname, id);
rdev = dummy_regulator_rdev;
get_device(&rdev->dev);
goto found;
/* Don't log an error when called from regulator_get_optional() */
} else if (!have_full_constraints() || exclusive) {
dev_warn(dev, "dummy supplies not allowed\n");
}
mutex_unlock(&regulator_list_mutex);
return regulator;
found:
if (rdev->exclusive) {
regulator = ERR_PTR(-EPERM);
goto out;
put_device(&rdev->dev);
return regulator;
}
if (exclusive && rdev->open_count) {
regulator = ERR_PTR(-EBUSY);
goto out;
put_device(&rdev->dev);
return regulator;
}
ret = regulator_resolve_supply(rdev);
if (ret < 0) {
regulator = ERR_PTR(ret);
goto out;
put_device(&rdev->dev);
return regulator;
}
if (!try_module_get(rdev->owner))
goto out;
if (!try_module_get(rdev->owner)) {
put_device(&rdev->dev);
return regulator;
}
regulator = create_regulator(rdev, dev, id);
if (regulator == NULL) {
regulator = ERR_PTR(-ENOMEM);
put_device(&rdev->dev);
module_put(rdev->owner);
goto out;
return regulator;
}
rdev->open_count++;
@ -1533,9 +1626,6 @@ found:
rdev->use_count = 0;
}
out:
mutex_unlock(&regulator_list_mutex);
return regulator;
}
@ -1633,6 +1723,7 @@ static void _regulator_put(struct regulator *regulator)
rdev->open_count--;
rdev->exclusive = 0;
put_device(&rdev->dev);
mutex_unlock(&rdev->mutex);
kfree(regulator->supply_name);
@ -2312,6 +2403,40 @@ static int _regulator_is_enabled(struct regulator_dev *rdev)
return rdev->desc->ops->is_enabled(rdev);
}
static int _regulator_list_voltage(struct regulator *regulator,
unsigned selector, int lock)
{
struct regulator_dev *rdev = regulator->rdev;
const struct regulator_ops *ops = rdev->desc->ops;
int ret;
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
return rdev->desc->fixed_uV;
if (ops->list_voltage) {
if (selector >= rdev->desc->n_voltages)
return -EINVAL;
if (lock)
mutex_lock(&rdev->mutex);
ret = ops->list_voltage(rdev, selector);
if (lock)
mutex_unlock(&rdev->mutex);
} else if (rdev->supply) {
ret = _regulator_list_voltage(rdev->supply, selector, lock);
} else {
return -EINVAL;
}
if (ret > 0) {
if (ret < rdev->constraints->min_uV)
ret = 0;
else if (ret > rdev->constraints->max_uV)
ret = 0;
}
return ret;
}
/**
* regulator_is_enabled - is the regulator output enabled
* @regulator: regulator source
@ -2401,33 +2526,7 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages);
*/
int regulator_list_voltage(struct regulator *regulator, unsigned selector)
{
struct regulator_dev *rdev = regulator->rdev;
const struct regulator_ops *ops = rdev->desc->ops;
int ret;
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
return rdev->desc->fixed_uV;
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;
}
if (ret > 0) {
if (ret < rdev->constraints->min_uV)
ret = 0;
else if (ret > rdev->constraints->max_uV)
ret = 0;
}
return ret;
return _regulator_list_voltage(regulator, selector, 1);
}
EXPORT_SYMBOL_GPL(regulator_list_voltage);
@ -2562,6 +2661,23 @@ int regulator_is_supported_voltage(struct regulator *regulator,
}
EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
int max_uV)
{
const struct regulator_desc *desc = rdev->desc;
if (desc->ops->map_voltage)
return desc->ops->map_voltage(rdev, min_uV, max_uV);
if (desc->ops->list_voltage == regulator_list_voltage_linear)
return regulator_map_voltage_linear(rdev, min_uV, max_uV);
if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
}
static int _regulator_call_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV,
unsigned *selector)
@ -2650,23 +2766,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
}
} else if (rdev->desc->ops->set_voltage_sel) {
if (rdev->desc->ops->map_voltage) {
ret = rdev->desc->ops->map_voltage(rdev, min_uV,
max_uV);
} else {
if (rdev->desc->ops->list_voltage ==
regulator_list_voltage_linear)
ret = regulator_map_voltage_linear(rdev,
min_uV, max_uV);
else if (rdev->desc->ops->list_voltage ==
regulator_list_voltage_linear_range)
ret = regulator_map_voltage_linear_range(rdev,
min_uV, max_uV);
else
ret = regulator_map_voltage_iterate(rdev,
min_uV, max_uV);
}
ret = regulator_map_voltage(rdev, min_uV, max_uV);
if (ret >= 0) {
best_val = rdev->desc->ops->list_voltage(rdev, ret);
if (min_uV <= best_val && max_uV >= best_val) {
@ -2717,32 +2817,15 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
return ret;
}
/**
* regulator_set_voltage - set regulator output voltage
* @regulator: regulator source
* @min_uV: Minimum required voltage in uV
* @max_uV: Maximum acceptable voltage in uV
*
* Sets a voltage regulator to the desired output voltage. This can be set
* during any regulator state. IOW, regulator can be disabled or enabled.
*
* If the regulator is enabled then the voltage will change to the new value
* immediately otherwise if the regulator is disabled the regulator will
* output at the new voltage when enabled.
*
* NOTE: If the regulator is shared between several devices then the lowest
* request voltage that meets the system constraints will be used.
* Regulator system constraints must be set for this regulator before
* calling this function otherwise this call will fail.
*/
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
static int regulator_set_voltage_unlocked(struct regulator *regulator,
int min_uV, int max_uV)
{
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
int old_min_uV, old_max_uV;
int current_uV;
mutex_lock(&rdev->mutex);
int best_supply_uV = 0;
int supply_change_uV = 0;
/* If we're setting the same range as last time the change
* should be a noop (some cpufreq implementations use the same
@ -2786,17 +2869,95 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
if (ret < 0)
goto out2;
if (rdev->supply && (rdev->desc->min_dropout_uV ||
!rdev->desc->ops->get_voltage)) {
int current_supply_uV;
int selector;
selector = regulator_map_voltage(rdev, min_uV, max_uV);
if (selector < 0) {
ret = selector;
goto out2;
}
best_supply_uV = _regulator_list_voltage(regulator, selector, 0);
if (best_supply_uV < 0) {
ret = best_supply_uV;
goto out2;
}
best_supply_uV += rdev->desc->min_dropout_uV;
current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
if (current_supply_uV < 0) {
ret = current_supply_uV;
goto out2;
}
supply_change_uV = best_supply_uV - current_supply_uV;
}
if (supply_change_uV > 0) {
ret = regulator_set_voltage_unlocked(rdev->supply,
best_supply_uV, INT_MAX);
if (ret) {
dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n",
ret);
goto out2;
}
}
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
if (ret < 0)
goto out2;
if (supply_change_uV < 0) {
ret = regulator_set_voltage_unlocked(rdev->supply,
best_supply_uV, INT_MAX);
if (ret)
dev_warn(&rdev->dev, "Failed to decrease supply voltage: %d\n",
ret);
/* No need to fail here */
ret = 0;
}
out:
mutex_unlock(&rdev->mutex);
return ret;
out2:
regulator->min_uV = old_min_uV;
regulator->max_uV = old_max_uV;
mutex_unlock(&rdev->mutex);
return ret;
}
/**
* regulator_set_voltage - set regulator output voltage
* @regulator: regulator source
* @min_uV: Minimum required voltage in uV
* @max_uV: Maximum acceptable voltage in uV
*
* Sets a voltage regulator to the desired output voltage. This can be set
* during any regulator state. IOW, regulator can be disabled or enabled.
*
* If the regulator is enabled then the voltage will change to the new value
* immediately otherwise if the regulator is disabled the regulator will
* output at the new voltage when enabled.
*
* NOTE: If the regulator is shared between several devices then the lowest
* request voltage that meets the system constraints will be used.
* Regulator system constraints must be set for this regulator before
* calling this function otherwise this call will fail.
*/
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
{
int ret = 0;
regulator_lock_supply(regulator->rdev);
ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV);
regulator_unlock_supply(regulator->rdev);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage);
@ -2949,7 +3110,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
} 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);
ret = _regulator_get_voltage(rdev->supply->rdev);
} else {
return -EINVAL;
}
@ -2972,11 +3133,11 @@ int regulator_get_voltage(struct regulator *regulator)
{
int ret;
mutex_lock(&regulator->rdev->mutex);
regulator_lock_supply(regulator->rdev);
ret = _regulator_get_voltage(regulator->rdev);
mutex_unlock(&regulator->rdev->mutex);
regulator_unlock_supply(regulator->rdev);
return ret;
}
@ -3810,8 +3971,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
}
}
list_add(&rdev->list, &regulator_list);
rdev_init_debugfs(rdev);
out:
mutex_unlock(&regulator_list_mutex);
@ -3865,6 +4024,19 @@ void regulator_unregister(struct regulator_dev *rdev)
}
EXPORT_SYMBOL_GPL(regulator_unregister);
static int _regulator_suspend_prepare(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
const suspend_state_t *state = data;
int ret;
mutex_lock(&rdev->mutex);
ret = suspend_prepare(rdev, *state);
mutex_unlock(&rdev->mutex);
return ret;
}
/**
* regulator_suspend_prepare - prepare regulators for system wide suspend
* @state: system suspend state
@ -3874,31 +4046,46 @@ EXPORT_SYMBOL_GPL(regulator_unregister);
*/
int regulator_suspend_prepare(suspend_state_t state)
{
struct regulator_dev *rdev;
int ret = 0;
/* ON is handled by regulator active state */
if (state == PM_SUSPEND_ON)
return -EINVAL;
mutex_lock(&regulator_list_mutex);
list_for_each_entry(rdev, &regulator_list, list) {
mutex_lock(&rdev->mutex);
ret = suspend_prepare(rdev, state);
mutex_unlock(&rdev->mutex);
if (ret < 0) {
rdev_err(rdev, "failed to prepare\n");
goto out;
}
}
out:
mutex_unlock(&regulator_list_mutex);
return ret;
return class_for_each_device(&regulator_class, NULL, &state,
_regulator_suspend_prepare);
}
EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
static int _regulator_suspend_finish(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
int ret;
mutex_lock(&rdev->mutex);
if (rdev->use_count > 0 || rdev->constraints->always_on) {
if (!_regulator_is_enabled(rdev)) {
ret = _regulator_do_enable(rdev);
if (ret)
dev_err(dev,
"Failed to resume regulator %d\n",
ret);
}
} else {
if (!have_full_constraints())
goto unlock;
if (!_regulator_is_enabled(rdev))
goto unlock;
ret = _regulator_do_disable(rdev);
if (ret)
dev_err(dev, "Failed to suspend regulator %d\n", ret);
}
unlock:
mutex_unlock(&rdev->mutex);
/* Keep processing regulators in spite of any errors */
return 0;
}
/**
* regulator_suspend_finish - resume regulators from system wide suspend
*
@ -3907,33 +4094,8 @@ EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
*/
int regulator_suspend_finish(void)
{
struct regulator_dev *rdev;
int ret = 0, error;
mutex_lock(&regulator_list_mutex);
list_for_each_entry(rdev, &regulator_list, list) {
mutex_lock(&rdev->mutex);
if (rdev->use_count > 0 || rdev->constraints->always_on) {
if (!_regulator_is_enabled(rdev)) {
error = _regulator_do_enable(rdev);
if (error)
ret = error;
}
} else {
if (!have_full_constraints())
goto unlock;
if (!_regulator_is_enabled(rdev))
goto unlock;
error = _regulator_do_disable(rdev);
if (error)
ret = error;
}
unlock:
mutex_unlock(&rdev->mutex);
}
mutex_unlock(&regulator_list_mutex);
return ret;
return class_for_each_device(&regulator_class, NULL, NULL,
_regulator_suspend_finish);
}
EXPORT_SYMBOL_GPL(regulator_suspend_finish);
@ -4053,14 +4215,35 @@ static const struct file_operations supply_map_fops = {
};
#ifdef CONFIG_DEBUG_FS
struct summary_data {
struct seq_file *s;
struct regulator_dev *parent;
int level;
};
static void regulator_summary_show_subtree(struct seq_file *s,
struct regulator_dev *rdev,
int level);
static int regulator_summary_show_children(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
struct summary_data *summary_data = data;
if (rdev->supply && rdev->supply->rdev == summary_data->parent)
regulator_summary_show_subtree(summary_data->s, rdev,
summary_data->level + 1);
return 0;
}
static void regulator_summary_show_subtree(struct seq_file *s,
struct regulator_dev *rdev,
int level)
{
struct list_head *list = s->private;
struct regulator_dev *child;
struct regulation_constraints *c;
struct regulator *consumer;
struct summary_data summary_data;
if (!rdev)
return;
@ -4110,33 +4293,32 @@ static void regulator_summary_show_subtree(struct seq_file *s,
seq_puts(s, "\n");
}
list_for_each_entry(child, list, list) {
/* handle only non-root regulators supplied by current rdev */
if (!child->supply || child->supply->rdev != rdev)
continue;
summary_data.s = s;
summary_data.level = level;
summary_data.parent = rdev;
regulator_summary_show_subtree(s, child, level + 1);
}
class_for_each_device(&regulator_class, NULL, &summary_data,
regulator_summary_show_children);
}
static int regulator_summary_show_roots(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
struct seq_file *s = data;
if (!rdev->supply)
regulator_summary_show_subtree(s, rdev, 0);
return 0;
}
static int regulator_summary_show(struct seq_file *s, void *data)
{
struct list_head *list = s->private;
struct regulator_dev *rdev;
seq_puts(s, " regulator use open bypass voltage current min max\n");
seq_puts(s, "-------------------------------------------------------------------------------\n");
mutex_lock(&regulator_list_mutex);
list_for_each_entry(rdev, list, list) {
if (rdev->supply)
continue;
regulator_summary_show_subtree(s, rdev, 0);
}
mutex_unlock(&regulator_list_mutex);
class_for_each_device(&regulator_class, NULL, s,
regulator_summary_show_roots);
return 0;
}
@ -4170,7 +4352,7 @@ static int __init regulator_init(void)
&supply_map_fops);
debugfs_create_file("regulator_summary", 0444, debugfs_root,
&regulator_list, &regulator_summary_fops);
NULL, &regulator_summary_fops);
regulator_dummy_init();

View File

@ -381,6 +381,7 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id,
case DA9053_AA:
case DA9053_BA:
case DA9053_BB:
case DA9053_BC:
for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) {
info = &da9053_regulator_info[i];
if (info->reg_desc.id == id)

View File

@ -698,7 +698,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
rdata->initdata = da9063_matches[i].init_data;
n++;
};
}
*da9063_reg_matches = da9063_matches;
return pdata;

View File

@ -76,6 +76,9 @@ static void of_get_regulation_constraints(struct device_node *np,
if (of_property_read_bool(np, "regulator-allow-bypass"))
constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
if (of_property_read_bool(np, "regulator-allow-set-load"))
constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS;
ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
if (!ret) {
if (pval)

View File

@ -69,12 +69,6 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
drvdata->state = selector;
ret = pwm_enable(drvdata->pwm);
if (ret) {
dev_err(&rdev->dev, "Failed to enable PWM\n");
return ret;
}
return 0;
}
@ -89,6 +83,29 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev,
return drvdata->duty_cycle_table[selector].uV;
}
static int pwm_regulator_enable(struct regulator_dev *dev)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
return pwm_enable(drvdata->pwm);
}
static int pwm_regulator_disable(struct regulator_dev *dev)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
pwm_disable(drvdata->pwm);
return 0;
}
static int pwm_regulator_is_enabled(struct regulator_dev *dev)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
return pwm_is_enabled(drvdata->pwm);
}
/**
* Continuous voltage call-backs
*/
@ -144,11 +161,17 @@ static struct regulator_ops pwm_regulator_voltage_table_ops = {
.get_voltage_sel = pwm_regulator_get_voltage_sel,
.list_voltage = pwm_regulator_list_voltage,
.map_voltage = regulator_map_voltage_iterate,
.enable = pwm_regulator_enable,
.disable = pwm_regulator_disable,
.is_enabled = pwm_regulator_is_enabled,
};
static struct regulator_ops pwm_regulator_voltage_continuous_ops = {
.get_voltage = pwm_regulator_get_voltage,
.set_voltage = pwm_regulator_set_voltage,
.enable = pwm_regulator_enable,
.disable = pwm_regulator_disable,
.is_enabled = pwm_regulator_is_enabled,
};
static struct regulator_desc pwm_regulator_desc = {

View File

@ -36,9 +36,9 @@ struct qcom_rpm_reg {
};
struct rpm_regulator_req {
u32 key;
u32 nbytes;
u32 value;
__le32 key;
__le32 nbytes;
__le32 value;
};
#define RPM_KEY_SWEN 0x6e657773 /* "swen" */
@ -62,9 +62,9 @@ static int rpm_reg_enable(struct regulator_dev *rdev)
struct rpm_regulator_req req;
int ret;
req.key = RPM_KEY_SWEN;
req.nbytes = sizeof(u32);
req.value = 1;
req.key = cpu_to_le32(RPM_KEY_SWEN);
req.nbytes = cpu_to_le32(sizeof(u32));
req.value = cpu_to_le32(1);
ret = rpm_reg_write_active(vreg, &req, sizeof(req));
if (!ret)
@ -86,8 +86,8 @@ static int rpm_reg_disable(struct regulator_dev *rdev)
struct rpm_regulator_req req;
int ret;
req.key = RPM_KEY_SWEN;
req.nbytes = sizeof(u32);
req.key = cpu_to_le32(RPM_KEY_SWEN);
req.nbytes = cpu_to_le32(sizeof(u32));
req.value = 0;
ret = rpm_reg_write_active(vreg, &req, sizeof(req));
@ -113,9 +113,9 @@ static int rpm_reg_set_voltage(struct regulator_dev *rdev,
struct rpm_regulator_req req;
int ret = 0;
req.key = RPM_KEY_UV;
req.nbytes = sizeof(u32);
req.value = min_uV;
req.key = cpu_to_le32(RPM_KEY_UV);
req.nbytes = cpu_to_le32(sizeof(u32));
req.value = cpu_to_le32(min_uV);
ret = rpm_reg_write_active(vreg, &req, sizeof(req));
if (!ret)
@ -129,9 +129,9 @@ static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA)
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
struct rpm_regulator_req req;
req.key = RPM_KEY_MA;
req.nbytes = sizeof(u32);
req.value = load_uA;
req.key = cpu_to_le32(RPM_KEY_MA);
req.nbytes = cpu_to_le32(sizeof(u32));
req.value = cpu_to_le32(load_uA / 1000);
return rpm_reg_write_active(vreg, &req, sizeof(req));
}

View File

@ -14,7 +14,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/core.h>
@ -33,7 +33,7 @@ static int tps6105x_regulator_enable(struct regulator_dev *rdev)
int ret;
/* Activate voltage mode */
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_MODE_MASK,
TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
if (ret)
@ -48,7 +48,7 @@ static int tps6105x_regulator_disable(struct regulator_dev *rdev)
int ret;
/* Set into shutdown mode */
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_MODE_MASK,
TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
if (ret)
@ -60,10 +60,10 @@ static int tps6105x_regulator_disable(struct regulator_dev *rdev)
static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
u8 regval;
unsigned int regval;
int ret;
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
if (ret)
return ret;
regval &= TPS6105X_REG0_MODE_MASK;
@ -78,10 +78,10 @@ static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
u8 regval;
unsigned int regval;
int ret;
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
if (ret)
return ret;
@ -96,7 +96,7 @@ static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
int ret;
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_VOLTAGE_MASK,
selector << TPS6105X_REG0_VOLTAGE_SHIFT);
if (ret)

View File

@ -86,6 +86,42 @@
#define TPS65023_MAX_REG_ID TPS65023_LDO_2
#define TPS65023_REGULATOR_DCDC(_num, _t, _em) \
{ \
.name = "VDCDC"#_num, \
.of_match = of_match_ptr("VDCDC"#_num), \
.regulators_node = of_match_ptr("regulators"), \
.id = TPS65023_DCDC_##_num, \
.n_voltages = ARRAY_SIZE(_t), \
.ops = &tps65023_dcdc_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.volt_table = _t, \
.vsel_reg = TPS65023_REG_DEF_CORE, \
.vsel_mask = ARRAY_SIZE(_t) - 1, \
.enable_mask = _em, \
.enable_reg = TPS65023_REG_REG_CTRL, \
.apply_reg = TPS65023_REG_CON_CTRL2, \
.apply_bit = TPS65023_REG_CTRL2_GO, \
} \
#define TPS65023_REGULATOR_LDO(_num, _t, _vm) \
{ \
.name = "LDO"#_num, \
.of_match = of_match_ptr("LDO"#_num), \
.regulators_node = of_match_ptr("regulators"), \
.id = TPS65023_LDO_##_num, \
.n_voltages = ARRAY_SIZE(_t), \
.ops = &tps65023_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.volt_table = _t, \
.vsel_reg = TPS65023_REG_LDO_CTRL, \
.vsel_mask = _vm, \
.enable_mask = 1 << (_num), \
.enable_reg = TPS65023_REG_REG_CTRL, \
} \
/* Supported voltage values for regulators */
static const unsigned int VCORE_VSEL_table[] = {
800000, 825000, 850000, 875000,
@ -124,25 +160,16 @@ static const unsigned int TPS65023_LDO2_VSEL_table[] = {
2500000, 2800000, 3000000, 3300000,
};
/* Regulator specific details */
struct tps_info {
const char *name;
u8 table_len;
const unsigned int *table;
};
/* PMIC details */
struct tps_pmic {
struct regulator_desc desc[TPS65023_NUM_REGULATOR];
struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
const struct tps_info *info[TPS65023_NUM_REGULATOR];
const struct tps_driver_data *driver_data;
struct regmap *regmap;
u8 core_regulator;
};
/* Struct passed as driver data */
struct tps_driver_data {
const struct tps_info *info;
const struct regulator_desc *desc;
u8 core_regulator;
};
@ -154,7 +181,7 @@ static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev)
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL;
if (dcdc != tps->core_regulator)
if (dcdc != tps->driver_data->core_regulator)
return 0;
return regulator_get_voltage_sel_regmap(dev);
@ -166,7 +193,7 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
if (dcdc != tps->core_regulator)
if (dcdc != tps->driver_data->core_regulator)
return -EINVAL;
return regulator_set_voltage_sel_regmap(dev, selector);
@ -199,30 +226,60 @@ static const struct regmap_config tps65023_regmap_config = {
.val_bits = 8,
};
static const struct regulator_desc tps65020_regulators[] = {
TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20),
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10),
TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08),
TPS65023_REGULATOR_LDO(1, TPS65020_LDO_VSEL_table, 0x07),
TPS65023_REGULATOR_LDO(2, TPS65020_LDO_VSEL_table, 0x70),
};
static const struct regulator_desc tps65021_regulators[] = {
TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20),
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10),
TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08),
TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07),
TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70),
};
static const struct regulator_desc tps65023_regulators[] = {
TPS65023_REGULATOR_DCDC(1, VCORE_VSEL_table, 0x20),
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_3300000_VSEL_table, 0x10),
TPS65023_REGULATOR_DCDC(3, DCDC_FIXED_1800000_VSEL_table, 0x08),
TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07),
TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70),
};
static struct tps_driver_data tps65020_drv_data = {
.desc = tps65020_regulators,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65021_drv_data = {
.desc = tps65021_regulators,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65023_drv_data = {
.desc = tps65023_regulators,
.core_regulator = TPS65023_DCDC_1,
};
static int tps_65023_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct tps_driver_data *drv_data = (void *)id->driver_data;
const struct tps_info *info = drv_data->info;
struct regulator_init_data *init_data = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
struct tps_pmic *tps;
int i;
int error;
/**
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
init_data = dev_get_platdata(&client->dev);
if (!init_data)
return -EIO;
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
tps->driver_data = (struct tps_driver_data *)id->driver_data;
tps->regmap = devm_regmap_init_i2c(client, &tps65023_regmap_config);
if (IS_ERR(tps->regmap)) {
error = PTR_ERR(tps->regmap);
@ -232,58 +289,22 @@ static int tps_65023_probe(struct i2c_client *client,
}
/* common for all regulators */
tps->core_regulator = drv_data->core_regulator;
config.dev = &client->dev;
config.driver_data = tps;
config.regmap = tps->regmap;
for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
/* Store regulator specific information */
tps->info[i] = info;
tps->desc[i].name = info->name;
tps->desc[i].id = i;
tps->desc[i].n_voltages = info->table_len;
tps->desc[i].volt_table = info->table;
tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
&tps65023_ldo_ops : &tps65023_dcdc_ops);
tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE;
tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL;
switch (i) {
case TPS65023_LDO_1:
tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
tps->desc[i].vsel_mask = 0x07;
tps->desc[i].enable_mask = 1 << 1;
break;
case TPS65023_LDO_2:
tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
tps->desc[i].vsel_mask = 0x70;
tps->desc[i].enable_mask = 1 << 2;
break;
default: /* DCDCx */
tps->desc[i].enable_mask =
1 << (TPS65023_NUM_REGULATOR - i);
tps->desc[i].vsel_reg = TPS65023_REG_DEF_CORE;
tps->desc[i].vsel_mask = info->table_len - 1;
tps->desc[i].apply_reg = TPS65023_REG_CON_CTRL2;
tps->desc[i].apply_bit = TPS65023_REG_CTRL2_GO;
}
config.dev = &client->dev;
config.init_data = init_data;
config.driver_data = tps;
config.regmap = tps->regmap;
for (i = 0; i < TPS65023_NUM_REGULATOR; i++) {
if (init_data)
config.init_data = &init_data[i];
/* Register the regulators */
rdev = devm_regulator_register(&client->dev, &tps->desc[i],
&config);
if (IS_ERR(rdev)) {
tps->rdev[i] = devm_regulator_register(&client->dev,
&tps->driver_data->desc[i], &config);
if (IS_ERR(tps->rdev[i])) {
dev_err(&client->dev, "failed to register %s\n",
id->name);
return PTR_ERR(rdev);
return PTR_ERR(tps->rdev[i]);
}
/* Save regulator for cleanup */
tps->rdev[i] = rdev;
}
i2c_set_clientdata(client, tps);
@ -296,120 +317,33 @@ static int tps_65023_probe(struct i2c_client *client,
return 0;
}
static const struct tps_info tps65020_regs[] = {
{
.name = "VDCDC1",
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
.table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC2",
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
.table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "VDCDC3",
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "LDO1",
.table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table),
.table = TPS65020_LDO_VSEL_table,
},
{
.name = "LDO2",
.table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table),
.table = TPS65020_LDO_VSEL_table,
},
};
static const struct tps_info tps65021_regs[] = {
{
.name = "VDCDC1",
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
.table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC2",
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
.table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "VDCDC3",
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "LDO1",
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
.table = TPS65023_LDO1_VSEL_table,
},
{
.name = "LDO2",
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
.table = TPS65023_LDO2_VSEL_table,
},
};
static const struct tps_info tps65023_regs[] = {
{
.name = "VDCDC1",
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "VDCDC2",
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
.table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC3",
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
.table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "LDO1",
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
.table = TPS65023_LDO1_VSEL_table,
},
{
.name = "LDO2",
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
.table = TPS65023_LDO2_VSEL_table,
},
};
static struct tps_driver_data tps65020_drv_data = {
.info = tps65020_regs,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65021_drv_data = {
.info = tps65021_regs,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65023_drv_data = {
.info = tps65023_regs,
.core_regulator = TPS65023_DCDC_1,
static const struct of_device_id tps65023_of_match[] = {
{ .compatible = "ti,tps65020", .data = &tps65020_drv_data},
{ .compatible = "ti,tps65021", .data = &tps65021_drv_data},
{ .compatible = "ti,tps65023", .data = &tps65023_drv_data},
{},
};
MODULE_DEVICE_TABLE(of, tps65023_of_match);
static const struct i2c_device_id tps_65023_id[] = {
{.name = "tps65023",
.driver_data = (unsigned long) &tps65023_drv_data},
{.name = "tps65021",
.driver_data = (unsigned long) &tps65021_drv_data,},
{.name = "tps65020",
.driver_data = (unsigned long) &tps65020_drv_data},
{
.name = "tps65023",
.driver_data = (kernel_ulong_t)&tps65023_drv_data
}, {
.name = "tps65021",
.driver_data = (kernel_ulong_t)&tps65021_drv_data
}, {
.name = "tps65020",
.driver_data = (kernel_ulong_t)&tps65020_drv_data
},
{ },
};
MODULE_DEVICE_TABLE(i2c, tps_65023_id);
static struct i2c_driver tps_65023_i2c_driver = {
.driver = {
.name = "tps65023",
.of_match_table = of_match_ptr(tps65023_of_match),
},
.probe = tps_65023_probe,
.id_table = tps_65023_id,

View File

@ -10,6 +10,7 @@
#define MFD_TPS6105X_H
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/regulator/machine.h>
/*
@ -82,20 +83,15 @@ struct tps6105x_platform_data {
/**
* struct tps6105x - state holder for the TPS6105x drivers
* @mutex: mutex to serialize I2C accesses
* @i2c_client: corresponding I2C client
* @regulator: regulator device if used in voltage mode
* @regmap: used for i2c communcation on accessing registers
*/
struct tps6105x {
struct tps6105x_platform_data *pdata;
struct mutex lock;
struct i2c_client *client;
struct regulator_dev *regulator;
struct regmap *regmap;
};
extern int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value);
extern int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf);
extern int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
u8 bitmask, u8 bitvalues);
#endif

View File

@ -245,6 +245,7 @@ enum regulator_type {
* @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)
* @min_dropout_uV: The minimum dropout voltage this regulator can handle
* @linear_ranges: A constant table of possible voltage ranges.
* @n_linear_ranges: Number of entries in the @linear_ranges table.
* @volt_table: Voltage mapping table (if table based mapping)
@ -292,6 +293,7 @@ struct regulator_desc {
unsigned int linear_min_sel;
int fixed_uV;
unsigned int ramp_delay;
int min_dropout_uV;
const struct regulator_linear_range *linear_ranges;
int n_linear_ranges;