summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mfd/bcm590xx.txt4
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mps11.txt14
-rw-r--r--Documentation/devicetree/bindings/regulator/ltc3589.txt99
-rw-r--r--Documentation/devicetree/bindings/regulator/tps65090.txt4
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--drivers/mfd/arizona-core.c41
-rw-r--r--drivers/mfd/bcm590xx.c60
-rw-r--r--drivers/mfd/tps65090.c41
-rw-r--r--drivers/mfd/tps6586x.c4
-rw-r--r--drivers/power/tps65090-charger.c11
-rw-r--r--drivers/regulator/Kconfig15
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/anatop-regulator.c2
-rw-r--r--drivers/regulator/arizona-ldo1.c58
-rw-r--r--drivers/regulator/arizona-micsupp.c38
-rw-r--r--drivers/regulator/axp20x-regulator.c286
-rw-r--r--drivers/regulator/bcm590xx-regulator.c92
-rw-r--r--drivers/regulator/core.c58
-rw-r--r--drivers/regulator/devres.c6
-rw-r--r--drivers/regulator/fixed.c13
-rw-r--r--drivers/regulator/ltc3589.c554
-rw-r--r--drivers/regulator/max8649.c4
-rw-r--r--drivers/regulator/max8952.c2
-rw-r--r--drivers/regulator/of_regulator.c68
-rw-r--r--drivers/regulator/palmas-regulator.c160
-rw-r--r--drivers/regulator/pbias-regulator.c29
-rw-r--r--drivers/regulator/pfuze100-regulator.c8
-rw-r--r--drivers/regulator/s2mpa01.c19
-rw-r--r--drivers/regulator/s2mps11.c113
-rw-r--r--drivers/regulator/s5m8767.c37
-rw-r--r--drivers/regulator/st-pwm.c2
-rw-r--r--drivers/regulator/tps65090-regulator.c214
-rw-r--r--drivers/regulator/tps65217-regulator.c4
-rw-r--r--drivers/regulator/tps65218-regulator.c37
-rw-r--r--drivers/regulator/tps6586x-regulator.c68
-rw-r--r--drivers/regulator/vexpress.c2
-rw-r--r--include/linux/mfd/arizona/core.h3
-rw-r--r--include/linux/mfd/bcm590xx.h9
-rw-r--r--include/linux/mfd/core.h2
-rw-r--r--include/linux/mfd/samsung/s2mps14.h2
-rw-r--r--include/linux/mfd/tps65090.h19
-rw-r--r--include/linux/mfd/tps65217.h1
-rw-r--r--include/linux/mfd/tps6586x.h2
-rw-r--r--include/linux/regulator/consumer.h42
44 files changed, 1832 insertions, 418 deletions
diff --git a/Documentation/devicetree/bindings/mfd/bcm590xx.txt b/Documentation/devicetree/bindings/mfd/bcm590xx.txt
index 1fe30e2b10da..be51a15e05f9 100644
--- a/Documentation/devicetree/bindings/mfd/bcm590xx.txt
+++ b/Documentation/devicetree/bindings/mfd/bcm590xx.txt
@@ -19,7 +19,9 @@ Optional child nodes:
The valid regulator node names for BCM59056 are:
rfldo, camldo1, camldo2, simldo1, simldo2, sdldo, sdxldo,
mmcldo1, mmcldo2, audldo, micldo, usbldo, vibldo,
- csr, iosr1, iosr2, msr, sdsr1, sdsr2, vsr
+ csr, iosr1, iosr2, msr, sdsr1, sdsr2, vsr,
+ gpldo1, gpldo2, gpldo3, gpldo4, gpldo5, gpldo6,
+ vbus
Example:
pmu: bcm59056@8 {
diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt
index 802e839b0829..d81ba30c0d8b 100644
--- a/Documentation/devicetree/bindings/mfd/s2mps11.txt
+++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt
@@ -56,6 +56,20 @@ for a particular group of BUCKs. So provide same regulator-ramp-delay<value>.
Grouping of BUCKs sharing ramp rate setting is as follow : BUCK[1, 6],
BUCK[3, 4], and BUCK[7, 8, 10]
+On S2MPS14 the LDO10, LDO11 and LDO12 can be configured to external control
+over GPIO. To turn this feature on this property must be added to the regulator
+sub-node:
+ - samsung,ext-control-gpios: GPIO specifier for one GPIO
+ controlling this regulator (enable/disable);
+Example:
+ LDO12 {
+ regulator-name = "V_EMMC_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ samsung,ext-control-gpios = <&gpk0 2 0>;
+ };
+
+
The regulator constraints inside the regulator nodes use the standard regulator
bindings which are documented elsewhere.
diff --git a/Documentation/devicetree/bindings/regulator/ltc3589.txt b/Documentation/devicetree/bindings/regulator/ltc3589.txt
new file mode 100644
index 000000000000..801053036146
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/ltc3589.txt
@@ -0,0 +1,99 @@
+Linear Technology LTC3589, LTC3589-1, and LTC3589-2 8-output regulators
+
+Required properties:
+- compatible: "lltc,ltc3589", "lltc,ltc3589-1" or "lltc,ltc3589-2"
+- reg: I2C slave address
+
+Required child node:
+- regulators: Contains eight regulator child nodes sw1, sw2, sw3, bb-out,
+ ldo1, ldo2, ldo3, and ldo4, specifying the initialization data as
+ documented in Documentation/devicetree/bindings/regulator/regulator.txt.
+
+Each regulator is defined using the standard binding for regulators. The
+nodes for sw1, sw2, sw3, bb-out, ldo1, and ldo2 additionally need to specify
+the resistor values of their external feedback voltage dividers:
+
+Required properties (not on ldo3, ldo4):
+- lltc,fb-voltage-divider: An array of two integers containing the resistor
+ values R1 and R2 of the feedback voltage divider in ohms.
+
+Regulators sw1, sw2, sw3, and ldo2 can regulate the feedback reference from
+0.3625 V to 0.75 V in 12.5 mV steps. The output voltage thus ranges between
+0.3625 * (1 + R1/R2) V and 0.75 * (1 + R1/R2) V. Regulators bb-out and ldo1
+have a fixed 0.8 V reference and thus output 0.8 * (1 + R1/R2) V. The ldo3
+regulator is fixed to 1.8 V on LTC3589 and to 2.8 V on LTC3589-1,2. The ldo4
+regulator can output between 1.8 V and 3.3 V on LTC3589 and between 1.2 V
+and 3.2 V on LTC3589-1,2 in four steps. The ldo1 standby regulator can not
+be disabled and thus should have the regulator-always-on property set.
+
+Example:
+
+ ltc3589: pmic@34 {
+ compatible = "lltc,ltc3589-1";
+ reg = <0x34>;
+
+ regulators {
+ sw1_reg: sw1 {
+ regulator-min-microvolt = <591930>;
+ regulator-max-microvolt = <1224671>;
+ lltc,fb-voltage-divider = <100000 158000>;
+ regulator-ramp-delay = <7000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw2_reg: sw2 {
+ regulator-min-microvolt = <704123>;
+ regulator-max-microvolt = <1456803>;
+ lltc,fb-voltage-divider = <180000 191000>;
+ regulator-ramp-delay = <7000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3_reg: sw3 {
+ regulator-min-microvolt = <1341250>;
+ regulator-max-microvolt = <2775000>;
+ lltc,fb-voltage-divider = <270000 100000>;
+ regulator-ramp-delay = <7000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ bb_out_reg: bb-out {
+ regulator-min-microvolt = <3387341>;
+ regulator-max-microvolt = <3387341>;
+ lltc,fb-voltage-divider = <511000 158000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1_reg: ldo1 {
+ regulator-min-microvolt = <1306329>;
+ regulator-max-microvolt = <1306329>;
+ lltc,fb-voltage-divider = <100000 158000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo2_reg: ldo2 {
+ regulator-min-microvolt = <704123>;
+ regulator-max-microvolt = <1456806>;
+ lltc,fb-voltage-divider = <180000 191000>;
+ regulator-ramp-delay = <7000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo3_reg: ldo3 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-boot-on;
+ };
+
+ ldo4_reg: ldo4 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3200000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/tps65090.txt b/Documentation/devicetree/bindings/regulator/tps65090.txt
index 313a60ba61d8..340980239ea9 100644
--- a/Documentation/devicetree/bindings/regulator/tps65090.txt
+++ b/Documentation/devicetree/bindings/regulator/tps65090.txt
@@ -21,6 +21,10 @@ Optional properties:
number should be provided. If it is externally controlled and no GPIO
entry then driver will just configure this rails as external control
and will not provide any enable/disable APIs.
+- ti,overcurrent-wait: This is applicable to FET registers, which have a
+ poorly defined "overcurrent wait" field. If this property is present it
+ should be between 0 - 3. If this property isn't present we won't touch the
+ "overcurrent wait" field and we'll leave it to the BIOS/EC to deal with.
Each regulator is defined using the standard binding for regulators.
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 2ee6ead72434..941980474e14 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -74,6 +74,7 @@ lantiq Lantiq Semiconductor
lg LG Corporation
linux Linux-specific binding
lsi LSI Corp. (LSI Logic)
+lltc Linear Technology Corporation
marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products
microchip Microchip Technology Inc.
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 1c3ae57082ed..07e6e27be23c 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -508,19 +508,31 @@ int arizona_of_get_type(struct device *dev)
}
EXPORT_SYMBOL_GPL(arizona_of_get_type);
+int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
+ bool mandatory)
+{
+ int gpio;
+
+ gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0);
+ if (gpio < 0) {
+ if (mandatory)
+ dev_err(arizona->dev,
+ "Mandatory DT gpio %s missing/malformed: %d\n",
+ prop, gpio);
+
+ gpio = 0;
+ }
+
+ return gpio;
+}
+EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio);
+
static int arizona_of_get_core_pdata(struct arizona *arizona)
{
+ struct arizona_pdata *pdata = &arizona->pdata;
int ret, i;
- arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node,
- "wlf,reset", 0);
- if (arizona->pdata.reset < 0)
- arizona->pdata.reset = 0;
-
- arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node,
- "wlf,ldoena", 0);
- if (arizona->pdata.ldoena < 0)
- arizona->pdata.ldoena = 0;
+ pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
ret = of_property_read_u32_array(arizona->dev->of_node,
"wlf,gpio-defaults",
@@ -652,6 +664,9 @@ int arizona_dev_init(struct arizona *arizona)
return -EINVAL;
}
+ /* Mark DCVDD as external, LDO1 driver will clear if internal */
+ arizona->external_dcvdd = true;
+
ret = mfd_add_devices(arizona->dev, -1, early_devs,
ARRAY_SIZE(early_devs), NULL, 0, NULL);
if (ret != 0) {
@@ -851,14 +866,6 @@ int arizona_dev_init(struct arizona *arizona)
arizona->pdata.gpio_defaults[i]);
}
- /*
- * LDO1 can only be used to supply DCVDD so if it has no
- * consumers then DCVDD is supplied externally.
- */
- if (arizona->pdata.ldo1 &&
- arizona->pdata.ldo1->num_consumer_supplies == 0)
- arizona->external_dcvdd = true;
-
pm_runtime_set_autosuspend_delay(arizona->dev, 100);
pm_runtime_use_autosuspend(arizona->dev);
pm_runtime_enable(arizona->dev);
diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c
index e9a33c79431b..43cba1a1973c 100644
--- a/drivers/mfd/bcm590xx.c
+++ b/drivers/mfd/bcm590xx.c
@@ -28,39 +28,71 @@ static const struct mfd_cell bcm590xx_devs[] = {
},
};
-static const struct regmap_config bcm590xx_regmap_config = {
+static const struct regmap_config bcm590xx_regmap_config_pri = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = BCM590XX_MAX_REGISTER,
+ .max_register = BCM590XX_MAX_REGISTER_PRI,
.cache_type = REGCACHE_RBTREE,
};
-static int bcm590xx_i2c_probe(struct i2c_client *i2c,
+static const struct regmap_config bcm590xx_regmap_config_sec = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = BCM590XX_MAX_REGISTER_SEC,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri,
const struct i2c_device_id *id)
{
struct bcm590xx *bcm590xx;
int ret;
- bcm590xx = devm_kzalloc(&i2c->dev, sizeof(*bcm590xx), GFP_KERNEL);
+ bcm590xx = devm_kzalloc(&i2c_pri->dev, sizeof(*bcm590xx), GFP_KERNEL);
if (!bcm590xx)
return -ENOMEM;
- i2c_set_clientdata(i2c, bcm590xx);
- bcm590xx->dev = &i2c->dev;
- bcm590xx->i2c_client = i2c;
+ i2c_set_clientdata(i2c_pri, bcm590xx);
+ bcm590xx->dev = &i2c_pri->dev;
+ bcm590xx->i2c_pri = i2c_pri;
- bcm590xx->regmap = devm_regmap_init_i2c(i2c, &bcm590xx_regmap_config);
- if (IS_ERR(bcm590xx->regmap)) {
- ret = PTR_ERR(bcm590xx->regmap);
- dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+ bcm590xx->regmap_pri = devm_regmap_init_i2c(i2c_pri,
+ &bcm590xx_regmap_config_pri);
+ if (IS_ERR(bcm590xx->regmap_pri)) {
+ ret = PTR_ERR(bcm590xx->regmap_pri);
+ dev_err(&i2c_pri->dev, "primary regmap init failed: %d\n", ret);
return ret;
}
- ret = mfd_add_devices(&i2c->dev, -1, bcm590xx_devs,
+ /* Secondary I2C slave address is the base address with A(2) asserted */
+ bcm590xx->i2c_sec = i2c_new_dummy(i2c_pri->adapter,
+ i2c_pri->addr | BIT(2));
+ if (IS_ERR_OR_NULL(bcm590xx->i2c_sec)) {
+ dev_err(&i2c_pri->dev, "failed to add secondary I2C device\n");
+ return -ENODEV;
+ }
+ i2c_set_clientdata(bcm590xx->i2c_sec, bcm590xx);
+
+ bcm590xx->regmap_sec = devm_regmap_init_i2c(bcm590xx->i2c_sec,
+ &bcm590xx_regmap_config_sec);
+ if (IS_ERR(bcm590xx->regmap_sec)) {
+ ret = PTR_ERR(bcm590xx->regmap_sec);
+ dev_err(&bcm590xx->i2c_sec->dev,
+ "secondary regmap init failed: %d\n", ret);
+ goto err;
+ }
+
+ ret = mfd_add_devices(&i2c_pri->dev, -1, bcm590xx_devs,
ARRAY_SIZE(bcm590xx_devs), NULL, 0, NULL);
- if (ret < 0)
- dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret);
+ if (ret < 0) {
+ dev_err(&i2c_pri->dev, "failed to add sub-devices: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+err:
+ i2c_unregister_device(bcm590xx->i2c_sec);
return ret;
}
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
index ba1a25d758c1..1c3e6e2efe41 100644
--- a/drivers/mfd/tps65090.c
+++ b/drivers/mfd/tps65090.c
@@ -32,14 +32,6 @@
#define NUM_INT_REG 2
#define TOTAL_NUM_REG 0x18
-/* interrupt status registers */
-#define TPS65090_INT_STS 0x0
-#define TPS65090_INT_STS2 0x1
-
-/* interrupt mask registers */
-#define TPS65090_INT_MSK 0x2
-#define TPS65090_INT_MSK2 0x3
-
#define TPS65090_INT1_MASK_VAC_STATUS_CHANGE 1
#define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2
#define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3
@@ -64,11 +56,16 @@ static struct resource charger_resources[] = {
}
};
-static const struct mfd_cell tps65090s[] = {
- {
+enum tps65090_cells {
+ PMIC = 0,
+ CHARGER = 1,
+};
+
+static struct mfd_cell tps65090s[] = {
+ [PMIC] = {
.name = "tps65090-pmic",
},
- {
+ [CHARGER] = {
.name = "tps65090-charger",
.num_resources = ARRAY_SIZE(charger_resources),
.resources = &charger_resources[0],
@@ -139,17 +136,26 @@ static struct regmap_irq_chip tps65090_irq_chip = {
.irqs = tps65090_irqs,
.num_irqs = ARRAY_SIZE(tps65090_irqs),
.num_regs = NUM_INT_REG,
- .status_base = TPS65090_INT_STS,
- .mask_base = TPS65090_INT_MSK,
+ .status_base = TPS65090_REG_INTR_STS,
+ .mask_base = TPS65090_REG_INTR_MASK,
.mask_invert = true,
};
static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
- if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2))
- return true;
- else
+ /* Nearly all registers have status bits mixed in, except a few */
+ switch (reg) {
+ case TPS65090_REG_INTR_MASK:
+ case TPS65090_REG_INTR_MASK2:
+ case TPS65090_REG_CG_CTRL0:
+ case TPS65090_REG_CG_CTRL1:
+ case TPS65090_REG_CG_CTRL2:
+ case TPS65090_REG_CG_CTRL3:
+ case TPS65090_REG_CG_CTRL4:
+ case TPS65090_REG_CG_CTRL5:
return false;
+ }
+ return true;
}
static const struct regmap_config tps65090_regmap_config = {
@@ -211,6 +217,9 @@ static int tps65090_i2c_probe(struct i2c_client *client,
"IRQ init failed with err: %d\n", ret);
return ret;
}
+ } else {
+ /* Don't tell children they have an IRQ that'll never fire */
+ tps65090s[CHARGER].num_resources = 0;
}
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index bbd54414a75d..835e5549ecdd 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -495,6 +495,10 @@ static void tps6586x_print_version(struct i2c_client *client, int version)
case TPS658623:
name = "TPS658623";
break;
+ case TPS658640:
+ case TPS658640v2:
+ name = "TPS658640";
+ break;
case TPS658643:
name = "TPS658643";
break;
diff --git a/drivers/power/tps65090-charger.c b/drivers/power/tps65090-charger.c
index 8fc9d6df87f6..1685f63b9e5d 100644
--- a/drivers/power/tps65090-charger.c
+++ b/drivers/power/tps65090-charger.c
@@ -28,17 +28,6 @@
#include <linux/mfd/tps65090.h>
-#define TPS65090_REG_INTR_STS 0x00
-#define TPS65090_REG_INTR_MASK 0x02
-#define TPS65090_REG_CG_CTRL0 0x04
-#define TPS65090_REG_CG_CTRL1 0x05
-#define TPS65090_REG_CG_CTRL2 0x06
-#define TPS65090_REG_CG_CTRL3 0x07
-#define TPS65090_REG_CG_CTRL4 0x08
-#define TPS65090_REG_CG_CTRL5 0x09
-#define TPS65090_REG_CG_STATUS1 0x0a
-#define TPS65090_REG_CG_STATUS2 0x0b
-
#define TPS65090_CHARGER_ENABLE BIT(0)
#define TPS65090_VACG BIT(1)
#define TPS65090_NOITERM BIT(5)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f0cc9e6dac3a..789eb46090e3 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -139,6 +139,13 @@ config REGULATOR_AS3722
AS3722 PMIC. This will enable support for all the software
controllable DCDC/LDO regulators.
+config REGULATOR_AXP20X
+ tristate "X-POWERS AXP20X PMIC Regulators"
+ depends on MFD_AXP20X
+ help
+ This driver provides support for the voltage regulators on the
+ AXP20X PMIC.
+
config REGULATOR_BCM590XX
tristate "Broadcom BCM590xx PMU Regulators"
depends on MFD_BCM590XX
@@ -265,6 +272,14 @@ config REGULATOR_LP8788
help
This driver supports LP8788 voltage regulator chip.
+config REGULATOR_LTC3589
+ tristate "LTC3589 8-output voltage regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This enables support for the LTC3589, LTC3589-1, and LTC3589-2
+ 8-output regulators controlled via I2C.
+
config REGULATOR_MAX14577
tristate "Maxim 14577/77836 regulator"
depends on MFD_MAX14577
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 12ef277a48b4..d461110f4463 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
+obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
@@ -37,6 +38,7 @@ obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
+obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 7c397bb81e01..4f730af70e7c 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -300,7 +300,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
return 0;
}
-static struct of_device_id of_anatop_regulator_match_tbl[] = {
+static const struct of_device_id of_anatop_regulator_match_tbl[] = {
{ .compatible = "fsl,anatop-regulator", },
{ /* end */ }
};
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index b1033d30b504..04f262a836b2 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -16,9 +16,11 @@
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -178,6 +180,42 @@ static const struct regulator_init_data arizona_ldo1_default = {
.num_consumer_supplies = 1,
};
+static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
+ struct regulator_config *config)
+{
+ struct arizona_pdata *pdata = &arizona->pdata;
+ struct arizona_ldo1 *ldo1 = config->driver_data;
+ struct device_node *init_node, *dcvdd_node;
+ struct regulator_init_data *init_data;
+
+ pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", 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);
+
+ if (init_node) {
+ config->of_node = init_node;
+
+ init_data = of_get_regulator_init_data(arizona->dev, init_node);
+
+ if (init_data) {
+ init_data->consumer_supplies = &ldo1->supply;
+ init_data->num_consumer_supplies = 1;
+
+ if (dcvdd_node && dcvdd_node != init_node)
+ arizona->external_dcvdd = true;
+
+ pdata->ldo1 = init_data;
+ }
+ } else if (dcvdd_node) {
+ arizona->external_dcvdd = true;
+ }
+
+ of_node_put(dcvdd_node);
+
+ return 0;
+}
+
static int arizona_ldo1_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -186,6 +224,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
struct arizona_ldo1 *ldo1;
int ret;
+ arizona->external_dcvdd = false;
+
ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
if (!ldo1)
return -ENOMEM;
@@ -216,6 +256,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
config.dev = arizona->dev;
config.driver_data = ldo1;
config.regmap = arizona->regmap;
+
+ if (IS_ENABLED(CONFIG_OF)) {
+ if (!dev_get_platdata(arizona->dev)) {
+ ret = arizona_ldo1_of_get_pdata(arizona, &config);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
config.ena_gpio = arizona->pdata.ldoena;
if (arizona->pdata.ldo1)
@@ -223,6 +272,13 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
else
config.init_data = &ldo1->init_data;
+ /*
+ * LDO1 can only be used to supply DCVDD so if it has no
+ * consumers then DCVDD is supplied externally.
+ */
+ if (config.init_data->num_consumer_supplies == 0)
+ arizona->external_dcvdd = true;
+
ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(ldo1->regulator)) {
ret = PTR_ERR(ldo1->regulator);
@@ -231,6 +287,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
return ret;
}
+ of_node_put(config.of_node);
+
platform_set_drvdata(pdev, ldo1);
return 0;
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index 6fdd9bf6927f..ce9aca5f8ee7 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -16,9 +16,11 @@
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@@ -195,6 +197,32 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
.num_consumer_supplies = 1,
};
+static int arizona_micsupp_of_get_pdata(struct arizona *arizona,
+ struct regulator_config *config)
+{
+ struct arizona_pdata *pdata = &arizona->pdata;
+ struct arizona_micsupp *micsupp = config->driver_data;
+ struct device_node *np;
+ struct regulator_init_data *init_data;
+
+ np = of_get_child_by_name(arizona->dev->of_node, "micvdd");
+
+ if (np) {
+ config->of_node = np;
+
+ init_data = of_get_regulator_init_data(arizona->dev, np);
+
+ if (init_data) {
+ init_data->consumer_supplies = &micsupp->supply;
+ init_data->num_consumer_supplies = 1;
+
+ pdata->micvdd = init_data;
+ }
+ }
+
+ return 0;
+}
+
static int arizona_micsupp_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -234,6 +262,14 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
config.driver_data = micsupp;
config.regmap = arizona->regmap;
+ if (IS_ENABLED(CONFIG_OF)) {
+ if (!dev_get_platdata(arizona->dev)) {
+ ret = arizona_micsupp_of_get_pdata(arizona, &config);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
if (arizona->pdata.micvdd)
config.init_data = arizona->pdata.micvdd;
else
@@ -253,6 +289,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
return ret;
}
+ of_node_put(config.of_node);
+
platform_set_drvdata(pdev, micsupp);
return 0;
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
new file mode 100644
index 000000000000..004aadb7bcc1
--- /dev/null
+++ b/drivers/regulator/axp20x-regulator.c
@@ -0,0 +1,286 @@
+/*
+ * AXP20x regulators driver.
+ *
+ * Copyright (C) 2013 Carlo Caione <carlo@caione.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define AXP20X_IO_ENABLED 0x03
+#define AXP20X_IO_DISABLED 0x07
+
+#define AXP20X_WORKMODE_DCDC2_MASK BIT(2)
+#define AXP20X_WORKMODE_DCDC3_MASK BIT(1)
+
+#define AXP20X_FREQ_DCDC_MASK 0x0f
+
+#define AXP20X_DESC_IO(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \
+ _emask, _enable_val, _disable_val) \
+ [AXP20X_##_id] = { \
+ .name = #_id, \
+ .supply_name = (_supply), \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AXP20X_##_id, \
+ .n_voltages = (((_max) - (_min)) / (_step) + 1), \
+ .owner = THIS_MODULE, \
+ .min_uV = (_min) * 1000, \
+ .uV_step = (_step) * 1000, \
+ .vsel_reg = (_vreg), \
+ .vsel_mask = (_vmask), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .enable_val = (_enable_val), \
+ .disable_val = (_disable_val), \
+ .ops = &axp20x_ops, \
+ }
+
+#define AXP20X_DESC(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \
+ _emask) \
+ [AXP20X_##_id] = { \
+ .name = #_id, \
+ .supply_name = (_supply), \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AXP20X_##_id, \
+ .n_voltages = (((_max) - (_min)) / (_step) + 1), \
+ .owner = THIS_MODULE, \
+ .min_uV = (_min) * 1000, \
+ .uV_step = (_step) * 1000, \
+ .vsel_reg = (_vreg), \
+ .vsel_mask = (_vmask), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .ops = &axp20x_ops, \
+ }
+
+#define AXP20X_DESC_FIXED(_id, _supply, _volt) \
+ [AXP20X_##_id] = { \
+ .name = #_id, \
+ .supply_name = (_supply), \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AXP20X_##_id, \
+ .n_voltages = 1, \
+ .owner = THIS_MODULE, \
+ .min_uV = (_volt) * 1000, \
+ .ops = &axp20x_ops_fixed \
+ }
+
+#define AXP20X_DESC_TABLE(_id, _supply, _table, _vreg, _vmask, _ereg, _emask) \
+ [AXP20X_##_id] = { \
+ .name = #_id, \
+ .supply_name = (_supply), \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AXP20X_##_id, \
+ .n_voltages = ARRAY_SIZE(_table), \
+ .owner = THIS_MODULE, \
+ .vsel_reg = (_vreg), \
+ .vsel_mask = (_vmask), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .volt_table = (_table), \
+ .ops = &axp20x_ops_table, \
+ }
+
+static const int axp20x_ldo4_data[] = { 1250000, 1300000, 1400000, 1500000, 1600000,
+ 1700000, 1800000, 1900000, 2000000, 2500000,
+ 2700000, 2800000, 3000000, 3100000, 3200000,
+ 3300000 };
+
+static struct regulator_ops axp20x_ops_fixed = {
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops axp20x_ops_table = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops axp20x_ops = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_desc axp20x_regulators[] = {
+ AXP20X_DESC(DCDC2, "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f,
+ AXP20X_PWR_OUT_CTRL, 0x10),
+ AXP20X_DESC(DCDC3, "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f,
+ AXP20X_PWR_OUT_CTRL, 0x02),
+ AXP20X_DESC_FIXED(LDO1, "acin", 1300),
+ AXP20X_DESC(LDO2, "ldo24in", 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0,
+ AXP20X_PWR_OUT_CTRL, 0x04),
+ AXP20X_DESC(LDO3, "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f,
+ AXP20X_PWR_OUT_CTRL, 0x40),
+ AXP20X_DESC_TABLE(LDO4, "ldo24in", axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f,
+ AXP20X_PWR_OUT_CTRL, 0x08),
+ AXP20X_DESC_IO(LDO5, "ldo5in", 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0,
+ AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED,
+ AXP20X_IO_DISABLED),
+};
+
+#define AXP_MATCH(_name, _id) \
+ [AXP20X_##_id] = { \
+ .name = #_name, \
+ .driver_data = (void *) &axp20x_regulators[AXP20X_##_id], \
+ }
+
+static struct of_regulator_match axp20x_matches[] = {
+ AXP_MATCH(dcdc2, DCDC2),
+ AXP_MATCH(dcdc3, DCDC3),
+ AXP_MATCH(ldo1, LDO1),
+ AXP_MATCH(ldo2, LDO2),
+ AXP_MATCH(ldo3, LDO3),
+ AXP_MATCH(ldo4, LDO4),
+ AXP_MATCH(ldo5, LDO5),
+};
+
+static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
+{
+ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+
+ if (dcdcfreq < 750) {
+ dcdcfreq = 750;
+ dev_warn(&pdev->dev, "DCDC frequency too low. Set to 750kHz\n");
+ }
+
+ if (dcdcfreq > 1875) {
+ dcdcfreq = 1875;
+ dev_warn(&pdev->dev, "DCDC frequency too high. Set to 1875kHz\n");
+ }
+
+ dcdcfreq = (dcdcfreq - 750) / 75;
+
+ return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ,
+ AXP20X_FREQ_DCDC_MASK, dcdcfreq);
+}
+
+static int axp20x_regulator_parse_dt(struct platform_device *pdev)
+{
+ struct device_node *np, *regulators;
+ int ret;
+ u32 dcdcfreq;
+
+ np = of_node_get(pdev->dev.parent->of_node);
+ if (!np)
+ return 0;
+
+ regulators = of_get_child_by_name(np, "regulators");
+ if (!regulators) {
+ dev_warn(&pdev->dev, "regulators node not found\n");
+ } else {
+ ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches,
+ ARRAY_SIZE(axp20x_matches));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
+ return ret;
+ }
+
+ dcdcfreq = 1500;
+ of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq);
+ ret = axp20x_set_dcdc_freq(pdev, dcdcfreq);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error setting dcdc frequency: %d\n", ret);
+ return ret;
+ }
+
+ of_node_put(regulators);
+ }
+
+ return 0;
+}
+
+static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
+{
+ unsigned int mask = AXP20X_WORKMODE_DCDC2_MASK;
+
+ if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3))
+ return -EINVAL;
+
+ if (id == AXP20X_DCDC3)
+ mask = AXP20X_WORKMODE_DCDC3_MASK;
+
+ workmode <<= ffs(mask) - 1;
+
+ return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode);
+}
+
+static int axp20x_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev;
+ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct regulator_init_data *init_data;
+ int ret, i;
+ u32 workmode;
+
+ ret = axp20x_regulator_parse_dt(pdev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
+ init_data = axp20x_matches[i].init_data;
+
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.regmap = axp20x->regmap;
+ config.of_node = axp20x_matches[i].of_node;
+
+ rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "Failed to register %s\n",
+ axp20x_regulators[i].name);
+
+ return PTR_ERR(rdev);
+ }
+
+ ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode",
+ &workmode);
+ if (!ret) {
+ if (axp20x_set_dcdc_workmode(rdev, i, workmode))
+ dev_err(&pdev->dev, "Failed to set workmode on %s\n",
+ axp20x_regulators[i].name);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver axp20x_regulator_driver = {
+ .probe = axp20x_regulator_probe,
+ .driver = {
+ .name = "axp20x-regulator",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(axp20x_regulator_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC");
diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c
index c3750c5b382b..57544e254a78 100644
--- a/drivers/regulator/bcm590xx-regulator.c
+++ b/drivers/regulator/bcm590xx-regulator.c
@@ -22,7 +22,7 @@
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
-/* Register defs */
+/* I2C slave 0 registers */
#define BCM590XX_RFLDOPMCTRL1 0x60
#define BCM590XX_IOSR1PMCTRL1 0x7a
#define BCM590XX_IOSR2PMCTRL1 0x7c
@@ -31,13 +31,34 @@
#define BCM590XX_SDSR2PMCTRL1 0x86
#define BCM590XX_MSRPMCTRL1 0x8a
#define BCM590XX_VSRPMCTRL1 0x8e
-#define BCM590XX_REG_ENABLE BIT(7)
-
#define BCM590XX_RFLDOCTRL 0x96
#define BCM590XX_CSRVOUT1 0xc0
+
+/* I2C slave 1 registers */
+#define BCM590XX_GPLDO5PMCTRL1 0x16
+#define BCM590XX_GPLDO6PMCTRL1 0x18
+#define BCM590XX_GPLDO1CTRL 0x1a
+#define BCM590XX_GPLDO2CTRL 0x1b
+#define BCM590XX_GPLDO3CTRL 0x1c
+#define BCM590XX_GPLDO4CTRL 0x1d
+#define BCM590XX_GPLDO5CTRL 0x1e
+#define BCM590XX_GPLDO6CTRL 0x1f
+#define BCM590XX_OTG_CTRL 0x40
+#define BCM590XX_GPLDO1PMCTRL1 0x57
+#define BCM590XX_GPLDO2PMCTRL1 0x59
+#define BCM590XX_GPLDO3PMCTRL1 0x5b
+#define BCM590XX_GPLDO4PMCTRL1 0x5d
+
+#define BCM590XX_REG_ENABLE BIT(7)
+#define BCM590XX_VBUS_ENABLE BIT(2)
#define BCM590XX_LDO_VSEL_MASK GENMASK(5, 3)
#define BCM590XX_SR_VSEL_MASK GENMASK(5, 0)
+/*
+ * RFLDO to VSR regulators are
+ * accessed via I2C slave 0
+ */
+
/* LDO regulator IDs */
#define BCM590XX_REG_RFLDO 0
#define BCM590XX_REG_CAMLDO1 1
@@ -62,9 +83,25 @@
#define BCM590XX_REG_SDSR2 18
#define BCM590XX_REG_VSR 19
-#define BCM590XX_NUM_REGS 20
+/*
+ * GPLDO1 to VBUS regulators are
+ * accessed via I2C slave 1
+ */
+
+#define BCM590XX_REG_GPLDO1 20
+#define BCM590XX_REG_GPLDO2 21
+#define BCM590XX_REG_GPLDO3 22
+#define BCM590XX_REG_GPLDO4 23
+#define BCM590XX_REG_GPLDO5 24
+#define BCM590XX_REG_GPLDO6 25
+#define BCM590XX_REG_VBUS 26
+
+#define BCM590XX_NUM_REGS 27
#define BCM590XX_REG_IS_LDO(n) (n < BCM590XX_REG_CSR)
+#define BCM590XX_REG_IS_GPLDO(n) \
+ ((n > BCM590XX_REG_VSR) && (n < BCM590XX_REG_VBUS))
+#define BCM590XX_REG_IS_VBUS(n) (n == BCM590XX_REG_VBUS)
struct bcm590xx_board {
struct regulator_init_data *bcm590xx_pmu_init_data[BCM590XX_NUM_REGS];
@@ -149,6 +186,12 @@ static struct bcm590xx_info bcm590xx_regs[] = {
BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges),
BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges),
BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges),
+ BCM590XX_REG_TABLE(gpldo1, ldo_a_table),
+ BCM590XX_REG_TABLE(gpldo2, ldo_a_table),
+ BCM590XX_REG_TABLE(gpldo3, ldo_a_table),
+ BCM590XX_REG_TABLE(gpldo4, ldo_a_table),
+ BCM590XX_REG_TABLE(gpldo5, ldo_a_table),
+ BCM590XX_REG_TABLE(gpldo6, ldo_a_table),
};
struct bcm590xx_reg {
@@ -161,6 +204,8 @@ static int bcm590xx_get_vsel_register(int id)
{
if (BCM590XX_REG_IS_LDO(id))
return BCM590XX_RFLDOCTRL + id;
+ else if (BCM590XX_REG_IS_GPLDO(id))
+ return BCM590XX_GPLDO1CTRL + id;
else
return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3;
}
@@ -171,6 +216,8 @@ static int bcm590xx_get_enable_register(int id)
if (BCM590XX_REG_IS_LDO(id))
reg = BCM590XX_RFLDOPMCTRL1 + id * 2;
+ else if (BCM590XX_REG_IS_GPLDO(id))
+ reg = BCM590XX_GPLDO1PMCTRL1 + id * 2;
else
switch (id) {
case BCM590XX_REG_CSR:
@@ -191,8 +238,11 @@ static int bcm590xx_get_enable_register(int id)
case BCM590XX_REG_SDSR2:
reg = BCM590XX_SDSR2PMCTRL1;
break;
+ case BCM590XX_REG_VBUS:
+ reg = BCM590XX_OTG_CTRL;
};
+
return reg;
}
@@ -216,6 +266,12 @@ static struct regulator_ops bcm590xx_ops_dcdc = {
.map_voltage = regulator_map_voltage_linear_range,
};
+static struct regulator_ops bcm590xx_ops_vbus = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+};
+
#define BCM590XX_MATCH(_name, _id) \
{ \
.name = #_name, \
@@ -243,6 +299,13 @@ static struct of_regulator_match bcm590xx_matches[] = {
BCM590XX_MATCH(sdsr1, SDSR1),
BCM590XX_MATCH(sdsr2, SDSR2),
BCM590XX_MATCH(vsr, VSR),
+ BCM590XX_MATCH(gpldo1, GPLDO1),
+ BCM590XX_MATCH(gpldo2, GPLDO2),
+ BCM590XX_MATCH(gpldo3, GPLDO3),
+ BCM590XX_MATCH(gpldo4, GPLDO4),
+ BCM590XX_MATCH(gpldo5, GPLDO5),
+ BCM590XX_MATCH(gpldo6, GPLDO6),
+ BCM590XX_MATCH(vbus, VBUS),
};
static struct bcm590xx_board *bcm590xx_parse_dt_reg_data(
@@ -353,17 +416,23 @@ static int bcm590xx_probe(struct platform_device *pdev)
pmu->desc[i].linear_ranges = info->linear_ranges;
pmu->desc[i].n_linear_ranges = info->n_linear_ranges;
- if (BCM590XX_REG_IS_LDO(i)) {
+ if ((BCM590XX_REG_IS_LDO(i)) || (BCM590XX_REG_IS_GPLDO(i))) {
pmu->desc[i].ops = &bcm590xx_ops_ldo;
pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK;
- } else {
+ } else if (BCM590XX_REG_IS_VBUS(i))
+ pmu->desc[i].ops = &bcm590xx_ops_vbus;
+ else {
pmu->desc[i].ops = &bcm590xx_ops_dcdc;
pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK;
}
- pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i);
- pmu->desc[i].enable_is_inverted = true;
- pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE;
+ if (BCM590XX_REG_IS_VBUS(i))
+ pmu->desc[i].enable_mask = BCM590XX_VBUS_ENABLE;
+ else {
+ pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i);
+ pmu->desc[i].enable_is_inverted = true;
+ pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE;
+ }
pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i);
pmu->desc[i].type = REGULATOR_VOLTAGE;
pmu->desc[i].owner = THIS_MODULE;
@@ -371,7 +440,10 @@ static int bcm590xx_probe(struct platform_device *pdev)
config.dev = bcm590xx->dev;
config.init_data = reg_data;
config.driver_data = pmu;
- config.regmap = bcm590xx->regmap;
+ if (BCM590XX_REG_IS_GPLDO(i) || BCM590XX_REG_IS_VBUS(i))
+ config.regmap = bcm590xx->regmap_sec;
+ else
+ config.regmap = bcm590xx->regmap_pri;
if (bcm590xx_reg_matches)
config.of_node = bcm590xx_reg_matches[i].of_node;
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9a09f3cdbabb..4c1f999041dd 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -844,13 +844,22 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
/* do we need to apply the constraint voltage */
if (rdev->constraints->apply_uV &&
rdev->constraints->min_uV == rdev->constraints->max_uV) {
- ret = _regulator_do_set_voltage(rdev,
- rdev->constraints->min_uV,
- rdev->constraints->max_uV);
- if (ret < 0) {
- rdev_err(rdev, "failed to apply %duV constraint\n",
- rdev->constraints->min_uV);
- return ret;
+ int current_uV = _regulator_get_voltage(rdev);
+ if (current_uV < 0) {
+ rdev_err(rdev, "failed to get the current voltage\n");
+ return current_uV;
+ }
+ if (current_uV < rdev->constraints->min_uV ||
+ current_uV > rdev->constraints->max_uV) {
+ ret = _regulator_do_set_voltage(
+ rdev, rdev->constraints->min_uV,
+ rdev->constraints->max_uV);
+ if (ret < 0) {
+ rdev_err(rdev,
+ "failed to apply %duV constraint\n",
+ rdev->constraints->min_uV);
+ return ret;
+ }
}
}
@@ -1430,9 +1439,9 @@ EXPORT_SYMBOL_GPL(regulator_get);
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno. Other consumers will be
- * unable to obtain this reference is held and the use count for the
- * regulator will be initialised to reflect the current state of the
- * regulator.
+ * unable to obtain this regulator while this reference is held and the
+ * use count for the regulator will be initialised to reflect the current
+ * state of the regulator.
*
* This is intended for use by consumers which cannot tolerate shared
* use of the regulator such as those which need to force the
@@ -1456,10 +1465,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
- * or IS_ERR() condition containing errno. Other consumers will be
- * unable to obtain this reference is held and the use count for the
- * regulator will be initialised to reflect the current state of the
- * regulator.
+ * or IS_ERR() condition containing errno.
*
* This is intended for use by consumers for devices which can have
* some supplies unconnected in normal use, such as some MMC devices.
@@ -1597,9 +1603,10 @@ EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);
* registered any aliases that were registered will be removed
* before returning to the caller.
*/
-int regulator_bulk_register_supply_alias(struct device *dev, const char **id,
+int regulator_bulk_register_supply_alias(struct device *dev,
+ const char *const *id,
struct device *alias_dev,
- const char **alias_id,
+ const char *const *alias_id,
int num_id)
{
int i;
@@ -1637,7 +1644,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias);
* aliases in one operation.
*/
void regulator_bulk_unregister_supply_alias(struct device *dev,
- const char **id,
+ const char *const *id,
int num_id)
{
int i;
@@ -2321,6 +2328,10 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
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);
@@ -3447,7 +3458,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
/* register with sysfs */
rdev->dev.class = &regulator_class;
- rdev->dev.of_node = config->of_node;
+ rdev->dev.of_node = of_node_get(config->of_node);
rdev->dev.parent = dev;
dev_set_name(&rdev->dev, "regulator.%d",
atomic_inc_return(&regulator_no) - 1);
@@ -3589,6 +3600,7 @@ void regulator_unregister(struct regulator_dev *rdev)
list_del(&rdev->list);
kfree(rdev->constraints);
regulator_ena_gpio_free(rdev);
+ of_node_put(rdev->dev.of_node);
device_unregister(&rdev->dev);
mutex_unlock(&regulator_list_mutex);
}
@@ -3819,8 +3831,9 @@ static int __init regulator_init_complete(void)
mutex_lock(&regulator_list_mutex);
/* If we have a full configuration then disable any regulators
- * which are not in use or always_on. This will become the
- * default behaviour in the future.
+ * we have permission to change the status for and which are
+ * not in use or always_on. This is effectively the default
+ * for DT and ACPI as they have full constraints.
*/
list_for_each_entry(rdev, &regulator_list, list) {
ops = rdev->desc->ops;
@@ -3829,6 +3842,9 @@ static int __init regulator_init_complete(void)
if (c && c->always_on)
continue;
+ if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))
+ continue;
+
mutex_lock(&rdev->mutex);
if (rdev->use_count)
@@ -3867,4 +3883,4 @@ unlock:
return 0;
}
-late_initcall(regulator_init_complete);
+late_initcall_sync(regulator_init_complete);
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index f44818b838dc..8f785bc9e510 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -360,9 +360,9 @@ EXPORT_SYMBOL_GPL(devm_regulator_unregister_supply_alias);
* will be removed before returning to the caller.
*/
int devm_regulator_bulk_register_supply_alias(struct device *dev,
- const char **id,
+ const char *const *id,
struct device *alias_dev,
- const char **alias_id,
+ const char *const *alias_id,
int num_id)
{
int i;
@@ -404,7 +404,7 @@ EXPORT_SYMBOL_GPL(devm_regulator_bulk_register_supply_alias);
* will ensure that the resource is freed.
*/
void devm_regulator_bulk_unregister_supply_alias(struct device *dev,
- const char **id,
+ const char *const *id,
int num_id)
{
int i;
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index c61f7e97e4f8..354105eff1f8 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -50,7 +50,6 @@ of_get_fixed_voltage_config(struct device *dev)
{
struct fixed_voltage_config *config;
struct device_node *np = dev->of_node;
- const __be32 *delay;
struct regulator_init_data *init_data;
config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
@@ -91,15 +90,11 @@ of_get_fixed_voltage_config(struct device *dev)
if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))
return ERR_PTR(-EPROBE_DEFER);
- delay = of_get_property(np, "startup-delay-us", NULL);
- if (delay)
- config->startup_delay = be32_to_cpu(*delay);
+ of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
- if (of_find_property(np, "enable-active-high", NULL))
- config->enable_high = true;
-
- if (of_find_property(np, "gpio-open-drain", NULL))
- config->gpio_is_open_drain = true;
+ config->enable_high = of_property_read_bool(np, "enable-active-high");
+ config->gpio_is_open_drain = of_property_read_bool(np,
+ "gpio-open-drain");
if (of_find_property(np, "vin-supply", NULL))
config->input_supply = "vin";
diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c
new file mode 100644
index 000000000000..110a99ee1162
--- /dev/null
+++ b/drivers/regulator/ltc3589.c
@@ -0,0 +1,554 @@
+/*
+ * Linear Technology LTC3589,LTC3589-1 regulator support
+ *
+ * Copyright (c) 2014 Philipp Zabel <p.zabel@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define DRIVER_NAME "ltc3589"
+
+#define LTC3589_IRQSTAT 0x02
+#define LTC3589_SCR1 0x07
+#define LTC3589_OVEN 0x10
+#define LTC3589_SCR2 0x12
+#define LTC3589_PGSTAT 0x13
+#define LTC3589_VCCR 0x20
+#define LTC3589_CLIRQ 0x21
+#define LTC3589_B1DTV1 0x23
+#define LTC3589_B1DTV2 0x24
+#define LTC3589_VRRCR 0x25
+#define LTC3589_B2DTV1 0x26
+#define LTC3589_B2DTV2 0x27
+#define LTC3589_B3DTV1 0x29
+#define LTC3589_B3DTV2 0x2a
+#define LTC3589_L2DTV1 0x32
+#define LTC3589_L2DTV2 0x33
+
+#define LTC3589_IRQSTAT_PGOOD_TIMEOUT BIT(3)
+#define LTC3589_IRQSTAT_UNDERVOLT_WARN BIT(4)
+#define LTC3589_IRQSTAT_UNDERVOLT_FAULT BIT(5)
+#define LTC3589_IRQSTAT_THERMAL_WARN BIT(6)
+#define LTC3589_IRQSTAT_THERMAL_FAULT BIT(7)
+
+#define LTC3589_OVEN_SW1 BIT(0)
+#define LTC3589_OVEN_SW2 BIT(1)
+#define LTC3589_OVEN_SW3 BIT(2)
+#define LTC3589_OVEN_BB_OUT BIT(3)
+#define LTC3589_OVEN_LDO2 BIT(4)
+#define LTC3589_OVEN_LDO3 BIT(5)
+#define LTC3589_OVEN_LDO4 BIT(6)
+#define LTC3589_OVEN_SW_CTRL BIT(7)
+
+#define LTC3589_VCCR_SW1_GO BIT(0)
+#define LTC3589_VCCR_SW2_GO BIT(2)
+#define LTC3589_VCCR_SW3_GO BIT(4)
+#define LTC3589_VCCR_LDO2_GO BIT(6)
+
+enum ltc3589_variant {
+ LTC3589,
+ LTC3589_1,
+ LTC3589_2,
+};
+
+enum ltc3589_reg {
+ LTC3589_SW1,
+ LTC3589_SW2,
+ LTC3589_SW3,
+ LTC3589_BB_OUT,
+ LTC3589_LDO1,
+ LTC3589_LDO2,
+ LTC3589_LDO3,
+ LTC3589_LDO4,
+ LTC3589_NUM_REGULATORS,
+};
+
+struct ltc3589_regulator {
+ struct regulator_desc desc;
+
+ /* External feedback voltage divider */
+ unsigned int r1;
+ unsigned int r2;
+};
+
+struct ltc3589 {
+ struct regmap *regmap;
+ struct device *dev;
+ enum ltc3589_variant variant;
+ struct ltc3589_regulator regulator_descs[LTC3589_NUM_REGULATORS];
+ struct regulator_dev *regulators[LTC3589_NUM_REGULATORS];
+};
+
+static const int ltc3589_ldo4[] = {
+ 2800000, 2500000, 1800000, 3300000,
+};
+
+static const int ltc3589_12_ldo4[] = {
+ 1200000, 1800000, 2500000, 3200000,
+};
+
+static int ltc3589_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev);
+ int sel, shift;
+
+ if (unlikely(ramp_delay <= 0))
+ return -EINVAL;
+
+ /* VRRCR slew rate offsets are the same as VCCR go bit offsets */
+ shift = ffs(rdev->desc->apply_bit) - 1;
+
+ /* The slew rate can be set to 0.88, 1.75, 3.5, or 7 mV/uS */
+ for (sel = 0; sel < 4; sel++) {
+ if ((880 << sel) >= ramp_delay) {
+ return regmap_update_bits(ltc3589->regmap,
+ LTC3589_VRRCR,
+ 0x3 << shift, sel << shift);
+ }
+ }
+ return -EINVAL;
+}
+
+static int ltc3589_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev);
+ int sel;
+
+ sel = regulator_map_voltage_linear(rdev, uV, uV);
+ if (sel < 0)
+ return sel;
+
+ /* DTV2 register follows right after the corresponding DTV1 register */
+ return regmap_update_bits(ltc3589->regmap, rdev->desc->vsel_reg + 1,
+ rdev->desc->vsel_mask, sel);
+}
+
+static int ltc3589_set_suspend_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev);
+ int mask, bit = 0;
+
+ /* VCCR reference selects are right next to the VCCR go bits */
+ mask = rdev->desc->apply_bit << 1;
+
+ if (mode == REGULATOR_MODE_STANDBY)
+ bit = mask; /* Select DTV2 */
+
+ mask |= rdev->desc->apply_bit;
+ bit |= rdev->desc->apply_bit;
+ return regmap_update_bits(ltc3589->regmap, LTC3589_VCCR, mask, bit);
+}
+
+/* SW1, SW2, SW3, LDO2 */
+static struct regulator_ops ltc3589_linear_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_ramp_delay = ltc3589_set_ramp_delay,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_voltage = ltc3589_set_suspend_voltage,
+ .set_suspend_mode = ltc3589_set_suspend_mode,
+};
+
+/* BB_OUT, LDO3 */
+static struct regulator_ops ltc3589_fixed_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+/* LDO1 */
+static struct regulator_ops ltc3589_fixed_standby_regulator_ops = {
+};
+
+/* LDO4 */
+static struct regulator_ops ltc3589_table_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+
+#define LTC3589_REG(_name, _ops, en_bit, dtv1_reg, dtv_mask, go_bit) \
+ [LTC3589_ ## _name] = { \
+ .desc = { \
+ .name = #_name, \
+ .n_voltages = (dtv_mask) + 1, \
+ .min_uV = (go_bit) ? 362500 : 0, \
+ .uV_step = (go_bit) ? 12500 : 0, \
+ .ramp_delay = (go_bit) ? 1750 : 0, \
+ .fixed_uV = (dtv_mask) ? 0 : 800000, \
+ .ops = &ltc3589_ ## _ops ## _regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = LTC3589_ ## _name, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = (dtv1_reg), \
+ .vsel_mask = (dtv_mask), \
+ .apply_reg = (go_bit) ? LTC3589_VCCR : 0, \
+ .apply_bit = (go_bit), \
+ .enable_reg = (en_bit) ? LTC3589_OVEN : 0, \
+ .enable_mask = (en_bit), \
+ }, \
+ }
+
+#define LTC3589_LINEAR_REG(_name, _dtv1) \
+ LTC3589_REG(_name, linear, LTC3589_OVEN_ ## _name, \
+ LTC3589_ ## _dtv1, 0x1f, \
+ LTC3589_VCCR_ ## _name ## _GO)
+
+#define LTC3589_FIXED_REG(_name) \
+ LTC3589_REG(_name, fixed, LTC3589_OVEN_ ## _name, 0, 0, 0)
+
+static struct ltc3589_regulator ltc3589_regulators[LTC3589_NUM_REGULATORS] = {
+ LTC3589_LINEAR_REG(SW1, B1DTV1),
+ LTC3589_LINEAR_REG(SW2, B2DTV1),
+ LTC3589_LINEAR_REG(SW3, B3DTV1),
+ LTC3589_FIXED_REG(BB_OUT),
+ LTC3589_REG(LDO1, fixed_standby, 0, 0, 0, 0),
+ LTC3589_LINEAR_REG(LDO2, L2DTV1),
+ LTC3589_FIXED_REG(LDO3),
+ LTC3589_REG(LDO4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, 0x60, 0),
+};
+
+#ifdef CONFIG_OF
+static struct of_regulator_match ltc3589_matches[LTC3589_NUM_REGULATORS] = {
+ { .name = "sw1", },
+ { .name = "sw2", },
+ { .name = "sw3", },
+ { .name = "bb-out", },
+ { .name = "ldo1", }, /* standby */
+ { .name = "ldo2", },
+ { .name = "ldo3", },
+ { .name = "ldo4", },
+};
+
+static int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589)
+{
+ struct device *dev = ltc3589->dev;
+ struct device_node *node;
+ int i, ret;
+
+ node = of_find_node_by_name(dev->of_node, "regulators");
+ if (!node) {
+ dev_err(dev, "regulators node not found\n");
+ return -EINVAL;
+ }
+
+ ret = of_regulator_match(dev, node, ltc3589_matches,
+ ARRAY_SIZE(ltc3589_matches));
+ of_node_put(node);
+ if (ret < 0) {
+ dev_err(dev, "Error parsing regulator init data: %d\n", ret);
+ return ret;
+ }
+ if (ret != LTC3589_NUM_REGULATORS) {
+ dev_err(dev, "Only %d regulators described in device tree\n",
+ ret);
+ return -EINVAL;
+ }
+
+ /* Parse feedback voltage dividers. LDO3 and LDO4 don't have them */
+ for (i = 0; i < LTC3589_LDO3; i++) {
+ struct ltc3589_regulator *desc = &ltc3589->regulator_descs[i];
+ struct device_node *np = ltc3589_matches[i].of_node;
+ u32 vdiv[2];
+
+ ret = of_property_read_u32_array(np, "lltc,fb-voltage-divider",
+ vdiv, 2);
+ if (ret) {
+ dev_err(dev, "Failed to parse voltage divider: %d\n",
+ ret);
+ return ret;
+ }
+
+ desc->r1 = vdiv[0];
+ desc->r2 = vdiv[1];
+ }
+
+ return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+ return ltc3589_matches[index].init_data;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+ return ltc3589_matches[index].of_node;
+}
+#else
+static inline int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589)
+{
+ return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+ return NULL;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+ return NULL;
+}
+#endif
+
+static bool ltc3589_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LTC3589_IRQSTAT:
+ case LTC3589_SCR1:
+ case LTC3589_OVEN:
+ case LTC3589_SCR2:
+ case LTC3589_VCCR:
+ case LTC3589_CLIRQ:
+ case LTC3589_B1DTV1:
+ case LTC3589_B1DTV2:
+ case LTC3589_VRRCR:
+ case LTC3589_B2DTV1:
+ case LTC3589_B2DTV2:
+ case LTC3589_B3DTV1:
+ case LTC3589_B3DTV2:
+ case LTC3589_L2DTV1:
+ case LTC3589_L2DTV2:
+ return true;
+ }
+ return false;
+}
+
+static bool ltc3589_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LTC3589_IRQSTAT:
+ case LTC3589_SCR1:
+ case LTC3589_OVEN:
+ case LTC3589_SCR2:
+ case LTC3589_PGSTAT:
+ case LTC3589_VCCR:
+ case LTC3589_B1DTV1:
+ case LTC3589_B1DTV2:
+ case LTC3589_VRRCR:
+ case LTC3589_B2DTV1:
+ case LTC3589_B2DTV2:
+ case LTC3589_B3DTV1:
+ case LTC3589_B3DTV2:
+ case LTC3589_L2DTV1:
+ case LTC3589_L2DTV2:
+ return true;
+ }
+ return false;
+}
+
+static bool ltc3589_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LTC3589_IRQSTAT:
+ case LTC3589_PGSTAT:
+ return true;
+ }
+ return false;
+}
+
+struct reg_default ltc3589_reg_defaults[] = {
+ { LTC3589_SCR1, 0x00 },
+ { LTC3589_OVEN, 0x00 },
+ { LTC3589_SCR2, 0x00 },
+ { LTC3589_VCCR, 0x00 },
+ { LTC3589_B1DTV1, 0x19 },
+ { LTC3589_B1DTV2, 0x19 },
+ { LTC3589_VRRCR, 0xff },
+ { LTC3589_B2DTV1, 0x19 },
+ { LTC3589_B2DTV2, 0x19 },
+ { LTC3589_B3DTV1, 0x19 },
+ { LTC3589_B3DTV2, 0x19 },
+ { LTC3589_L2DTV1, 0x19 },
+ { LTC3589_L2DTV2, 0x19 },
+};
+
+static const struct regmap_config ltc3589_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = ltc3589_writeable_reg,
+ .readable_reg = ltc3589_readable_reg,
+ .volatile_reg = ltc3589_volatile_reg,
+ .max_register = LTC3589_L2DTV2,
+ .reg_defaults = ltc3589_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ltc3589_reg_defaults),
+ .use_single_rw = true,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+
+static irqreturn_t ltc3589_isr(int irq, void *dev_id)
+{
+ struct ltc3589 *ltc3589 = dev_id;
+ unsigned int i, irqstat, event;
+
+ regmap_read(ltc3589->regmap, LTC3589_IRQSTAT, &irqstat);
+
+ if (irqstat & LTC3589_IRQSTAT_THERMAL_WARN) {
+ event = REGULATOR_EVENT_OVER_TEMP;
+ for (i = 0; i < LTC3589_NUM_REGULATORS; i++)
+ regulator_notifier_call_chain(ltc3589->regulators[i],
+ event, NULL);
+ }
+
+ if (irqstat & LTC3589_IRQSTAT_UNDERVOLT_WARN) {
+ event = REGULATOR_EVENT_UNDER_VOLTAGE;
+ for (i = 0; i < LTC3589_NUM_REGULATORS; i++)
+ regulator_notifier_call_chain(ltc3589->regulators[i],
+ event, NULL);
+ }
+
+ /* Clear warning condition */
+ regmap_write(ltc3589->regmap, LTC3589_CLIRQ, 0);
+
+ return IRQ_HANDLED;
+}
+
+static inline unsigned int ltc3589_scale(unsigned int uV, u32 r1, u32 r2)
+{
+ uint64_t tmp;
+ if (uV == 0)
+ return 0;
+ tmp = (uint64_t)uV * r1;
+ do_div(tmp, r2);
+ return uV + (unsigned int)tmp;
+}
+
+static void ltc3589_apply_fb_voltage_divider(struct ltc3589_regulator *rdesc)
+{
+ struct regulator_desc *desc = &rdesc->desc;
+
+ if (!rdesc->r1 || !rdesc->r2)
+ return;
+
+ desc->min_uV = ltc3589_scale(desc->min_uV, rdesc->r1, rdesc->r2);
+ desc->uV_step = ltc3589_scale(desc->uV_step, rdesc->r1, rdesc->r2);
+ desc->fixed_uV = ltc3589_scale(desc->fixed_uV, rdesc->r1, rdesc->r2);
+}
+
+static int ltc3589_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct ltc3589_regulator *descs;
+ struct ltc3589 *ltc3589;
+ int i, ret;
+
+ ltc3589 = devm_kzalloc(dev, sizeof(*ltc3589), GFP_KERNEL);
+ if (!ltc3589)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, ltc3589);
+ ltc3589->variant = id->driver_data;
+ ltc3589->dev = dev;
+
+ descs = ltc3589->regulator_descs;
+ memcpy(descs, ltc3589_regulators, sizeof(ltc3589_regulators));
+ if (ltc3589->variant == LTC3589) {
+ descs[LTC3589_LDO3].desc.fixed_uV = 1800000;
+ descs[LTC3589_LDO4].desc.volt_table = ltc3589_ldo4;
+ } else {
+ descs[LTC3589_LDO3].desc.fixed_uV = 2800000;
+ descs[LTC3589_LDO4].desc.volt_table = ltc3589_12_ldo4;
+ }
+
+ ltc3589->regmap = devm_regmap_init_i2c(client, &ltc3589_regmap_config);
+ if (IS_ERR(ltc3589->regmap)) {
+ ret = PTR_ERR(ltc3589->regmap);
+ dev_err(dev, "failed to initialize regmap: %d\n", ret);
+ return ret;
+ }
+
+ ret = ltc3589_parse_regulators_dt(ltc3589);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < LTC3589_NUM_REGULATORS; i++) {
+ struct ltc3589_regulator *rdesc = &ltc3589->regulator_descs[i];
+ struct regulator_desc *desc = &rdesc->desc;
+ struct regulator_init_data *init_data;
+ struct regulator_config config = { };
+
+ init_data = match_init_data(i);
+
+ if (i < LTC3589_LDO3)
+ ltc3589_apply_fb_voltage_divider(rdesc);
+
+ config.dev = dev;
+ config.init_data = init_data;
+ config.driver_data = ltc3589;
+ config.of_node = match_of_node(i);
+
+ ltc3589->regulators[i] = devm_regulator_register(dev, desc,
+ &config);
+ if (IS_ERR(ltc3589->regulators[i])) {
+ ret = PTR_ERR(ltc3589->regulators[i]);
+ dev_err(dev, "failed to register regulator %s: %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL, ltc3589_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->name, ltc3589);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct i2c_device_id ltc3589_i2c_id[] = {
+ { "ltc3589", LTC3589 },
+ { "ltc3589-1", LTC3589_1 },
+ { "ltc3589-2", LTC3589_2 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc3589_i2c_id);
+
+static struct i2c_driver ltc3589_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ltc3589_probe,
+ .id_table = ltc3589_i2c_id,
+};
+module_i2c_driver(ltc3589_driver);
+
+MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
+MODULE_DESCRIPTION("Regulator driver for Linear Technology LTC3589(-1,2)");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:ltc3589");
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 3172da847d24..c8bddcc8f911 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -161,10 +161,8 @@ static int max8649_regulator_probe(struct i2c_client *client,
info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info),
GFP_KERNEL);
- if (!info) {
- dev_err(&client->dev, "No enough memory\n");
+ if (!info)
return -ENOMEM;
- }
info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config);
if (IS_ERR(info->regmap)) {
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index d920f5a32ec8..c2792f0271ab 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -129,7 +129,7 @@ static const struct regulator_desc regulator = {
};
#ifdef CONFIG_OF
-static struct of_device_id max8952_dt_match[] = {
+static const struct of_device_id max8952_dt_match[] = {
{ .compatible = "maxim,max8952" },
{},
};
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index ea4f36f2cbe2..ee5e67bc8d5b 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -19,9 +19,7 @@
static void of_get_regulation_constraints(struct device_node *np,
struct regulator_init_data **init_data)
{
- const __be32 *min_uV, *max_uV, *uV_offset;
- const __be32 *min_uA, *max_uA, *ramp_delay;
- struct property *prop;
+ const __be32 *min_uV, *max_uV;
struct regulation_constraints *constraints = &(*init_data)->constraints;
int ret;
u32 pval;
@@ -42,36 +40,29 @@ static void of_get_regulation_constraints(struct device_node *np,
if (min_uV && max_uV && constraints->min_uV == constraints->max_uV)
constraints->apply_uV = true;
- uV_offset = of_get_property(np, "regulator-microvolt-offset", NULL);
- if (uV_offset)
- constraints->uV_offset = be32_to_cpu(*uV_offset);
- min_uA = of_get_property(np, "regulator-min-microamp", NULL);
- if (min_uA)
- constraints->min_uA = be32_to_cpu(*min_uA);
- max_uA = of_get_property(np, "regulator-max-microamp", NULL);
- if (max_uA)
- constraints->max_uA = be32_to_cpu(*max_uA);
+ if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
+ constraints->uV_offset = pval;
+ if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
+ constraints->min_uA = pval;
+ if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
+ constraints->max_uA = pval;
/* Current change possible? */
if (constraints->min_uA != constraints->max_uA)
constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
- if (of_find_property(np, "regulator-boot-on", NULL))
- constraints->boot_on = true;
-
- if (of_find_property(np, "regulator-always-on", NULL))
- constraints->always_on = true;
- else /* status change should be possible if not always on. */
+ constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
+ constraints->always_on = of_property_read_bool(np, "regulator-always-on");
+ if (!constraints->always_on) /* status change should be possible. */
constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
if (of_property_read_bool(np, "regulator-allow-bypass"))
constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
- prop = of_find_property(np, "regulator-ramp-delay", NULL);
- if (prop && prop->value) {
- ramp_delay = prop->value;
- if (*ramp_delay)
- constraints->ramp_delay = be32_to_cpu(*ramp_delay);
+ ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
+ if (!ret) {
+ if (pval)
+ constraints->ramp_delay = pval;
else
constraints->ramp_disable = true;
}
@@ -106,6 +97,20 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
}
EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
+struct devm_of_regulator_matches {
+ struct of_regulator_match *matches;
+ unsigned int num_matches;
+};
+
+static void devm_of_regulator_put_matches(struct device *dev, void *res)
+{
+ struct devm_of_regulator_matches *devm_matches = res;
+ int i;
+
+ for (i = 0; i < devm_matches->num_matches; i++)
+ of_node_put(devm_matches->matches[i].of_node);
+}
+
/**
* of_regulator_match - extract multiple regulator init data from device tree.
* @dev: device requesting the data
@@ -119,7 +124,8 @@ EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
* regulator. The data parsed from a child node will be matched to a regulator
* based on either the deprecated property regulator-compatible if present,
* or otherwise the child node's name. Note that the match table is modified
- * in place.
+ * in place and an additional of_node reference is taken for each matched
+ * regulator.
*
* Returns the number of matches found or a negative error code on failure.
*/
@@ -131,10 +137,22 @@ int of_regulator_match(struct device *dev, struct device_node *node,
unsigned int i;
const char *name;
struct device_node *child;
+ struct devm_of_regulator_matches *devm_matches;
if (!dev || !node)
return -EINVAL;
+ devm_matches = devres_alloc(devm_of_regulator_put_matches,
+ sizeof(struct devm_of_regulator_matches),
+ GFP_KERNEL);
+ if (!devm_matches)
+ return -ENOMEM;
+
+ devm_matches->matches = matches;
+ devm_matches->num_matches = num_matches;
+
+ devres_add(dev, devm_matches);
+
for (i = 0; i < num_matches; i++) {
struct of_regulator_match *match = &matches[i];
match->init_data = NULL;
@@ -162,7 +180,7 @@ int of_regulator_match(struct device *dev, struct device_node *node,
child->name);
return -EINVAL;
}
- match->of_node = child;
+ match->of_node = of_node_get(child);
count++;
break;
}
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index 9c62b1d34685..864ed02ce4b7 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -36,6 +36,18 @@ struct regs_info {
int sleep_id;
};
+static const struct regulator_linear_range smps_low_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x1, 0x6, 0),
+ REGULATOR_LINEAR_RANGE(510000, 0x7, 0x79, 10000),
+ REGULATOR_LINEAR_RANGE(1650000, 0x7A, 0x7f, 0),
+};
+
+static const struct regulator_linear_range smps_high_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x6, 0),
+ REGULATOR_LINEAR_RANGE(1020000, 0x7, 0x79, 20000),
+ REGULATOR_LINEAR_RANGE(3300000, 0x7A, 0x7f, 0),
+};
+
static const struct regs_info palmas_regs_info[] = {
{
.name = "SMPS12",
@@ -280,54 +292,6 @@ static int palmas_ldo_write(struct palmas *palmas, unsigned int reg,
return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value);
}
-static int palmas_is_enabled_smps(struct regulator_dev *dev)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- unsigned int reg;
-
- palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
-
- reg &= PALMAS_SMPS12_CTRL_STATUS_MASK;
- reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
-
- return !!(reg);
-}
-
-static int palmas_enable_smps(struct regulator_dev *dev)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- unsigned int reg;
-
- palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
-
- reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
- if (pmic->current_reg_mode[id])
- reg |= pmic->current_reg_mode[id];
- else
- reg |= SMPS_CTRL_MODE_ON;
-
- palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
-
- return 0;
-}
-
-static int palmas_disable_smps(struct regulator_dev *dev)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- unsigned int reg;
-
- palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
-
- reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
-
- palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
-
- return 0;
-}
-
static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
{
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
@@ -382,81 +346,6 @@ static unsigned int palmas_get_mode_smps(struct regulator_dev *dev)
return 0;
}
-static int palmas_list_voltage_smps(struct regulator_dev *dev,
- unsigned selector)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- int mult = 1;
-
- /* Read the multiplier set in VSEL register to return
- * the correct voltage.
- */
- if (pmic->range[id])
- mult = 2;
-
- if (selector == 0)
- return 0;
- else if (selector < 6)
- return 500000 * mult;
- else
- /* Voltage is linear mapping starting from selector 6,
- * volt = (0.49V + ((selector - 5) * 0.01V)) * RANGE
- * RANGE is either x1 or x2
- */
- return (490000 + ((selector - 5) * 10000)) * mult;
-}
-
-static int palmas_map_voltage_smps(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
- int ret, voltage;
-
- if (min_uV == 0)
- return 0;
-
- if (pmic->range[id]) { /* RANGE is x2 */
- if (min_uV < 1000000)
- min_uV = 1000000;
- ret = DIV_ROUND_UP(min_uV - 1000000, 20000) + 6;
- } else { /* RANGE is x1 */
- if (min_uV < 500000)
- min_uV = 500000;
- ret = DIV_ROUND_UP(min_uV - 500000, 10000) + 6;
- }
-
- /* Map back into a voltage to verify we're still in bounds */
- voltage = palmas_list_voltage_smps(rdev, ret);
- if (voltage < min_uV || voltage > max_uV)
- return -EINVAL;
-
- return ret;
-}
-
-static int palma_smps_set_voltage_smps_time_sel(struct regulator_dev *rdev,
- unsigned int old_selector, unsigned int new_selector)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
- int old_uv, new_uv;
- unsigned int ramp_delay = pmic->ramp_delay[id];
-
- if (!ramp_delay)
- return 0;
-
- old_uv = palmas_list_voltage_smps(rdev, old_selector);
- if (old_uv < 0)
- return old_uv;
-
- new_uv = palmas_list_voltage_smps(rdev, new_selector);
- if (new_uv < 0)
- return new_uv;
-
- return DIV_ROUND_UP(abs(old_uv - new_uv), ramp_delay);
-}
-
static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,
int ramp_delay)
{
@@ -493,16 +382,16 @@ static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,
}
static struct regulator_ops palmas_ops_smps = {
- .is_enabled = palmas_is_enabled_smps,
- .enable = palmas_enable_smps,
- .disable = palmas_disable_smps,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.set_mode = palmas_set_mode_smps,
.get_mode = palmas_get_mode_smps,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .list_voltage = palmas_list_voltage_smps,
- .map_voltage = palmas_map_voltage_smps,
- .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = palmas_smps_set_ramp_delay,
};
@@ -511,9 +400,9 @@ static struct regulator_ops palmas_ops_ext_control_smps = {
.get_mode = palmas_get_mode_smps,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .list_voltage = palmas_list_voltage_smps,
- .map_voltage = palmas_map_voltage_smps,
- .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = palmas_smps_set_ramp_delay,
};
@@ -1042,12 +931,17 @@ static int palmas_regulators_probe(struct platform_device *pdev)
* ranges. Read the current smps mode for later use.
*/
addr = palmas_regs_info[id].vsel_addr;
+ pmic->desc[id].n_linear_ranges = 3;
ret = palmas_smps_read(pmic->palmas, addr, &reg);
if (ret)
return ret;
if (reg & PALMAS_SMPS12_VOLTAGE_RANGE)
pmic->range[id] = 1;
+ if (pmic->range[id])
+ pmic->desc[id].linear_ranges = smps_high_ranges;
+ else
+ pmic->desc[id].linear_ranges = smps_low_ranges;
if (reg_init && reg_init->roof_floor)
pmic->desc[id].ops =
@@ -1199,7 +1093,7 @@ static int palmas_regulators_probe(struct platform_device *pdev)
return 0;
}
-static struct of_device_id of_palmas_match_tbl[] = {
+static const struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas-pmic", },
{ .compatible = "ti,twl6035-pmic", },
{ .compatible = "ti,twl6036-pmic", },
diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c
index 6d38be3d970c..6d02d68dfb46 100644
--- a/drivers/regulator/pbias-regulator.c
+++ b/drivers/regulator/pbias-regulator.c
@@ -49,33 +49,13 @@ static const unsigned int pbias_volt_table[] = {
3000000
};
-static int pbias_regulator_enable(struct regulator_dev *rdev)
-{
- struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
- const struct pbias_reg_info *info = data->info;
-
- return regmap_update_bits(data->syscon, rdev->desc->enable_reg,
- info->enable_mask, info->enable);
-}
-
-static int pbias_regulator_is_enable(struct regulator_dev *rdev)
-{
- struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
- const struct pbias_reg_info *info = data->info;
- int value;
-
- regmap_read(data->syscon, rdev->desc->enable_reg, &value);
-
- return (value & info->enable_mask) == info->enable;
-}
-
static struct regulator_ops pbias_regulator_voltage_ops = {
.list_voltage = regulator_list_voltage_table,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .enable = pbias_regulator_enable,
+ .enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .is_enabled = pbias_regulator_is_enable,
+ .is_enabled = regulator_is_enabled_regmap,
};
static const struct pbias_reg_info pbias_mmc_omap2430 = {
@@ -142,10 +122,8 @@ static int pbias_regulator_probe(struct platform_device *pdev)
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data)
* count, GFP_KERNEL);
- if (drvdata == NULL) {
- dev_err(&pdev->dev, "Failed to allocate device data\n");
+ if (!drvdata)
return -ENOMEM;
- }
syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(syscon))
@@ -180,6 +158,7 @@ static int pbias_regulator_probe(struct platform_device *pdev)
drvdata[data_idx].desc.vsel_mask = info->vmode;
drvdata[data_idx].desc.enable_reg = res->start;
drvdata[data_idx].desc.enable_mask = info->enable_mask;
+ drvdata[data_idx].desc.enable_val = info->enable;
cfg.init_data = pbias_matches[idx].init_data;
cfg.driver_data = &drvdata[data_idx];
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 67e678c4301c..c879dff597ee 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -125,6 +125,9 @@ static struct regulator_ops pfuze100_ldo_regulator_ops = {
};
static struct regulator_ops pfuze100_fixed_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear,
};
@@ -137,6 +140,8 @@ static struct regulator_ops pfuze100_sw_regulator_ops = {
};
static struct regulator_ops pfuze100_swb_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -189,6 +194,8 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
.volt_table = voltages, \
.vsel_reg = (base), \
.vsel_mask = (mask), \
+ .enable_reg = (base), \
+ .enable_mask = 0x48, \
}, \
}
@@ -502,6 +509,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
config.init_data = init_data;
config.driver_data = pfuze_chip;
config.of_node = match_of_node(i);
+ config.ena_gpio = -EINVAL;
pfuze_chip->regulators[i] =
devm_regulator_register(&client->dev, desc, &config);
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
index f19a30f0fb42..ee83b4876420 100644
--- a/drivers/regulator/s2mpa01.c
+++ b/drivers/regulator/s2mpa01.c
@@ -61,7 +61,7 @@ static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int ramp_delay = 0;
int old_volt, new_volt;
- switch (rdev->desc->id) {
+ switch (rdev_get_id(rdev)) {
case S2MPA01_BUCK2:
case S2MPA01_BUCK4:
ramp_delay = s2mpa01->ramp_delay24;
@@ -102,7 +102,7 @@ static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
unsigned int ramp_enable = 1, enable_shift = 0;
int ret;
- switch (rdev->desc->id) {
+ switch (rdev_get_id(rdev)) {
case S2MPA01_BUCK1:
enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT;
if (!ramp_delay) {
@@ -116,7 +116,6 @@ static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
ramp_delay = s2mpa01->ramp_delay16;
ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
- ramp_reg = S2MPA01_REG_RAMP1;
break;
case S2MPA01_BUCK2:
enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT;
@@ -192,11 +191,15 @@ static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
if (!ramp_enable)
goto ramp_disable;
- ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
- 1 << enable_shift, 1 << enable_shift);
- if (ret) {
- dev_err(&rdev->dev, "failed to enable ramp rate\n");
- return ret;
+ /* Ramp delay can be enabled/disabled only for buck[1234] */
+ if (rdev_get_id(rdev) >= S2MPA01_BUCK1 &&
+ rdev_get_id(rdev) <= S2MPA01_BUCK4) {
+ ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+ 1 << enable_shift, 1 << enable_shift);
+ if (ret) {
+ dev_err(&rdev->dev, "failed to enable ramp rate\n");
+ return ret;
+ }
}
ramp_val = get_ramp_delay(ramp_delay);
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index e713c162fbd4..02e2fb2fca66 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -27,6 +27,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#include <linux/of_gpio.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps14.h>
@@ -44,6 +45,8 @@ struct s2mps11_info {
* was enabled.
*/
unsigned int s2mps14_suspend_state:30;
+ /* Array of size rdev_num with GPIO-s for external sleep control */
+ int *ext_control_gpio;
};
static int get_ramp_delay(int ramp_delay)
@@ -202,11 +205,16 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
if (!ramp_enable)
goto ramp_disable;
- ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
- 1 << enable_shift, 1 << enable_shift);
- if (ret) {
- dev_err(&rdev->dev, "failed to enable ramp rate\n");
- return ret;
+ /* Ramp delay can be enabled/disabled only for buck[2346] */
+ if ((rdev_get_id(rdev) >= S2MPS11_BUCK2 &&
+ rdev_get_id(rdev) <= S2MPS11_BUCK4) ||
+ rdev_get_id(rdev) == S2MPS11_BUCK6) {
+ ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
+ 1 << enable_shift, 1 << enable_shift);
+ if (ret) {
+ dev_err(&rdev->dev, "failed to enable ramp rate\n");
+ return ret;
+ }
}
ramp_val = get_ramp_delay(ramp_delay);
@@ -409,6 +417,8 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
val = S2MPS14_ENABLE_SUSPEND;
+ else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)]))
+ val = S2MPS14_ENABLE_EXT_CONTROL;
else
val = rdev->desc->enable_mask;
@@ -565,12 +575,61 @@ static const struct regulator_desc s2mps14_regulators[] = {
regulator_desc_s2mps14_buck1235(5),
};
+static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
+ struct regulator_dev *rdev)
+{
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL);
+}
+
+static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
+ struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
+{
+ int *gpio = s2mps11->ext_control_gpio;
+ unsigned int i;
+ unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11,
+ S2MPS14_LDO12 };
+
+ for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) {
+ unsigned int reg = valid_regulators[i];
+
+ if (!rdata[reg].init_data || !rdata[reg].of_node)
+ continue;
+
+ gpio[reg] = of_get_named_gpio(rdata[reg].of_node,
+ "samsung,ext-control-gpios", 0);
+ if (gpio_is_valid(gpio[reg]))
+ dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n",
+ gpio[reg], reg, rdata[reg].name);
+ }
+}
+
+static int s2mps11_pmic_dt_parse(struct platform_device *pdev,
+ struct of_regulator_match *rdata, struct s2mps11_info *s2mps11,
+ enum sec_device_type dev_type)
+{
+ struct device_node *reg_np;
+
+ reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
+ if (!reg_np) {
+ dev_err(&pdev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
+ if (dev_type == S2MPS14X)
+ s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11);
+
+ of_node_put(reg_np);
+
+ return 0;
+}
+
static int s2mps11_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct sec_platform_data *pdata = iodev->pdata;
+ struct sec_platform_data *pdata = NULL;
struct of_regulator_match *rdata = NULL;
- struct device_node *reg_np = NULL;
struct regulator_config config = { };
struct s2mps11_info *s2mps11;
int i, ret = 0;
@@ -597,8 +656,21 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
return -EINVAL;
};
+ s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev,
+ sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num,
+ GFP_KERNEL);
+ if (!s2mps11->ext_control_gpio)
+ return -ENOMEM;
+ /*
+ * 0 is a valid GPIO so initialize all GPIO-s to negative value
+ * to indicate that external control won't be used for this regulator.
+ */
+ for (i = 0; i < s2mps11->rdev_num; i++)
+ s2mps11->ext_control_gpio[i] = -EINVAL;
+
if (!iodev->dev->of_node) {
- if (pdata) {
+ if (iodev->pdata) {
+ pdata = iodev->pdata;
goto common_reg;
} else {
dev_err(pdev->dev.parent,
@@ -614,15 +686,9 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
for (i = 0; i < s2mps11->rdev_num; i++)
rdata[i].name = regulators[i].name;
- reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators");
- if (!reg_np) {
- dev_err(&pdev->dev, "could not find regulators sub-node\n");
- ret = -EINVAL;
+ ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, dev_type);
+ if (ret)
goto out;
- }
-
- of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
- of_node_put(reg_np);
common_reg:
platform_set_drvdata(pdev, s2mps11);
@@ -630,16 +696,18 @@ common_reg:
config.dev = &pdev->dev;
config.regmap = iodev->regmap_pmic;
config.driver_data = s2mps11;
+ config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
for (i = 0; i < s2mps11->rdev_num; i++) {
struct regulator_dev *regulator;
- if (!reg_np) {
+ if (pdata) {
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].reg_node;
} else {
config.init_data = rdata[i].init_data;
config.of_node = rdata[i].of_node;
}
+ config.ena_gpio = s2mps11->ext_control_gpio[i];
regulator = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
@@ -649,6 +717,17 @@ common_reg:
i);
goto out;
}
+
+ if (gpio_is_valid(s2mps11->ext_control_gpio[i])) {
+ ret = s2mps14_pmic_enable_ext_control(s2mps11,
+ regulator);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "failed to enable GPIO control over %s: %d\n",
+ regulator->desc->name, ret);
+ goto out;
+ }
+ }
}
out:
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 92f19a005dc3..c79af943a5c0 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -28,7 +28,6 @@ struct s5m8767_info {
struct device *dev;
struct sec_pmic_dev *iodev;
int num_regulators;
- struct regulator_dev **rdev;
struct sec_opmode_data *opmode;
int ramp_delay;
@@ -529,16 +528,6 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
return 0;
}
-static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev,
- struct sec_regulator_data *rdata,
- struct device_node *reg_np)
-{
- rdata->ext_control_gpio = of_get_named_gpio(reg_np,
- "s5m8767,pmic-ext-control-gpios", 0);
- if (!gpio_is_valid(rdata->ext_control_gpio))
- rdata->ext_control_gpio = 0;
-}
-
static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
struct sec_platform_data *pdata)
{
@@ -587,7 +576,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
continue;
}
- s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np);
+ rdata->ext_control_gpio = of_get_named_gpio(reg_np,
+ "s5m8767,pmic-ext-control-gpios", 0);
rdata->id = i;
rdata->initdata = of_get_regulator_init_data(
@@ -695,7 +685,6 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct sec_platform_data *pdata = iodev->pdata;
struct regulator_config config = { };
- struct regulator_dev **rdev;
struct s5m8767_info *s5m8767;
int i, ret, size, buck_init;
@@ -737,11 +726,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
return -ENOMEM;
size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2);
- s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
- if (!s5m8767->rdev)
- return -ENOMEM;
- rdev = s5m8767->rdev;
s5m8767->dev = &pdev->dev;
s5m8767->iodev = iodev;
s5m8767->num_regulators = pdata->num_regulators;
@@ -938,6 +923,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
const struct sec_voltage_desc *desc;
int id = pdata->regulators[i].id;
int enable_reg, enable_val;
+ struct regulator_dev *rdev;
desc = reg_voltage_map[id];
if (desc) {
@@ -964,26 +950,27 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
config.driver_data = s5m8767;
config.regmap = iodev->regmap_pmic;
config.of_node = pdata->regulators[i].reg_node;
- config.ena_gpio = config.ena_gpio_flags = 0;
- if (pdata->regulators[i].ext_control_gpio)
+ config.ena_gpio = -EINVAL;
+ config.ena_gpio_flags = 0;
+ if (gpio_is_valid(pdata->regulators[i].ext_control_gpio))
s5m8767_regulator_config_ext_control(s5m8767,
&pdata->regulators[i], &config);
- rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
+ rdev = devm_regulator_register(&pdev->dev, &regulators[id],
&config);
- if (IS_ERR(rdev[i])) {
- ret = PTR_ERR(rdev[i]);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
dev_err(s5m8767->dev, "regulator init failed for %d\n",
id);
return ret;
}
- if (pdata->regulators[i].ext_control_gpio) {
- ret = s5m8767_enable_ext_control(s5m8767, rdev[i]);
+ if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) {
+ ret = s5m8767_enable_ext_control(s5m8767, rdev);
if (ret < 0) {
dev_err(s5m8767->dev,
"failed to enable gpio control over %s: %d\n",
- rdev[i]->desc->name, ret);
+ rdev->desc->name, ret);
return ret;
}
}
diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c
index e367af1c5f9d..5ea78df449f8 100644
--- a/drivers/regulator/st-pwm.c
+++ b/drivers/regulator/st-pwm.c
@@ -118,7 +118,7 @@ static const struct st_pwm_regulator_pdata b2105_info = {
.duty_cycle_table = b2105_duty_cycle_table,
};
-static struct of_device_id st_pwm_of_match[] = {
+static const struct of_device_id st_pwm_of_match[] = {
{ .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
{ },
};
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index 2e92ef68574d..2064b3fd45f7 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -17,6 +17,7 @@
*/
#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
@@ -28,49 +29,216 @@
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/tps65090.h>
+#define MAX_CTRL_READ_TRIES 5
+#define MAX_FET_ENABLE_TRIES 1000
+
+#define CTRL_EN_BIT 0 /* Regulator enable bit, active high */
+#define CTRL_WT_BIT 2 /* Regulator wait time 0 bit */
+#define CTRL_PG_BIT 4 /* Regulator power good bit, 1=good */
+#define CTRL_TO_BIT 7 /* Regulator timeout bit, 1=wait */
+
+#define MAX_OVERCURRENT_WAIT 3 /* Overcurrent wait must be <= this */
+
+/**
+ * struct tps65090_regulator - Per-regulator data for a tps65090 regulator
+ *
+ * @dev: Pointer to our device.
+ * @desc: The struct regulator_desc for the regulator.
+ * @rdev: The struct regulator_dev for the regulator.
+ * @overcurrent_wait_valid: True if overcurrent_wait is valid.
+ * @overcurrent_wait: For FETs, the value to put in the WTFET bitfield.
+ */
+
struct tps65090_regulator {
struct device *dev;
struct regulator_desc *desc;
struct regulator_dev *rdev;
+ bool overcurrent_wait_valid;
+ int overcurrent_wait;
};
static struct regulator_ops tps65090_ext_control_ops = {
};
-static struct regulator_ops tps65090_reg_contol_ops = {
+/**
+ * tps65090_reg_set_overcurrent_wait - Setup overcurrent wait
+ *
+ * This will set the overcurrent wait time based on what's in the regulator
+ * info.
+ *
+ * @ri: Overall regulator data
+ * @rdev: Regulator device
+ *
+ * Return: 0 if no error, non-zero if there was an error writing the register.
+ */
+static int tps65090_reg_set_overcurrent_wait(struct tps65090_regulator *ri,
+ struct regulator_dev *rdev)
+{
+ int ret;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ MAX_OVERCURRENT_WAIT << CTRL_WT_BIT,
+ ri->overcurrent_wait << CTRL_WT_BIT);
+ if (ret) {
+ dev_err(&rdev->dev, "Error updating overcurrent wait %#x\n",
+ rdev->desc->enable_reg);
+ }
+
+ return ret;
+}
+
+/**
+ * tps65090_try_enable_fet - Try to enable a FET
+ *
+ * @rdev: Regulator device
+ *
+ * Return: 0 if ok, -ENOTRECOVERABLE if the FET power good bit did not get
+ * set, or some other -ve value if another error occurred (e.g. i2c error)
+ */
+static int tps65090_try_enable_fet(struct regulator_dev *rdev)
+{
+ unsigned int control;
+ int ret, i;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask,
+ rdev->desc->enable_mask);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "Error in updating reg %#x\n",
+ rdev->desc->enable_reg);
+ return ret;
+ }
+
+ for (i = 0; i < MAX_CTRL_READ_TRIES; i++) {
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg,
+ &control);
+ if (ret < 0)
+ return ret;
+
+ if (!(control & BIT(CTRL_TO_BIT)))
+ break;
+
+ usleep_range(1000, 1500);
+ }
+ if (!(control & BIT(CTRL_PG_BIT)))
+ return -ENOTRECOVERABLE;
+
+ return 0;
+}
+
+/**
+ * tps65090_fet_enable - Enable a FET, trying a few times if it fails
+ *
+ * Some versions of the tps65090 have issues when turning on the FETs.
+ * This function goes through several steps to ensure the best chance of the
+ * FET going on. Specifically:
+ * - We'll make sure that we bump the "overcurrent wait" to the maximum, which
+ * increases the chances that we'll turn on properly.
+ * - We'll retry turning the FET on multiple times (turning off in between).
+ *
+ * @rdev: Regulator device
+ *
+ * Return: 0 if ok, non-zero if it fails.
+ */
+static int tps65090_fet_enable(struct regulator_dev *rdev)
+{
+ int ret, tries;
+
+ /*
+ * Try enabling multiple times until we succeed since sometimes the
+ * first try times out.
+ */
+ tries = 0;
+ while (true) {
+ ret = tps65090_try_enable_fet(rdev);
+ if (!ret)
+ break;
+ if (ret != -ENOTRECOVERABLE || tries == MAX_FET_ENABLE_TRIES)
+ goto err;
+
+ /* Try turning the FET off (and then on again) */
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, 0);
+ if (ret)
+ goto err;
+
+ tries++;
+ }
+
+ if (tries)
+ dev_warn(&rdev->dev, "reg %#x enable ok after %d tries\n",
+ rdev->desc->enable_reg, tries);
+
+ return 0;
+err:
+ dev_warn(&rdev->dev, "reg %#x enable failed\n", rdev->desc->enable_reg);
+ WARN_ON(1);
+
+ return ret;
+}
+
+static struct regulator_ops tps65090_reg_control_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
+static struct regulator_ops tps65090_fet_control_ops = {
+ .enable = tps65090_fet_enable,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
static struct regulator_ops tps65090_ldo_ops = {
};
-#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops) \
+#define tps65090_REG_DESC(_id, _sname, _en_reg, _en_bits, _ops) \
{ \
.name = "TPS65090_RAILS"#_id, \
.supply_name = _sname, \
.id = TPS65090_REGULATOR_##_id, \
.ops = &_ops, \
.enable_reg = _en_reg, \
- .enable_mask = BIT(0), \
+ .enable_val = _en_bits, \
+ .enable_mask = _en_bits, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}
static struct regulator_desc tps65090_regulator_desc[] = {
- tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, tps65090_reg_contol_ops),
- tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, tps65090_reg_contol_ops),
- tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, tps65090_reg_contol_ops),
- tps65090_REG_DESC(FET1, "infet1", 0x0F, tps65090_reg_contol_ops),
- tps65090_REG_DESC(FET2, "infet2", 0x10, tps65090_reg_contol_ops),
- tps65090_REG_DESC(FET3, "infet3", 0x11, tps65090_reg_contol_ops),
- tps65090_REG_DESC(FET4, "infet4", 0x12, tps65090_reg_contol_ops),
- tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops),
- tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops),
- tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops),
- tps65090_REG_DESC(LDO1, "vsys-l1", 0, tps65090_ldo_ops),
- tps65090_REG_DESC(LDO2, "vsys-l2", 0, tps65090_ldo_ops),
+ tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, BIT(CTRL_EN_BIT),
+ tps65090_reg_control_ops),
+ tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, BIT(CTRL_EN_BIT),
+ tps65090_reg_control_ops),
+ tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, BIT(CTRL_EN_BIT),
+ tps65090_reg_control_ops),
+
+ tps65090_REG_DESC(FET1, "infet1", 0x0F,
+ BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+ tps65090_fet_control_ops),
+ tps65090_REG_DESC(FET2, "infet2", 0x10,
+ BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+ tps65090_fet_control_ops),
+ tps65090_REG_DESC(FET3, "infet3", 0x11,
+ BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+ tps65090_fet_control_ops),
+ tps65090_REG_DESC(FET4, "infet4", 0x12,
+ BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+ tps65090_fet_control_ops),
+ tps65090_REG_DESC(FET5, "infet5", 0x13,
+ BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+ tps65090_fet_control_ops),
+ tps65090_REG_DESC(FET6, "infet6", 0x14,
+ BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+ tps65090_fet_control_ops),
+ tps65090_REG_DESC(FET7, "infet7", 0x15,
+ BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
+ tps65090_fet_control_ops),
+
+ tps65090_REG_DESC(LDO1, "vsys-l1", 0, 0,
+ tps65090_ldo_ops),
+ tps65090_REG_DESC(LDO2, "vsys-l2", 0, 0,
+ tps65090_ldo_ops),
};
static inline bool is_dcdc(int id)
@@ -209,6 +377,11 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
rpdata->gpio = of_get_named_gpio(np,
"dcdc-ext-control-gpios", 0);
+ if (of_property_read_u32(tps65090_matches[idx].of_node,
+ "ti,overcurrent-wait",
+ &rpdata->overcurrent_wait) == 0)
+ rpdata->overcurrent_wait_valid = true;
+
tps65090_pdata->reg_pdata[idx] = rpdata;
}
return tps65090_pdata;
@@ -258,6 +431,11 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
ri = &pmic[num];
ri->dev = &pdev->dev;
ri->desc = &tps65090_regulator_desc[num];
+ if (tps_pdata) {
+ ri->overcurrent_wait_valid =
+ tps_pdata->overcurrent_wait_valid;
+ ri->overcurrent_wait = tps_pdata->overcurrent_wait;
+ }
/*
* TPS5090 DCDC support the control from external digital input.
@@ -299,6 +477,12 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
}
ri->rdev = rdev;
+ if (ri->overcurrent_wait_valid) {
+ ret = tps65090_reg_set_overcurrent_wait(ri, rdev);
+ if (ret < 0)
+ return ret;
+ }
+
/* Enable external control if it is require */
if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data &&
tps_pdata->enable_ext_control) {
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index 10b78d2b766a..f7ed20a5a8b9 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -134,6 +134,7 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = tps65217_pmic_set_voltage_sel,
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
};
static const struct regulator_desc regulators[] = {
@@ -257,9 +258,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
pdev->name);
return PTR_ERR(rdev);
}
-
- /* Save regulator for cleanup */
- tps->rdev[i] = rdev;
}
return 0;
}
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
index cec72fa71d1d..69b4b7750410 100644
--- a/drivers/regulator/tps65218-regulator.c
+++ b/drivers/regulator/tps65218-regulator.c
@@ -27,12 +27,10 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65218.h>
-static unsigned int tps65218_ramp_delay = 4000;
-
enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, _t, \
- _lr, _nlr) \
+ _lr, _nlr, _delay) \
{ \
.name = _name, \
.id = _id, \
@@ -47,6 +45,7 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
.volt_table = _t, \
.linear_ranges = _lr, \
.n_linear_ranges = _nlr, \
+ .ramp_delay = _delay, \
} \
#define TPS65218_INFO(_id, _nm, _min, _max) \
@@ -152,22 +151,6 @@ static int tps65218_pmic_disable(struct regulator_dev *dev)
dev->desc->enable_mask, TPS65218_PROTECT_L1);
}
-static int tps65218_set_voltage_time_sel(struct regulator_dev *rdev,
- unsigned int old_selector, unsigned int new_selector)
-{
- int old_uv, new_uv;
-
- old_uv = regulator_list_voltage_linear_range(rdev, old_selector);
- if (old_uv < 0)
- return old_uv;
-
- new_uv = regulator_list_voltage_linear_range(rdev, new_selector);
- if (new_uv < 0)
- return new_uv;
-
- return DIV_ROUND_UP(abs(old_uv - new_uv), tps65218_ramp_delay);
-}
-
/* Operations permitted on DCDC1, DCDC2 */
static struct regulator_ops tps65218_dcdc12_ops = {
.is_enabled = regulator_is_enabled_regmap,
@@ -177,7 +160,7 @@ static struct regulator_ops tps65218_dcdc12_ops = {
.set_voltage_sel = tps65218_pmic_set_voltage_sel,
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
- .set_voltage_time_sel = tps65218_set_voltage_time_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
};
/* Operations permitted on DCDC3, DCDC4 and LDO1 */
@@ -203,33 +186,33 @@ static const struct regulator_desc regulators[] = {
TPS65218_REG_CONTROL_DCDC1,
TPS65218_CONTROL_DCDC1_MASK,
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, NULL,
- dcdc1_dcdc2_ranges, 2),
+ dcdc1_dcdc2_ranges, 2, 4000),
TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64,
TPS65218_REG_CONTROL_DCDC2,
TPS65218_CONTROL_DCDC2_MASK,
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, NULL,
- dcdc1_dcdc2_ranges, 2),
+ dcdc1_dcdc2_ranges, 2, 4000),
TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops,
64, TPS65218_REG_CONTROL_DCDC3,
TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC3_EN, NULL,
- ldo1_dcdc3_ranges, 2),
+ ldo1_dcdc3_ranges, 2, 0),
TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops,
53, TPS65218_REG_CONTROL_DCDC4,
TPS65218_CONTROL_DCDC4_MASK,
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, NULL,
- dcdc4_ranges, 2),
+ dcdc4_ranges, 2, 0),
TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops,
1, -1, -1, TPS65218_REG_ENABLE1,
- TPS65218_ENABLE1_DC5_EN, NULL, NULL, 0),
+ TPS65218_ENABLE1_DC5_EN, NULL, NULL, 0, 0),
TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops,
1, -1, -1, TPS65218_REG_ENABLE1,
- TPS65218_ENABLE1_DC6_EN, NULL, NULL, 0),
+ TPS65218_ENABLE1_DC6_EN, NULL, NULL, 0, 0),
TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64,
TPS65218_REG_CONTROL_DCDC4,
TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
TPS65218_ENABLE2_LDO1_EN, NULL, ldo1_dcdc3_ranges,
- 2),
+ 2, 0),
};
static int tps65218_regulator_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index 32f38a63d944..0a3bb3aecd97 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -63,12 +63,7 @@ struct tps6586x_regulator {
int enable_reg[2];
};
-static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
-{
- return rdev_get_dev(rdev)->parent;
-}
-
-static struct regulator_ops tps6586x_regulator_ops = {
+static struct regulator_ops tps6586x_rw_regulator_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -79,6 +74,16 @@ static struct regulator_ops tps6586x_regulator_ops = {
.disable = regulator_disable_regmap,
};
+static struct regulator_ops tps6586x_ro_regulator_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+};
+
static struct regulator_ops tps6586x_sys_regulator_ops = {
};
@@ -106,6 +111,13 @@ static const unsigned int tps6586x_sm2_voltages[] = {
4200000, 4250000, 4300000, 4350000, 4400000, 4450000, 4500000, 4550000,
};
+static int tps658640_sm2_voltages[] = {
+ 2150000, 2200000, 2250000, 2300000, 2350000, 2400000, 2450000, 2500000,
+ 2550000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000, 2900000,
+ 2950000, 3000000, 3050000, 3100000, 3150000, 3200000, 3250000, 3300000,
+ 3350000, 3400000, 3450000, 3500000, 3550000, 3600000, 3650000, 3700000,
+};
+
static const unsigned int tps658643_sm2_voltages[] = {
1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000,
1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000,
@@ -120,12 +132,16 @@ static const unsigned int tps6586x_dvm_voltages[] = {
1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
};
-#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \
+static int tps658640_rtc_voltages[] = {
+ 2500000, 2850000, 3100000, 3300000,
+};
+
+#define TPS6586X_REGULATOR(_id, _ops, _pin_name, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
.desc = { \
.supply_name = _pin_name, \
.name = "REG-" #_id, \
- .ops = &tps6586x_regulator_ops, \
+ .ops = &tps6586x_## _ops ## _regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = TPS6586X_ID_##_id, \
.n_voltages = ARRAY_SIZE(vdata##_voltages), \
@@ -146,14 +162,21 @@ static const unsigned int tps6586x_dvm_voltages[] = {
#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
{ \
- TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
+ TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits, \
+ ereg0, ebit0, ereg1, ebit1, 0, 0) \
+}
+
+#define TPS6586X_FIXED_LDO(_id, _pname, vdata, vreg, shift, nbits, \
+ ereg0, ebit0, ereg1, ebit1) \
+{ \
+ TPS6586X_REGULATOR(_id, ro, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, 0, 0) \
}
#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
{ \
- TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
+ TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
}
@@ -207,6 +230,26 @@ static struct tps6586x_regulator tps658623_regulator[] = {
END, 7),
};
+static struct tps6586x_regulator tps658640_regulator[] = {
+ TPS6586X_LDO(LDO_3, "vinldo23", tps6586x_ldo0, SUPPLYV4, 0, 3,
+ ENC, 2, END, 2),
+ TPS6586X_LDO(LDO_5, "REG-SYS", tps6586x_ldo0, SUPPLYV6, 0, 3,
+ ENE, 6, ENE, 6),
+ TPS6586X_LDO(LDO_6, "vinldo678", tps6586x_ldo0, SUPPLYV3, 0, 3,
+ ENC, 4, END, 4),
+ TPS6586X_LDO(LDO_7, "vinldo678", tps6586x_ldo0, SUPPLYV3, 3, 3,
+ ENC, 5, END, 5),
+ TPS6586X_LDO(LDO_8, "vinldo678", tps6586x_ldo0, SUPPLYV2, 5, 3,
+ ENC, 6, END, 6),
+ TPS6586X_LDO(LDO_9, "vinldo9", tps6586x_ldo0, SUPPLYV6, 3, 3,
+ ENE, 7, ENE, 7),
+ TPS6586X_LDO(SM_2, "vin-sm2", tps658640_sm2, SUPPLYV2, 0, 5,
+ ENC, 7, END, 7),
+
+ TPS6586X_FIXED_LDO(LDO_RTC, "REG-SYS", tps658640_rtc, SUPPLYV4, 3, 2,
+ V4, 7, V4, 7),
+};
+
static struct tps6586x_regulator tps658643_regulator[] = {
TPS6586X_LDO(SM_2, "vin-sm2", tps658643_sm2, SUPPLYV2, 0, 5, ENC, 7,
END, 7),
@@ -295,6 +338,11 @@ static struct tps6586x_regulator *find_regulator_info(int id, int version)
table = tps658623_regulator;
num = ARRAY_SIZE(tps658623_regulator);
break;
+ case TPS658640:
+ case TPS658640v2:
+ table = tps658640_regulator;
+ num = ARRAY_SIZE(tps658640_regulator);
+ break;
case TPS658643:
table = tps658643_regulator;
num = ARRAY_SIZE(tps658643_regulator);
diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c
index 2863428813e4..02e7267ccf92 100644
--- a/drivers/regulator/vexpress.c
+++ b/drivers/regulator/vexpress.c
@@ -98,7 +98,7 @@ static int vexpress_regulator_probe(struct platform_device *pdev)
return 0;
}
-static struct of_device_id vexpress_regulator_of_match[] = {
+static const struct of_device_id vexpress_regulator_of_match[] = {
{ .compatible = "arm,vexpress-volt", },
{ }
};
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h
index 5cf8b91ce996..6d9371f88875 100644
--- a/include/linux/mfd/arizona/core.h
+++ b/include/linux/mfd/arizona/core.h
@@ -124,4 +124,7 @@ int wm5102_patch(struct arizona *arizona);
int wm5110_patch(struct arizona *arizona);
int wm8997_patch(struct arizona *arizona);
+extern int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
+ bool mandatory);
+
#endif
diff --git a/include/linux/mfd/bcm590xx.h b/include/linux/mfd/bcm590xx.h
index 434df2d4e587..267aedee1c7a 100644
--- a/include/linux/mfd/bcm590xx.h
+++ b/include/linux/mfd/bcm590xx.h
@@ -19,12 +19,15 @@
#include <linux/regmap.h>
/* max register address */
-#define BCM590XX_MAX_REGISTER 0xe7
+#define BCM590XX_MAX_REGISTER_PRI 0xe7
+#define BCM590XX_MAX_REGISTER_SEC 0xf0
struct bcm590xx {
struct device *dev;
- struct i2c_client *i2c_client;
- struct regmap *regmap;
+ struct i2c_client *i2c_pri;
+ struct i2c_client *i2c_sec;
+ struct regmap *regmap_pri;
+ struct regmap *regmap_sec;
unsigned int id;
};
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index bdba8c61207b..f543de91ce19 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -63,7 +63,7 @@ struct mfd_cell {
/* A list of regulator supplies that should be mapped to the MFD
* device rather than the child device when requested
*/
- const char **parent_supplies;
+ const char * const *parent_supplies;
int num_parent_supplies;
};
diff --git a/include/linux/mfd/samsung/s2mps14.h b/include/linux/mfd/samsung/s2mps14.h
index 4b449b8ac548..900cd7a04314 100644
--- a/include/linux/mfd/samsung/s2mps14.h
+++ b/include/linux/mfd/samsung/s2mps14.h
@@ -148,6 +148,8 @@ enum s2mps14_regulators {
#define S2MPS14_ENABLE_SHIFT 6
/* On/Off controlled by PWREN */
#define S2MPS14_ENABLE_SUSPEND (0x01 << S2MPS14_ENABLE_SHIFT)
+/* On/Off controlled by LDO10EN or EMMCEN */
+#define S2MPS14_ENABLE_EXT_CONTROL (0x00 << S2MPS14_ENABLE_SHIFT)
#define S2MPS14_LDO_N_VOLTAGES (S2MPS14_LDO_VSEL_MASK + 1)
#define S2MPS14_BUCK_N_VOLTAGES (S2MPS14_BUCK_VSEL_MASK + 1)
diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h
index 3f43069413e7..0bf2708df150 100644
--- a/include/linux/mfd/tps65090.h
+++ b/include/linux/mfd/tps65090.h
@@ -64,6 +64,20 @@ enum {
TPS65090_REGULATOR_MAX,
};
+/* Register addresses */
+#define TPS65090_REG_INTR_STS 0x00
+#define TPS65090_REG_INTR_STS2 0x01
+#define TPS65090_REG_INTR_MASK 0x02
+#define TPS65090_REG_INTR_MASK2 0x03
+#define TPS65090_REG_CG_CTRL0 0x04
+#define TPS65090_REG_CG_CTRL1 0x05
+#define TPS65090_REG_CG_CTRL2 0x06
+#define TPS65090_REG_CG_CTRL3 0x07
+#define TPS65090_REG_CG_CTRL4 0x08
+#define TPS65090_REG_CG_CTRL5 0x09
+#define TPS65090_REG_CG_STATUS1 0x0a
+#define TPS65090_REG_CG_STATUS2 0x0b
+
struct tps65090 {
struct device *dev;
struct regmap *rmap;
@@ -78,11 +92,16 @@ struct tps65090 {
* DCDC1, DCDC2 and DCDC3.
* @gpio: Gpio number if external control is enabled and controlled through
* gpio.
+ * @overcurrent_wait_valid: True if the overcurrent_wait should be applied.
+ * @overcurrent_wait: Value to set as the overcurrent wait time. This is the
+ * actual bitfield value, not a time in ms (valid value are 0 - 3).
*/
struct tps65090_regulator_plat_data {
struct regulator_init_data *reg_init_data;
bool enable_ext_control;
int gpio;
+ bool overcurrent_wait_valid;
+ int overcurrent_wait;
};
struct tps65090_platform_data {
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index 54b5458ec084..95d6938737fd 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -254,7 +254,6 @@ struct tps65217 {
struct tps65217_board *pdata;
unsigned long id;
struct regulator_desc desc[TPS65217_NUM_REGULATOR];
- struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
struct regmap *regmap;
};
diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h
index cbecec2e353a..96187ed9f9bb 100644
--- a/include/linux/mfd/tps6586x.h
+++ b/include/linux/mfd/tps6586x.h
@@ -17,6 +17,8 @@
#define TPS658621A 0x15
#define TPS658621CD 0x2c
#define TPS658623 0x1b
+#define TPS658640 0x01
+#define TPS658640v2 0x02
#define TPS658643 0x03
enum {
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 1a4a8c157b31..a2d9d81038d1 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -151,11 +151,13 @@ int regulator_register_supply_alias(struct device *dev, const char *id,
const char *alias_id);
void regulator_unregister_supply_alias(struct device *dev, const char *id);
-int regulator_bulk_register_supply_alias(struct device *dev, const char **id,
+int regulator_bulk_register_supply_alias(struct device *dev,
+ const char *const *id,
struct device *alias_dev,
- const char **alias_id, int num_id);
+ const char *const *alias_id,
+ int num_id);
void regulator_bulk_unregister_supply_alias(struct device *dev,
- const char **id, int num_id);
+ const char * const *id, int num_id);
int devm_regulator_register_supply_alias(struct device *dev, const char *id,
struct device *alias_dev,
@@ -164,12 +166,12 @@ void devm_regulator_unregister_supply_alias(struct device *dev,
const char *id);
int devm_regulator_bulk_register_supply_alias(struct device *dev,
- const char **id,
+ const char *const *id,
struct device *alias_dev,
- const char **alias_id,
+ const char *const *alias_id,
int num_id);
void devm_regulator_bulk_unregister_supply_alias(struct device *dev,
- const char **id,
+ const char *const *id,
int num_id);
/* regulator output control and status */
@@ -290,17 +292,17 @@ static inline void regulator_unregister_supply_alias(struct device *dev,
}
static inline int regulator_bulk_register_supply_alias(struct device *dev,
- const char **id,
- struct device *alias_dev,
- const char **alias_id,
- int num_id)
+ const char *const *id,
+ struct device *alias_dev,
+ const char * const *alias_id,
+ int num_id)
{
return 0;
}
static inline void regulator_bulk_unregister_supply_alias(struct device *dev,
- const char **id,
- int num_id)
+ const char * const *id,
+ int num_id)
{
}
@@ -317,15 +319,17 @@ static inline void devm_regulator_unregister_supply_alias(struct device *dev,
{
}
-static inline int devm_regulator_bulk_register_supply_alias(
- struct device *dev, const char **id, struct device *alias_dev,
- const char **alias_id, int num_id)
+static inline int devm_regulator_bulk_register_supply_alias(struct device *dev,
+ const char *const *id,
+ struct device *alias_dev,
+ const char *const *alias_id,
+ int num_id)
{
return 0;
}
static inline void devm_regulator_bulk_unregister_supply_alias(
- struct device *dev, const char **id, int num_id)
+ struct device *dev, const char *const *id, int num_id)
{
}
@@ -397,6 +401,12 @@ static inline int regulator_set_voltage(struct regulator *regulator,
return 0;
}
+static inline int regulator_set_voltage_time(struct regulator *regulator,
+ int old_uV, int new_uV)
+{
+ return 0;
+}
+
static inline int regulator_get_voltage(struct regulator *regulator)
{
return -EINVAL;