summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/regulator/anatop-regulator.txt1
-rw-r--r--Documentation/devicetree/bindings/regulator/lm363x-regulator.txt78
-rw-r--r--Documentation/devicetree/bindings/regulator/pfuze100.txt8
-rw-r--r--Documentation/devicetree/bindings/regulator/regulator.txt3
-rw-r--r--Documentation/devicetree/bindings/regulator/tps65132-regulator.txt46
-rw-r--r--Documentation/devicetree/bindings/regulator/vctrl.txt49
-rw-r--r--MAINTAINERS2
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410-module.c8
-rw-r--r--drivers/regulator/Kconfig40
-rw-r--r--drivers/regulator/Makefile6
-rw-r--r--drivers/regulator/anatop-regulator.c19
-rw-r--r--drivers/regulator/arizona-ldo1.c140
-rw-r--r--drivers/regulator/arizona-micsupp.c119
-rw-r--r--drivers/regulator/bd9571mwv-regulator.c178
-rw-r--r--drivers/regulator/core.c37
-rw-r--r--drivers/regulator/helpers.c36
-rw-r--r--drivers/regulator/hi655x-regulator.c7
-rw-r--r--drivers/regulator/internal.h2
-rw-r--r--drivers/regulator/lm363x-regulator.c4
-rw-r--r--drivers/regulator/ltc3589.c25
-rw-r--r--drivers/regulator/ltc3676.c7
-rw-r--r--drivers/regulator/max1586.c4
-rw-r--r--drivers/regulator/max77693-regulator.c2
-rw-r--r--drivers/regulator/max8660.c4
-rw-r--r--drivers/regulator/of_regulator.c4
-rw-r--r--drivers/regulator/pfuze100-regulator.c24
-rw-r--r--drivers/regulator/rk808-regulator.c2
-rw-r--r--drivers/regulator/s2mpa01.c14
-rw-r--r--drivers/regulator/s2mps11.c16
-rw-r--r--drivers/regulator/s5m8767.c4
-rw-r--r--drivers/regulator/tps65023-regulator.c3
-rw-r--r--drivers/regulator/tps65132-regulator.c284
-rw-r--r--drivers/regulator/twl6030-regulator.c2
-rw-r--r--drivers/regulator/vctrl-regulator.c546
-rw-r--r--include/linux/mfd/arizona/pdata.h7
-rw-r--r--include/linux/platform_data/isl9305.h2
-rw-r--r--include/linux/regulator/arizona-ldo1.h24
-rw-r--r--include/linux/regulator/arizona-micsupp.h21
-rw-r--r--include/linux/regulator/consumer.h1
-rw-r--r--include/linux/regulator/driver.h18
-rw-r--r--include/linux/regulator/machine.h3
-rw-r--r--include/linux/regulator/pfuze100.h1
42 files changed, 1626 insertions, 175 deletions
diff --git a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
index 1d58c8cfdbc0..a3106c72fbea 100644
--- a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
@@ -2,6 +2,7 @@ Anatop Voltage regulators
Required properties:
- compatible: Must be "fsl,anatop-regulator"
+- regulator-name: A string used as a descriptive name for regulator outputs
- anatop-reg-offset: Anatop MFD register offset
- anatop-vol-bit-shift: Bit shift for the register
- anatop-vol-bit-width: Number of bits used in the register
diff --git a/Documentation/devicetree/bindings/regulator/lm363x-regulator.txt b/Documentation/devicetree/bindings/regulator/lm363x-regulator.txt
index 8f14df9d1205..cc5a6151d85f 100644
--- a/Documentation/devicetree/bindings/regulator/lm363x-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/lm363x-regulator.txt
@@ -8,8 +8,8 @@ Required property:
Optional properties:
LM3632 has external enable pins for two LDOs.
- - ti,lcm-en1-gpio: A GPIO specifier for Vpos control pin.
- - ti,lcm-en2-gpio: A GPIO specifier for Vneg control pin.
+ - enable-gpios: Two GPIO specifiers for Vpos and Vneg control pins.
+ The first entry is Vpos, the second is Vneg enable pin.
Child nodes:
LM3631
@@ -30,5 +30,79 @@ Child nodes:
Examples: Please refer to ti-lmu dt-bindings [2].
+lm3631@29 {
+ compatible = "ti,lm3631";
+ reg = <0x29>;
+
+ regulators {
+ compatible = "ti,lm363x-regulator";
+
+ vboost {
+ regulator-name = "lcd_boost";
+ regulator-min-microvolt = <4500000>;
+ regulator-max-microvolt = <6350000>;
+ regulator-always-on;
+ };
+
+ vcont {
+ regulator-name = "lcd_vcont";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ voref {
+ regulator-name = "lcd_voref";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ };
+
+ vpos {
+ regulator-name = "lcd_vpos";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ regulator-boot-on;
+ };
+
+ vneg {
+ regulator-name = "lcd_vneg";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ regulator-boot-on;
+ };
+ };
+};
+
+lm3632@11 {
+ compatible = "ti,lm3632";
+ reg = <0x11>;
+
+ regulators {
+ compatible = "ti,lm363x-regulator";
+
+ /* GPIO1_16 for Vpos, GPIO1_28 is for Vneg */
+ enable-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>,
+ <&gpio1 28 GPIO_ACTIVE_HIGH>;
+
+ vboost {
+ regulator-name = "lcd_boost";
+ regulator-min-microvolt = <4500000>;
+ regulator-max-microvolt = <6400000>;
+ regulator-always-on;
+ };
+
+ vpos {
+ regulator-name = "lcd_vpos";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ };
+
+ vneg {
+ regulator-name = "lcd_vneg";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ };
+ };
+};
+
[1] ../regulator/regulator.txt
[2] ../mfd/ti-lmu.txt
diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt
index 9b40db88f637..444c47831a40 100644
--- a/Documentation/devicetree/bindings/regulator/pfuze100.txt
+++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt
@@ -13,7 +13,7 @@ Required child node:
--PFUZE100
sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6
--PFUZE200
- sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6
+ sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6,coin
--PFUZE3000
sw1a,sw1b,sw2,sw3,swbst,vsnvs,vrefddr,vldo1,vldo2,vccsd,v33,vldo3,vldo4
@@ -205,6 +205,12 @@ Example 2: PFUZE200
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
+
+ coin_reg: coin {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index 6ab5aef619d9..d18edb075e1c 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -21,6 +21,9 @@ Optional properties:
design requires. This property describes the total system ramp time
required due to the combination of internal ramping of the regulator itself,
and board design issues such as trace capacitance and load on the supply.
+- regulator-settling-time-us: Settling time, in microseconds, for voltage
+ change if regulator have the constant time for any level voltage change.
+ This is useful when regulator have exponential voltage change.
- regulator-soft-start: Enable soft start so that voltage ramps slowly
- regulator-state-mem sub-root node for Suspend-to-RAM mode
: suspend to memory, the device goes to sleep, but all data stored in memory,
diff --git a/Documentation/devicetree/bindings/regulator/tps65132-regulator.txt b/Documentation/devicetree/bindings/regulator/tps65132-regulator.txt
new file mode 100644
index 000000000000..3a3505520c69
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/tps65132-regulator.txt
@@ -0,0 +1,46 @@
+TPS65132 regulators
+
+Required properties:
+- compatible: "ti,tps65132"
+- reg: I2C slave address
+
+Optional Subnode:
+Device supports two regulators OUTP and OUTN. A sub node within the
+ device node describe the properties of these regulators. The sub-node
+ names must be as follows:
+ -For regulator outp, the sub node name should be "outp".
+ -For regulator outn, the sub node name should be "outn".
+
+-enable-gpios:(active high, output) Regulators are controlled by the input pins.
+ If it is connected to GPIO through host system then provide the
+ gpio number as per gpio.txt.
+-active-discharge-gpios: (active high, output) Some configurations use delay mechanisms
+ on the enable pin, to keep the regulator enabled for some time after
+ the enable signal goes low. This GPIO is used to actively discharge
+ the delay mechanism. Requires specification of ti,active-discharge-time-us
+-ti,active-discharge-time-us: how long the active discharge gpio should be
+ asserted for during active discharge, in microseconds.
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+ tps65132@3e {
+ compatible = "ti,tps65132";
+ reg = <0x3e>;
+
+ outp {
+ regulator-name = "outp";
+ regulator-boot-on;
+ regulator-always-on;
+ enable-gpios = <&gpio 23 0>;
+ };
+
+ outn {
+ regulator-name = "outn";
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-active-discharge = <0>;
+ enable-gpios = <&gpio 40 0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/vctrl.txt b/Documentation/devicetree/bindings/regulator/vctrl.txt
new file mode 100644
index 000000000000..601328d7fdbb
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/vctrl.txt
@@ -0,0 +1,49 @@
+Bindings for Voltage controlled regulators
+==========================================
+
+Required properties:
+--------------------
+- compatible : must be "vctrl-regulator".
+- regulator-min-microvolt : smallest voltage consumers may set
+- regulator-max-microvolt : largest voltage consumers may set
+- ctrl-supply : The regulator supplying the control voltage.
+- ctrl-voltage-range : an array of two integer values describing the range
+ (min/max) of the control voltage. The values specify
+ the control voltage needed to generate the corresponding
+ regulator-min/max-microvolt output voltage.
+
+Optional properties:
+--------------------
+- ovp-threshold-percent : overvoltage protection (OVP) threshold of the
+ regulator in percent. Some regulators have an OVP
+ circuitry which shuts down the regulator when the
+ actual output voltage deviates beyond a certain
+ margin from the expected value for a given control
+ voltage. On larger voltage decreases this can occur
+ undesiredly since the output voltage does not adjust
+ inmediately to changes in the control voltage. To
+ avoid this situation the vctrl driver breaks down
+ larger voltage decreases into multiple steps, where
+ each step is within the OVP threshold.
+- min-slew-down-rate : Describes how slowly the regulator voltage will decay
+ down in the worst case (lightest expected load).
+ Specified in uV / us (like main regulator ramp rate).
+ This value is required when ovp-threshold-percent is
+ specified.
+
+Example:
+
+ vctrl-reg {
+ compatible = "vctrl-regulator";
+ regulator-name = "vctrl_reg";
+
+ ctrl-supply = <&ctrl_reg>;
+
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+
+ ctrl-voltage-range = <200000 500000>;
+
+ min-slew-down-rate = <225>;
+ ovp-threshold-percent = <16>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 95803b7b61be..c732ba701ae7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13756,12 +13756,14 @@ F: drivers/mfd/cs47l24*
F: drivers/power/supply/wm83*.c
F: drivers/rtc/rtc-wm83*.c
F: drivers/regulator/wm8*.c
+F: drivers/regulator/arizona*
F: drivers/video/backlight/wm83*_bl.c
F: drivers/watchdog/wm83*_wdt.c
F: include/linux/mfd/arizona/
F: include/linux/mfd/wm831x/
F: include/linux/mfd/wm8350/
F: include/linux/mfd/wm8400*
+F: include/linux/regulator/arizona*
F: include/linux/wm97xx.h
F: include/sound/wm????.h
F: sound/soc/codecs/arizona.?
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
index ccc3ab8d58e7..ea5f2169c850 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
@@ -209,7 +209,9 @@ static const struct i2c_board_info wm1277_devs[] = {
};
static struct arizona_pdata wm5102_reva_pdata = {
- .ldoena = S3C64XX_GPN(7),
+ .ldo1 = {
+ .ldoena = S3C64XX_GPN(7),
+ },
.gpio_base = CODEC_GPIO_BASE,
.irq_flags = IRQF_TRIGGER_HIGH,
.micd_pol_gpio = CODEC_GPIO_BASE + 4,
@@ -239,7 +241,9 @@ static struct spi_board_info wm5102_reva_spi_devs[] = {
};
static struct arizona_pdata wm5102_pdata = {
- .ldoena = S3C64XX_GPN(7),
+ .ldo1 = {
+ .ldoena = S3C64XX_GPN(7),
+ },
.gpio_base = CODEC_GPIO_BASE,
.irq_flags = IRQF_TRIGGER_HIGH,
.micd_pol_gpio = CODEC_GPIO_BASE + 2,
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index be06eb29c681..48db87d6dfef 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -125,12 +125,20 @@ config REGULATOR_AB8500
This driver supports the regulators found on the ST-Ericsson mixed
signal AB8500 PMIC
-config REGULATOR_ARIZONA
- tristate "Wolfson Arizona class devices"
+config REGULATOR_ARIZONA_LDO1
+ tristate "Wolfson Arizona class devices LDO1"
depends on MFD_ARIZONA
depends on SND_SOC
help
- Support for the regulators found on Wolfson Arizona class
+ Support for the LDO1 regulators found on Wolfson Arizona class
+ devices.
+
+config REGULATOR_ARIZONA_MICSUPP
+ tristate "Wolfson Arizona class devices MICSUPP"
+ depends on MFD_ARIZONA
+ depends on SND_SOC
+ help
+ Support for the MICSUPP regulators found on Wolfson Arizona class
devices.
config REGULATOR_AS3711
@@ -163,6 +171,17 @@ config REGULATOR_BCM590XX
BCM590xx PMUs. This will enable support for the software
controllable LDO/Switching regulators.
+config REGULATOR_BD9571MWV
+ tristate "ROHM BD9571MWV Regulators"
+ depends on MFD_BD9571MWV
+ help
+ This driver provides support for the voltage regulators on the
+ ROHM BD9571MWV PMIC. This will enable support for the software
+ controllable regulator and voltage sampling units.
+
+ This driver can also be built as a module. If so, the module
+ will be called bd9571mwv-regulator.
+
config REGULATOR_CPCAP
tristate "Motorola CPCAP regulator"
depends on MFD_CPCAP
@@ -788,6 +807,14 @@ config REGULATOR_TPS65090
This driver provides support for the voltage regulators on the
TI TPS65090 PMIC.
+config REGULATOR_TPS65132
+ tristate "TI TPS65132 Dual Output Power regulators"
+ depends on I2C && GPIOLIB
+ select REGMAP_I2C
+ help
+ This driver supports TPS65132 single inductor - dual output
+ power supply specifcally designed for display panels.
+
config REGULATOR_TPS65217
tristate "TI TPS65217 Power regulators"
depends on MFD_TPS65217
@@ -850,6 +877,13 @@ config REGULATOR_TWL4030
This driver supports the voltage regulators provided by
this family of companion chips.
+config REGULATOR_VCTRL
+ tristate "Voltage controlled regulators"
+ depends on OF
+ help
+ This driver provides support for voltage regulators whose output
+ voltage is controlled by the voltage of another regulator.
+
config REGULATOR_VEXPRESS
tristate "Versatile Express regulators"
depends on VEXPRESS_CONFIG
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ef7725e2592a..dc3503fb3e30 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -19,11 +19,13 @@ obj-$(CONFIG_REGULATOR_ACT8865) += act8865-regulator.o
obj-$(CONFIG_REGULATOR_ACT8945A) += act8945a-regulator.o
obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
-obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
+obj-$(CONFIG_REGULATOR_ARIZONA_LDO1) += arizona-ldo1.o
+obj-$(CONFIG_REGULATOR_ARIZONA_MICSUPP) += arizona-micsupp.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_BD9571MWV) += bd9571mwv-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
@@ -105,7 +107,9 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o
+obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index b041f277a38b..7d6478e6a503 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -39,7 +39,6 @@
#define LDO_FET_FULL_ON 0x1f
struct anatop_regulator {
- const char *name;
u32 control_reg;
struct regmap *anatop;
int vol_bit_shift;
@@ -193,13 +192,21 @@ static int anatop_regulator_probe(struct platform_device *pdev)
sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
if (!sreg)
return -ENOMEM;
- sreg->name = of_get_property(np, "regulator-name", NULL);
+
rdesc = &sreg->rdesc;
- rdesc->name = sreg->name;
rdesc->type = REGULATOR_VOLTAGE;
rdesc->owner = THIS_MODULE;
+ of_property_read_string(np, "regulator-name", &rdesc->name);
+ if (!rdesc->name) {
+ dev_err(dev, "failed to get a regulator-name\n");
+ return -EINVAL;
+ }
+
initdata = of_get_regulator_init_data(dev, np, rdesc);
+ if (!initdata)
+ return -ENOMEM;
+
initdata->supply_regulator = "vin";
sreg->initdata = initdata;
@@ -293,9 +300,13 @@ static int anatop_regulator_probe(struct platform_device *pdev)
* a sane default until imx6-cpufreq was probed and changes the
* voltage to the correct value. In this case we set 1.25V.
*/
- if (!sreg->sel && !strcmp(sreg->name, "vddpu"))
+ if (!sreg->sel && !strcmp(rdesc->name, "vddpu"))
sreg->sel = 22;
+ /* set the default voltage of the pcie phy to be 1.100v */
+ if (!sreg->sel && !strcmp(rdesc->name, "vddpcie"))
+ sreg->sel = 0x10;
+
if (!sreg->bypass && !sreg->sel) {
dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n");
return -EINVAL;
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index e76d094591e7..96fddfff5dc4 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -25,13 +25,15 @@
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/regulator/arizona-ldo1.h>
+
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
struct arizona_ldo1 {
struct regulator_dev *regulator;
- struct arizona *arizona;
+ struct regmap *regmap;
struct regulator_consumer_supply supply;
struct regulator_init_data init_data;
@@ -65,7 +67,7 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
unsigned sel)
{
struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev);
- struct regmap *regmap = ldo->arizona->regmap;
+ struct regmap *regmap = ldo->regmap;
unsigned int val;
int ret;
@@ -91,7 +93,7 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev)
{
struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev);
- struct regmap *regmap = ldo->arizona->regmap;
+ struct regmap *regmap = ldo->regmap;
unsigned int val;
int ret;
@@ -186,19 +188,19 @@ static const struct regulator_init_data arizona_ldo1_wm5110 = {
.num_consumer_supplies = 1,
};
-static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
+static int arizona_ldo1_of_get_pdata(struct arizona_ldo1_pdata *pdata,
struct regulator_config *config,
- const struct regulator_desc *desc)
+ const struct regulator_desc *desc,
+ bool *external_dcvdd)
{
- struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_ldo1 *ldo1 = config->driver_data;
- struct device_node *np = arizona->dev->of_node;
+ struct device_node *np = config->dev->of_node;
struct device_node *init_node, *dcvdd_node;
struct regulator_init_data *init_data;
pdata->ldoena = of_get_named_gpio(np, "wlf,ldoena", 0);
if (pdata->ldoena < 0) {
- dev_warn(arizona->dev,
+ dev_warn(config->dev,
"LDOENA GPIO property missing/malformed: %d\n",
pdata->ldoena);
pdata->ldoena = 0;
@@ -212,20 +214,19 @@ static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
if (init_node) {
config->of_node = init_node;
- init_data = of_get_regulator_init_data(arizona->dev, init_node,
+ init_data = of_get_regulator_init_data(config->dev, init_node,
desc);
-
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;
+ *external_dcvdd = true;
- pdata->ldo1 = init_data;
+ pdata->init_data = init_data;
}
} else if (dcvdd_node) {
- arizona->external_dcvdd = true;
+ *external_dcvdd = true;
}
of_node_put(dcvdd_node);
@@ -233,66 +234,40 @@ static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
return 0;
}
-static int arizona_ldo1_probe(struct platform_device *pdev)
+static int arizona_ldo1_common_init(struct platform_device *pdev,
+ struct arizona_ldo1 *ldo1,
+ const struct regulator_desc *desc,
+ struct arizona_ldo1_pdata *pdata,
+ bool *external_dcvdd)
{
- struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
- const struct regulator_desc *desc;
+ struct device *parent_dev = pdev->dev.parent;
struct regulator_config config = { };
- struct arizona_ldo1 *ldo1;
int ret;
- arizona->external_dcvdd = false;
-
- ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
- if (!ldo1)
- return -ENOMEM;
-
- ldo1->arizona = arizona;
-
- /*
- * Since the chip usually supplies itself we provide some
- * default init_data for it. This will be overridden with
- * platform data if provided.
- */
- switch (arizona->type) {
- case WM5102:
- case WM8997:
- case WM8998:
- case WM1814:
- desc = &arizona_ldo1_hc;
- ldo1->init_data = arizona_ldo1_dvfs;
- break;
- case WM5110:
- case WM8280:
- desc = &arizona_ldo1;
- ldo1->init_data = arizona_ldo1_wm5110;
- break;
- default:
- desc = &arizona_ldo1;
- ldo1->init_data = arizona_ldo1_default;
- break;
- }
+ *external_dcvdd = false;
- ldo1->init_data.consumer_supplies = &ldo1->supply;
ldo1->supply.supply = "DCVDD";
- ldo1->supply.dev_name = dev_name(arizona->dev);
+ ldo1->init_data.consumer_supplies = &ldo1->supply;
+ ldo1->supply.dev_name = dev_name(parent_dev);
- config.dev = arizona->dev;
+ config.dev = parent_dev;
config.driver_data = ldo1;
- config.regmap = arizona->regmap;
+ config.regmap = ldo1->regmap;
if (IS_ENABLED(CONFIG_OF)) {
- if (!dev_get_platdata(arizona->dev)) {
- ret = arizona_ldo1_of_get_pdata(arizona, &config, desc);
+ if (!dev_get_platdata(parent_dev)) {
+ ret = arizona_ldo1_of_get_pdata(pdata,
+ &config, desc,
+ external_dcvdd);
if (ret < 0)
return ret;
}
}
- config.ena_gpio = arizona->pdata.ldoena;
+ config.ena_gpio = pdata->ldoena;
- if (arizona->pdata.ldo1)
- config.init_data = arizona->pdata.ldo1;
+ if (pdata->init_data)
+ config.init_data = pdata->init_data;
else
config.init_data = &ldo1->init_data;
@@ -301,7 +276,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
* consumers then DCVDD is supplied externally.
*/
if (config.init_data->num_consumer_supplies == 0)
- arizona->external_dcvdd = true;
+ *external_dcvdd = true;
ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
@@ -309,7 +284,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
if (IS_ERR(ldo1->regulator)) {
ret = PTR_ERR(ldo1->regulator);
- dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n",
+ dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n",
ret);
return ret;
}
@@ -319,6 +294,53 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
return 0;
}
+static int arizona_ldo1_probe(struct platform_device *pdev)
+{
+ struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+ struct arizona_ldo1 *ldo1;
+ const struct regulator_desc *desc;
+ bool external_dcvdd;
+ int ret;
+
+ ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
+ if (!ldo1)
+ return -ENOMEM;
+
+ ldo1->regmap = arizona->regmap;
+
+ /*
+ * Since the chip usually supplies itself we provide some
+ * default init_data for it. This will be overridden with
+ * platform data if provided.
+ */
+ switch (arizona->type) {
+ case WM5102:
+ case WM8997:
+ case WM8998:
+ case WM1814:
+ desc = &arizona_ldo1_hc;
+ ldo1->init_data = arizona_ldo1_dvfs;
+ break;
+ case WM5110:
+ case WM8280:
+ desc = &arizona_ldo1;
+ ldo1->init_data = arizona_ldo1_wm5110;
+ break;
+ default:
+ desc = &arizona_ldo1;
+ ldo1->init_data = arizona_ldo1_default;
+ break;
+ }
+
+ ret = arizona_ldo1_common_init(pdev, ldo1, desc,
+ &arizona->pdata.ldo1,
+ &external_dcvdd);
+ if (ret == 0)
+ arizona->external_dcvdd = external_dcvdd;
+
+ return ret;
+}
+
static struct platform_driver arizona_ldo1_driver = {
.probe = arizona_ldo1_probe,
.driver = {
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index 22bd71407622..120de94caf02 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -30,9 +30,14 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
+#include <linux/regulator/arizona-micsupp.h>
+
struct arizona_micsupp {
struct regulator_dev *regulator;
- struct arizona *arizona;
+ struct regmap *regmap;
+ struct snd_soc_dapm_context **dapm;
+ unsigned int enable_reg;
+ struct device *dev;
struct regulator_consumer_supply supply;
struct regulator_init_data init_data;
@@ -44,21 +49,22 @@ static void arizona_micsupp_check_cp(struct work_struct *work)
{
struct arizona_micsupp *micsupp =
container_of(work, struct arizona_micsupp, check_cp_work);
- struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
- struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
- struct arizona *arizona = micsupp->arizona;
- struct regmap *regmap = arizona->regmap;
- unsigned int reg;
+ struct snd_soc_dapm_context *dapm = *micsupp->dapm;
+ struct snd_soc_component *component;
+ unsigned int val;
int ret;
- ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, &reg);
+ ret = regmap_read(micsupp->regmap, micsupp->enable_reg, &val);
if (ret != 0) {
- dev_err(arizona->dev, "Failed to read CP state: %d\n", ret);
+ dev_err(micsupp->dev,
+ "Failed to read CP state: %d\n", ret);
return;
}
if (dapm) {
- if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
+ component = snd_soc_dapm_to_component(dapm);
+
+ if ((val & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
ARIZONA_CPMIC_ENA)
snd_soc_component_force_enable_pin(component,
"MICSUPP");
@@ -199,89 +205,67 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
.num_consumer_supplies = 1,
};
-static int arizona_micsupp_of_get_pdata(struct arizona *arizona,
+static int arizona_micsupp_of_get_pdata(struct arizona_micsupp_pdata *pdata,
struct regulator_config *config,
const struct regulator_desc *desc)
{
- 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");
+ np = of_get_child_by_name(config->dev->of_node, "micvdd");
if (np) {
config->of_node = np;
- init_data = of_get_regulator_init_data(arizona->dev, np, desc);
+ init_data = of_get_regulator_init_data(config->dev, np, desc);
if (init_data) {
init_data->consumer_supplies = &micsupp->supply;
init_data->num_consumer_supplies = 1;
- pdata->micvdd = init_data;
+ pdata->init_data = init_data;
}
}
return 0;
}
-static int arizona_micsupp_probe(struct platform_device *pdev)
+static int arizona_micsupp_common_init(struct platform_device *pdev,
+ struct arizona_micsupp *micsupp,
+ const struct regulator_desc *desc,
+ struct arizona_micsupp_pdata *pdata)
{
- struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
- const struct regulator_desc *desc;
struct regulator_config config = { };
- struct arizona_micsupp *micsupp;
int ret;
- micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
- if (!micsupp)
- return -ENOMEM;
-
- micsupp->arizona = arizona;
INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
- /*
- * Since the chip usually supplies itself we provide some
- * default init_data for it. This will be overridden with
- * platform data if provided.
- */
- switch (arizona->type) {
- case WM5110:
- case WM8280:
- desc = &arizona_micsupp_ext;
- micsupp->init_data = arizona_micsupp_ext_default;
- break;
- default:
- desc = &arizona_micsupp;
- micsupp->init_data = arizona_micsupp_default;
- break;
- }
-
micsupp->init_data.consumer_supplies = &micsupp->supply;
micsupp->supply.supply = "MICVDD";
- micsupp->supply.dev_name = dev_name(arizona->dev);
+ micsupp->supply.dev_name = dev_name(micsupp->dev);
+ micsupp->enable_reg = desc->enable_reg;
- config.dev = arizona->dev;
+ config.dev = micsupp->dev;
config.driver_data = micsupp;
- config.regmap = arizona->regmap;
+ config.regmap = micsupp->regmap;
if (IS_ENABLED(CONFIG_OF)) {
- if (!dev_get_platdata(arizona->dev)) {
- ret = arizona_micsupp_of_get_pdata(arizona, &config,
+ if (!dev_get_platdata(micsupp->dev)) {
+ ret = arizona_micsupp_of_get_pdata(pdata, &config,
desc);
if (ret < 0)
return ret;
}
}
- if (arizona->pdata.micvdd)
- config.init_data = arizona->pdata.micvdd;
+ if (pdata->init_data)
+ config.init_data = pdata->init_data;
else
config.init_data = &micsupp->init_data;
- /* Default to regulated mode until the API supports bypass */
- regmap_update_bits(arizona->regmap, ARIZONA_MIC_CHARGE_PUMP_1,
+ /* Default to regulated mode */
+ regmap_update_bits(micsupp->regmap, micsupp->enable_reg,
ARIZONA_CPMIC_BYPASS, 0);
micsupp->regulator = devm_regulator_register(&pdev->dev,
@@ -292,7 +276,7 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
if (IS_ERR(micsupp->regulator)) {
ret = PTR_ERR(micsupp->regulator);
- dev_err(arizona->dev, "Failed to register mic supply: %d\n",
+ dev_err(micsupp->dev, "Failed to register mic supply: %d\n",
ret);
return ret;
}
@@ -302,6 +286,41 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
return 0;
}
+static int arizona_micsupp_probe(struct platform_device *pdev)
+{
+ struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+ const struct regulator_desc *desc;
+ struct arizona_micsupp *micsupp;
+
+ micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
+ if (!micsupp)
+ return -ENOMEM;
+
+ micsupp->regmap = arizona->regmap;
+ micsupp->dapm = &arizona->dapm;
+ micsupp->dev = arizona->dev;
+
+ /*
+ * Since the chip usually supplies itself we provide some
+ * default init_data for it. This will be overridden with
+ * platform data if provided.
+ */
+ switch (arizona->type) {
+ case WM5110:
+ case WM8280:
+ desc = &arizona_micsupp_ext;
+ micsupp->init_data = arizona_micsupp_ext_default;
+ break;
+ default:
+ desc = &arizona_micsupp;
+ micsupp->init_data = arizona_micsupp_default;
+ break;
+ }
+
+ return arizona_micsupp_common_init(pdev, micsupp, desc,
+ &arizona->pdata.micvdd);
+}
+
static struct platform_driver arizona_micsupp_driver = {
.probe = arizona_micsupp_probe,
.driver = {
diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c
new file mode 100644
index 000000000000..8ba206fec31e
--- /dev/null
+++ b/drivers/regulator/bd9571mwv-regulator.c
@@ -0,0 +1,178 @@
+/*
+ * ROHM BD9571MWV-M regulator driver
+ *
+ * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
+ *
+ * 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 "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether expressed or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2 for more details.
+ *
+ * Based on the TPS65086 driver
+ *
+ * NOTE: VD09 is missing
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+
+#include <linux/mfd/bd9571mwv.h>
+
+enum bd9571mwv_regulators { VD09, VD18, VD25, VD33, DVFS };
+
+#define BD9571MWV_REG(_name, _of, _id, _ops, _vr, _vm, _nv, _min, _step, _lmin)\
+ { \
+ .name = _name, \
+ .of_match = of_match_ptr(_of), \
+ .regulators_node = "regulators", \
+ .id = _id, \
+ .ops = &_ops, \
+ .n_voltages = _nv, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = _vr, \
+ .vsel_mask = _vm, \
+ .min_uV = _min, \
+ .uV_step = _step, \
+ .linear_min_sel = _lmin, \
+ }
+
+int bd9571mwv_avs_get_moni_state(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, BD9571MWV_AVS_SET_MONI, &val);
+ if (ret != 0)
+ return ret;
+
+ return val & BD9571MWV_AVS_SET_MONI_MASK;
+}
+
+int bd9571mwv_avs_set_voltage_sel_regmap(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ int ret;
+
+ ret = bd9571mwv_avs_get_moni_state(rdev);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write_bits(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret),
+ rdev->desc->vsel_mask, sel);
+}
+
+int bd9571mwv_avs_get_voltage_sel_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = bd9571mwv_avs_get_moni_state(rdev);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret), &val);
+ if (ret != 0)
+ return ret;
+
+ val &= rdev->desc->vsel_mask;
+ val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+ return val;
+}
+
+int bd9571mwv_reg_set_voltage_sel_regmap(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ return regmap_write_bits(rdev->regmap, BD9571MWV_DVFS_SETVID,
+ rdev->desc->vsel_mask, sel);
+}
+
+/* Operations permitted on AVS voltage regulator */
+static struct regulator_ops avs_ops = {
+ .set_voltage_sel = bd9571mwv_avs_set_voltage_sel_regmap,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = bd9571mwv_avs_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+/* Operations permitted on voltage regulators */
+static struct regulator_ops reg_ops = {
+ .set_voltage_sel = bd9571mwv_reg_set_voltage_sel_regmap,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+/* Operations permitted on voltage monitors */
+static struct regulator_ops vid_ops = {
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_desc regulators[] = {
+ BD9571MWV_REG("VD09", "vd09", VD09, avs_ops, 0, 0x7f,
+ 0x80, 600000, 10000, 0x3c),
+ BD9571MWV_REG("VD18", "vd18", VD18, vid_ops, BD9571MWV_VD18_VID, 0xf,
+ 16, 1625000, 25000, 0),
+ BD9571MWV_REG("VD25", "vd25", VD25, vid_ops, BD9571MWV_VD25_VID, 0xf,
+ 16, 2150000, 50000, 0),
+ BD9571MWV_REG("VD33", "vd33", VD33, vid_ops, BD9571MWV_VD33_VID, 0xf,
+ 11, 2800000, 100000, 0),
+ BD9571MWV_REG("DVFS", "dvfs", DVFS, reg_ops,
+ BD9571MWV_DVFS_MONIVDAC, 0x7f,
+ 0x80, 600000, 10000, 0x3c),
+};
+
+static int bd9571mwv_regulator_probe(struct platform_device *pdev)
+{
+ struct bd9571mwv *bd = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+ int i;
+
+ platform_set_drvdata(pdev, bd);
+
+ config.dev = &pdev->dev;
+ config.dev->of_node = bd->dev->of_node;
+ config.driver_data = bd;
+ config.regmap = bd->regmap;
+
+ for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+ rdev = devm_regulator_register(&pdev->dev, &regulators[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(bd->dev, "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id bd9571mwv_regulator_id_table[] = {
+ { "bd9571mwv-regulator", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table);
+
+static struct platform_driver bd9571mwv_regulator_driver = {
+ .driver = {
+ .name = "bd9571mwv-regulator",
+ },
+ .probe = bd9571mwv_regulator_probe,
+ .id_table = bd9571mwv_regulator_id_table,
+};
+module_platform_driver(bd9571mwv_regulator_driver);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
+MODULE_DESCRIPTION("BD9571MWV Regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 53d4fc70dbd0..c0d9ae8d0860 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1326,8 +1326,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
regulator->dev = dev;
/* Add a link to the device sysfs entry */
- size = scnprintf(buf, REG_STR_SIZE, "%s-%s",
- dev->kobj.name, supply_name);
+ size = snprintf(buf, REG_STR_SIZE, "%s-%s",
+ dev->kobj.name, supply_name);
if (size >= REG_STR_SIZE)
goto overflow_err;
@@ -1343,7 +1343,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
/* non-fatal */
}
} else {
- regulator->supply_name = kstrdup(supply_name, GFP_KERNEL);
+ regulator->supply_name = kstrdup_const(supply_name, GFP_KERNEL);
if (regulator->supply_name == NULL)
goto overflow_err;
}
@@ -1451,8 +1451,6 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
* regulator_dev_lookup - lookup a regulator device.
* @dev: device for regulator "consumer".
* @supply: Supply name or regulator ID.
- * @ret: 0 on success, -ENODEV if lookup fails permanently, -EPROBE_DEFER if
- * lookup could succeed in the future.
*
* If successful, returns a struct regulator_dev that corresponds to the name
* @supply and with the embedded struct device refcount incremented by one.
@@ -1534,14 +1532,6 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (IS_ERR(r)) {
ret = PTR_ERR(r);
- if (ret == -ENODEV) {
- /*
- * No supply was specified for this regulator and
- * there will never be one.
- */
- return 0;
- }
-
/* Did the lookup explicitly defer for us? */
if (ret == -EPROBE_DEFER)
return ret;
@@ -1799,7 +1789,7 @@ static void _regulator_put(struct regulator *regulator)
put_device(&rdev->dev);
mutex_unlock(&rdev->mutex);
- kfree(regulator->supply_name);
+ kfree_const(regulator->supply_name);
kfree(regulator);
module_put(rdev->owner);
@@ -2182,6 +2172,8 @@ static int _regulator_enable(struct regulator_dev *rdev)
if (ret < 0)
return ret;
+ _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE,
+ NULL);
} else if (ret < 0) {
rdev_err(rdev, "is_enabled() failed: %d\n", ret);
return ret;
@@ -2486,7 +2478,7 @@ static int _regulator_list_voltage(struct regulator *regulator,
ret = ops->list_voltage(rdev, selector);
if (lock)
mutex_unlock(&rdev->mutex);
- } else if (rdev->supply) {
+ } else if (rdev->is_switch && rdev->supply) {
ret = _regulator_list_voltage(rdev->supply, selector, lock);
} else {
return -EINVAL;
@@ -2544,7 +2536,7 @@ int regulator_count_voltages(struct regulator *regulator)
if (rdev->desc->n_voltages)
return rdev->desc->n_voltages;
- if (!rdev->supply)
+ if (!rdev->is_switch || !rdev->supply)
return -EINVAL;
return regulator_count_voltages(rdev->supply);
@@ -2773,6 +2765,8 @@ static int _regulator_set_voltage_time(struct regulator_dev *rdev,
ramp_delay = rdev->constraints->ramp_delay;
else if (rdev->desc->ramp_delay)
ramp_delay = rdev->desc->ramp_delay;
+ else if (rdev->constraints->settling_time)
+ return rdev->constraints->settling_time;
if (ramp_delay == 0) {
rdev_dbg(rdev, "ramp_delay not set\n");
@@ -2941,8 +2935,10 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
if (ret < 0)
goto out2;
- if (rdev->supply && (rdev->desc->min_dropout_uV ||
- !rdev->desc->ops->get_voltage)) {
+ if (rdev->supply &&
+ regulator_ops_is_valid(rdev->supply->rdev,
+ REGULATOR_CHANGE_VOLTAGE) &&
+ (rdev->desc->min_dropout_uV || !rdev->desc->ops->get_voltage)) {
int current_supply_uV;
int selector;
@@ -4099,6 +4095,11 @@ regulator_register(const struct regulator_desc *regulator_desc,
mutex_unlock(&regulator_list_mutex);
}
+ if (!rdev->desc->ops->get_voltage &&
+ !rdev->desc->ops->list_voltage &&
+ !rdev->desc->fixed_uV)
+ rdev->is_switch = true;
+
ret = device_register(&rdev->dev);
if (ret != 0) {
put_device(&rdev->dev);
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index 379cdacc05d8..2ae7c3ac5940 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -446,6 +446,42 @@ int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
/**
+ * regulator_set_soft_start_regmap - Default set_soft_start() using regmap
+ *
+ * @rdev: device to operate on.
+ */
+int regulator_set_soft_start_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+
+ val = rdev->desc->soft_start_val_on;
+ if (!val)
+ val = rdev->desc->soft_start_mask;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->soft_start_reg,
+ rdev->desc->soft_start_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_soft_start_regmap);
+
+/**
+ * regulator_set_pull_down_regmap - Default set_pull_down() using regmap
+ *
+ * @rdev: device to operate on.
+ */
+int regulator_set_pull_down_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+
+ val = rdev->desc->pull_down_val_on;
+ if (!val)
+ val = rdev->desc->pull_down_mask;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->pull_down_reg,
+ rdev->desc->pull_down_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_pull_down_regmap);
+
+/**
* regulator_get_bypass_regmap - Default get_bypass() using regmap
*
* @rdev: device to operate on.
diff --git a/drivers/regulator/hi655x-regulator.c b/drivers/regulator/hi655x-regulator.c
index 065c100e9a03..36ae54b53814 100644
--- a/drivers/regulator/hi655x-regulator.c
+++ b/drivers/regulator/hi655x-regulator.c
@@ -214,7 +214,14 @@ static int hi655x_regulator_probe(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id hi655x_regulator_table[] = {
+ { .name = "hi655x-regulator" },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, hi655x_regulator_table);
+
static struct platform_driver hi655x_regulator_driver = {
+ .id_table = hi655x_regulator_table,
.driver = {
.name = "hi655x-regulator",
},
diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h
index 1dd575b28564..66a8ea0c8386 100644
--- a/drivers/regulator/internal.h
+++ b/drivers/regulator/internal.h
@@ -29,7 +29,7 @@ struct regulator {
int uA_load;
int min_uV;
int max_uV;
- char *supply_name;
+ const char *supply_name;
struct device_attribute dev_attr;
struct regulator_dev *rdev;
struct dentry *debugfs;
diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c
index f53e63301a20..ce5f7d9ad475 100644
--- a/drivers/regulator/lm363x-regulator.c
+++ b/drivers/regulator/lm363x-regulator.c
@@ -227,9 +227,9 @@ static int lm363x_regulator_of_get_enable_gpio(struct device_node *np, int id)
*/
switch (id) {
case LM3632_LDO_POS:
- return of_get_named_gpio(np, "ti,lcm-en1-gpio", 0);
+ return of_get_named_gpio(np, "enable-gpios", 0);
case LM3632_LDO_NEG:
- return of_get_named_gpio(np, "ti,lcm-en2-gpio", 0);
+ return of_get_named_gpio(np, "enable-gpios", 1);
default:
return -EINVAL;
}
diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c
index a7a1a0313bbf..853a06ad86d6 100644
--- a/drivers/regulator/ltc3589.c
+++ b/drivers/regulator/ltc3589.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
@@ -470,7 +471,11 @@ static int ltc3589_probe(struct i2c_client *client,
return -ENOMEM;
i2c_set_clientdata(client, ltc3589);
- ltc3589->variant = id->driver_data;
+ if (client->dev.of_node)
+ ltc3589->variant = (enum ltc3589_variant)
+ of_device_get_match_data(&client->dev);
+ else
+ ltc3589->variant = id->driver_data;
ltc3589->dev = dev;
descs = ltc3589->regulator_descs;
@@ -542,9 +547,27 @@ static struct i2c_device_id ltc3589_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ltc3589_i2c_id);
+static const struct of_device_id ltc3589_of_match[] = {
+ {
+ .compatible = "lltc,ltc3589",
+ .data = (void *)LTC3589,
+ },
+ {
+ .compatible = "lltc,ltc3589-1",
+ .data = (void *)LTC3589_1,
+ },
+ {
+ .compatible = "lltc,ltc3589-2",
+ .data = (void *)LTC3589_2,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ltc3589_of_match);
+
static struct i2c_driver ltc3589_driver = {
.driver = {
.name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(ltc3589_of_match),
},
.probe = ltc3589_probe,
.id_table = ltc3589_i2c_id,
diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c
index 503cd90eba39..662ee05ea44d 100644
--- a/drivers/regulator/ltc3676.c
+++ b/drivers/regulator/ltc3676.c
@@ -406,9 +406,16 @@ static const struct i2c_device_id ltc3676_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ltc3676_i2c_id);
+static const struct of_device_id ltc3676_of_match[] = {
+ { .compatible = "lltc,ltc3676" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ltc3676_of_match);
+
static struct i2c_driver ltc3676_driver = {
.driver = {
.name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(ltc3676_of_match),
},
.probe = ltc3676_regulator_probe,
.id_table = ltc3676_i2c_id,
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 2c1228d5796a..6779c2b53674 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -126,14 +126,14 @@ static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev,
* The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back
* the set up value.
*/
-static struct regulator_ops max1586_v3_ops = {
+static const struct regulator_ops max1586_v3_ops = {
.get_voltage_sel = max1586_v3_get_voltage_sel,
.set_voltage_sel = max1586_v3_set_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
};
-static struct regulator_ops max1586_v6_ops = {
+static const struct regulator_ops max1586_v6_ops = {
.get_voltage_sel = max1586_v6_get_voltage_sel,
.set_voltage_sel = max1586_v6_set_voltage_sel,
.list_voltage = regulator_list_voltage_table,
diff --git a/drivers/regulator/max77693-regulator.c b/drivers/regulator/max77693-regulator.c
index 3fce67982682..e7000e777292 100644
--- a/drivers/regulator/max77693-regulator.c
+++ b/drivers/regulator/max77693-regulator.c
@@ -150,7 +150,7 @@ static const struct regulator_ops max77693_safeout_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
-static struct regulator_ops max77693_charger_ops = {
+static const struct regulator_ops max77693_charger_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index b87f62dd484e..a6183425f27d 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -194,7 +194,7 @@ static int max8660_ldo5_set_voltage_sel(struct regulator_dev *rdev,
return max8660_write(max8660, MAX8660_VCC1, 0xff, 0xc0);
}
-static struct regulator_ops max8660_ldo5_ops = {
+static const struct regulator_ops max8660_ldo5_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.set_voltage_sel = max8660_ldo5_set_voltage_sel,
@@ -252,7 +252,7 @@ static int max8660_ldo67_set_voltage_sel(struct regulator_dev *rdev,
selector << 4);
}
-static struct regulator_ops max8660_ldo67_ops = {
+static const struct regulator_ops max8660_ldo67_ops = {
.is_enabled = max8660_ldo67_is_enabled,
.enable = max8660_ldo67_enable,
.disable = max8660_ldo67_disable,
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 4f613ec99500..09d677d5d3f0 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -86,6 +86,10 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->ramp_disable = true;
}
+ ret = of_property_read_u32(np, "regulator-settling-time-us", &pval);
+ if (!ret)
+ constraints->settling_time = pval;
+
ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
if (!ret)
constraints->enable_time = pval;
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index e193bbbb8ffc..63922a2167e5 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -40,6 +40,7 @@
#define PFUZE100_REVID 0x3
#define PFUZE100_FABID 0x4
+#define PFUZE100_COINVOL 0x1a
#define PFUZE100_SW1ABVOL 0x20
#define PFUZE100_SW1CVOL 0x2e
#define PFUZE100_SW2VOL 0x35
@@ -81,6 +82,10 @@ static const int pfuze100_vsnvs[] = {
1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
};
+static const int pfuze100_coin[] = {
+ 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
static const int pfuze3000_sw2lo[] = {
1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000,
};
@@ -230,6 +235,23 @@ static const struct regulator_ops pfuze100_swb_regulator_ops = {
.stby_mask = 0x20, \
}
+#define PFUZE100_COIN_REG(_chip, _name, base, mask, voltages) \
+ [_chip ## _ ## _name] = { \
+ .desc = { \
+ .name = #_name, \
+ .n_voltages = ARRAY_SIZE(voltages), \
+ .ops = &pfuze100_swb_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .volt_table = voltages, \
+ .vsel_reg = (base), \
+ .vsel_mask = (mask), \
+ .enable_reg = (base), \
+ .enable_mask = 0x8, \
+ }, \
+ }
+
#define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step) { \
.desc = { \
.name = #_name, \
@@ -317,6 +339,7 @@ static struct pfuze_regulator pfuze200_regulators[] = {
PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+ PFUZE100_COIN_REG(PFUZE200, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin),
};
static struct pfuze_regulator pfuze3000_regulators[] = {
@@ -371,6 +394,7 @@ static struct of_regulator_match pfuze200_matches[] = {
{ .name = "vgen4", },
{ .name = "vgen5", },
{ .name = "vgen6", },
+ { .name = "coin", },
};
/* PFUZE3000 */
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index fb44d5215e30..a16d81420612 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -519,7 +519,7 @@ static const struct regulator_desc rk818_reg[] = {
RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
BIT(0), 400),
RK8XX_DESC(RK818_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100,
- RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ RK818_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
BIT(1), 400),
{
.name = "LDO_REG3",
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
index 38ee97a085f9..48f0ca90743c 100644
--- a/drivers/regulator/s2mpa01.c
+++ b/drivers/regulator/s2mpa01.c
@@ -213,7 +213,7 @@ ramp_disable:
1 << enable_shift, 0);
}
-static struct regulator_ops s2mpa01_ldo_ops = {
+static const struct regulator_ops s2mpa01_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
@@ -224,7 +224,7 @@ static struct regulator_ops s2mpa01_ldo_ops = {
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
-static struct regulator_ops s2mpa01_buck_ops = {
+static const struct regulator_ops s2mpa01_buck_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
@@ -359,11 +359,11 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev)
if (iodev->dev->of_node) {
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");
- return -EINVAL;
- }
+ if (!reg_np) {
+ dev_err(&pdev->dev,
+ "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
of_regulator_match(&pdev->dev, reg_np, rdata,
S2MPA01_REGULATOR_MAX);
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index d838e77dd947..7726b874e539 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -238,7 +238,7 @@ ramp_disable:
1 << enable_shift, 0);
}
-static struct regulator_ops s2mps11_ldo_ops = {
+static const struct regulator_ops s2mps11_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
@@ -249,7 +249,7 @@ static struct regulator_ops s2mps11_ldo_ops = {
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
-static struct regulator_ops s2mps11_buck_ops = {
+static const struct regulator_ops s2mps11_buck_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
@@ -392,7 +392,7 @@ static const struct regulator_desc s2mps11_regulators[] = {
regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV),
};
-static struct regulator_ops s2mps14_reg_ops;
+static const struct regulator_ops s2mps14_reg_ops;
#define regulator_desc_s2mps13_ldo(num, min, step, min_sel) { \
.name = "LDO"#num, \
@@ -599,7 +599,7 @@ static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
rdev->desc->enable_mask, state);
}
-static struct regulator_ops s2mps14_reg_ops = {
+static const struct regulator_ops s2mps14_reg_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
@@ -681,7 +681,7 @@ static const struct regulator_desc s2mps14_regulators[] = {
S2MPS14_BUCK1235_START_SEL),
};
-static struct regulator_ops s2mps15_reg_ldo_ops = {
+static const struct regulator_ops s2mps15_reg_ldo_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.is_enabled = regulator_is_enabled_regmap,
@@ -691,7 +691,7 @@ static struct regulator_ops s2mps15_reg_ldo_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
-static struct regulator_ops s2mps15_reg_buck_ops = {
+static const struct regulator_ops s2mps15_reg_buck_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.is_enabled = regulator_is_enabled_regmap,
@@ -886,7 +886,7 @@ static int s2mpu02_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
ramp_val << ramp_shift);
}
-static struct regulator_ops s2mpu02_ldo_ops = {
+static const struct regulator_ops s2mpu02_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
@@ -898,7 +898,7 @@ static struct regulator_ops s2mpu02_ldo_ops = {
.set_suspend_disable = s2mps14_regulator_set_suspend_disable,
};
-static struct regulator_ops s2mpu02_buck_ops = {
+static const struct regulator_ops s2mpu02_buck_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 27343e1c43ef..383cd7533721 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -357,7 +357,7 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
return 0;
}
-static struct regulator_ops s5m8767_ops = {
+static const struct regulator_ops s5m8767_ops = {
.list_voltage = regulator_list_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
@@ -367,7 +367,7 @@ static struct regulator_ops s5m8767_ops = {
.set_voltage_time_sel = s5m8767_set_voltage_time_sel,
};
-static struct regulator_ops s5m8767_buck78_ops = {
+static const struct regulator_ops s5m8767_buck78_ops = {
.list_voltage = regulator_list_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index d2c3d7cc35f5..5ca6d2130593 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -311,8 +311,7 @@ static int tps_65023_probe(struct i2c_client *client,
/* Enable setting output voltage by I2C */
regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
- TPS65023_REG_CTRL2_CORE_ADJ,
- TPS65023_REG_CTRL2_CORE_ADJ);
+ TPS65023_REG_CTRL2_CORE_ADJ, 0);
return 0;
}
diff --git a/drivers/regulator/tps65132-regulator.c b/drivers/regulator/tps65132-regulator.c
new file mode 100644
index 000000000000..73978dd440f7
--- /dev/null
+++ b/drivers/regulator/tps65132-regulator.c
@@ -0,0 +1,284 @@
+/*
+ * TI TPS65132 Regulator driver
+ *
+ * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author: Venkat Reddy Talla <vreddytalla@nvidia.com>
+ * Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define TPS65132_REG_VPOS 0x00
+#define TPS65132_REG_VNEG 0x01
+#define TPS65132_REG_APPS_DISP_DISN 0x03
+#define TPS65132_REG_CONTROL 0x0FF
+
+#define TPS65132_VOUT_MASK 0x1F
+#define TPS65132_VOUT_N_VOLTAGE 0x15
+#define TPS65132_VOUT_VMIN 4000000
+#define TPS65132_VOUT_VMAX 6000000
+#define TPS65132_VOUT_STEP 100000
+
+#define TPS65132_REG_APPS_DIS_VPOS BIT(0)
+#define TPS65132_REG_APPS_DIS_VNEG BIT(1)
+
+#define TPS65132_REGULATOR_ID_VPOS 0
+#define TPS65132_REGULATOR_ID_VNEG 1
+#define TPS65132_MAX_REGULATORS 2
+
+#define TPS65132_ACT_DIS_TIME_SLACK 1000
+
+struct tps65132_reg_pdata {
+ struct gpio_desc *en_gpiod;
+ struct gpio_desc *act_dis_gpiod;
+ unsigned int act_dis_time_us;
+ int ena_gpio_state;
+};
+
+struct tps65132_regulator {
+ struct device *dev;
+ struct regmap *rmap;
+ struct regulator_desc *rdesc[TPS65132_MAX_REGULATORS];
+ struct tps65132_reg_pdata reg_pdata[TPS65132_MAX_REGULATORS];
+ struct regulator_dev *rdev[TPS65132_MAX_REGULATORS];
+};
+
+static int tps65132_regulator_enable(struct regulator_dev *rdev)
+{
+ struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
+ int ret;
+
+ if (!IS_ERR(rpdata->en_gpiod)) {
+ gpiod_set_value_cansleep(rpdata->en_gpiod, 1);
+ rpdata->ena_gpio_state = 1;
+ }
+
+ /* Hardware automatically enable discharge bit in enable */
+ if (rdev->constraints->active_discharge ==
+ REGULATOR_ACTIVE_DISCHARGE_DISABLE) {
+ ret = regulator_set_active_discharge_regmap(rdev, false);
+ if (ret < 0) {
+ dev_err(tps->dev, "Failed to disable active discharge: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int tps65132_regulator_disable(struct regulator_dev *rdev)
+{
+ struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
+
+ if (!IS_ERR(rpdata->en_gpiod)) {
+ gpiod_set_value_cansleep(rpdata->en_gpiod, 0);
+ rpdata->ena_gpio_state = 0;
+ }
+
+ if (!IS_ERR(rpdata->act_dis_gpiod)) {
+ gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 1);
+ usleep_range(rpdata->act_dis_time_us, rpdata->act_dis_time_us +
+ TPS65132_ACT_DIS_TIME_SLACK);
+ gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 0);
+ }
+
+ return 0;
+}
+
+static int tps65132_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
+
+ if (!IS_ERR(rpdata->en_gpiod))
+ return rpdata->ena_gpio_state;
+
+ return 1;
+}
+
+static struct regulator_ops tps65132_regulator_ops = {
+ .enable = tps65132_regulator_enable,
+ .disable = tps65132_regulator_disable,
+ .is_enabled = tps65132_regulator_is_enabled,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+};
+
+static int tps65132_of_parse_cb(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct tps65132_regulator *tps = config->driver_data;
+ struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[desc->id];
+ int ret;
+
+ rpdata->en_gpiod = devm_fwnode_get_index_gpiod_from_child(tps->dev,
+ "enable", 0, &np->fwnode, 0, "enable");
+ if (IS_ERR(rpdata->en_gpiod)) {
+ ret = PTR_ERR(rpdata->en_gpiod);
+
+ /* Ignore the error other than probe defer */
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ return 0;
+ }
+
+ rpdata->act_dis_gpiod = devm_fwnode_get_index_gpiod_from_child(
+ tps->dev, "active-discharge", 0,
+ &np->fwnode, 0, "active-discharge");
+ if (IS_ERR(rpdata->act_dis_gpiod)) {
+ ret = PTR_ERR(rpdata->act_dis_gpiod);
+
+ /* Ignore the error other than probe defer */
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ return 0;
+ }
+
+ ret = of_property_read_u32(np, "ti,active-discharge-time-us",
+ &rpdata->act_dis_time_us);
+ if (ret < 0) {
+ dev_err(tps->dev, "Failed to read active discharge time:%d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+#define TPS65132_REGULATOR_DESC(_id, _name) \
+ [TPS65132_REGULATOR_ID_##_id] = { \
+ .name = "tps65132-"#_name, \
+ .supply_name = "vin", \
+ .id = TPS65132_REGULATOR_ID_##_id, \
+ .of_match = of_match_ptr(#_name), \
+ .of_parse_cb = tps65132_of_parse_cb, \
+ .ops = &tps65132_regulator_ops, \
+ .n_voltages = TPS65132_VOUT_N_VOLTAGE, \
+ .min_uV = TPS65132_VOUT_VMIN, \
+ .uV_step = TPS65132_VOUT_STEP, \
+ .enable_time = 500, \
+ .vsel_mask = TPS65132_VOUT_MASK, \
+ .vsel_reg = TPS65132_REG_##_id, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = TPS65132_REG_APPS_DIS_##_id, \
+ .active_discharge_mask = TPS65132_REG_APPS_DIS_##_id, \
+ .active_discharge_reg = TPS65132_REG_APPS_DISP_DISN, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }
+
+static struct regulator_desc tps_regs_desc[TPS65132_MAX_REGULATORS] = {
+ TPS65132_REGULATOR_DESC(VPOS, outp),
+ TPS65132_REGULATOR_DESC(VNEG, outn),
+};
+
+static const struct regmap_range tps65132_no_reg_ranges[] = {
+ regmap_reg_range(TPS65132_REG_APPS_DISP_DISN + 1,
+ TPS65132_REG_CONTROL - 1),
+};
+
+static const struct regmap_access_table tps65132_no_reg_table = {
+ .no_ranges = tps65132_no_reg_ranges,
+ .n_no_ranges = ARRAY_SIZE(tps65132_no_reg_ranges),
+};
+
+static const struct regmap_config tps65132_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = TPS65132_REG_CONTROL,
+ .cache_type = REGCACHE_NONE,
+ .rd_table = &tps65132_no_reg_table,
+ .wr_table = &tps65132_no_reg_table,
+};
+
+static int tps65132_probe(struct i2c_client *client,
+ const struct i2c_device_id *client_id)
+{
+ struct device *dev = &client->dev;
+ struct tps65132_regulator *tps;
+ struct regulator_config config = { };
+ int id;
+ int ret;
+
+ tps = devm_kzalloc(dev, sizeof(*tps), GFP_KERNEL);
+ if (!tps)
+ return -ENOMEM;
+
+ tps->rmap = devm_regmap_init_i2c(client, &tps65132_regmap_config);
+ if (IS_ERR(tps->rmap)) {
+ ret = PTR_ERR(tps->rmap);
+ dev_err(dev, "regmap init failed: %d\n", ret);
+ return ret;
+ }
+
+ i2c_set_clientdata(client, tps);
+ tps->dev = dev;
+
+ for (id = 0; id < TPS65132_MAX_REGULATORS; ++id) {
+ tps->rdesc[id] = &tps_regs_desc[id];
+
+ config.regmap = tps->rmap;
+ config.dev = dev;
+ config.driver_data = tps;
+
+ tps->rdev[id] = devm_regulator_register(dev,
+ tps->rdesc[id], &config);
+ if (IS_ERR(tps->rdev[id])) {
+ ret = PTR_ERR(tps->rdev[id]);
+ dev_err(dev, "regulator %s register failed: %d\n",
+ tps->rdesc[id]->name, ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static const struct i2c_device_id tps65132_id[] = {
+ {.name = "tps65132",},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, tps65132_id);
+
+static struct i2c_driver tps65132_i2c_driver = {
+ .driver = {
+ .name = "tps65132",
+ },
+ .probe = tps65132_probe,
+ .id_table = tps65132_id,
+};
+
+module_i2c_driver(tps65132_i2c_driver);
+
+MODULE_DESCRIPTION("tps65132 regulator driver");
+MODULE_AUTHOR("Venkat Reddy Talla <vreddytalla@nvidia.com>");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c
index 716191046a70..56aada387887 100644
--- a/drivers/regulator/twl6030-regulator.c
+++ b/drivers/regulator/twl6030-regulator.c
@@ -456,8 +456,6 @@ static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV,
vsel = 60;
else if ((min_uV > 1350000) && (min_uV <= 1500000))
vsel = 59;
- else if ((min_uV > 1300000) && (min_uV <= 1350000))
- vsel = 58;
else
return -EINVAL;
break;
diff --git a/drivers/regulator/vctrl-regulator.c b/drivers/regulator/vctrl-regulator.c
new file mode 100644
index 000000000000..78de002037c7
--- /dev/null
+++ b/drivers/regulator/vctrl-regulator.c
@@ -0,0 +1,546 @@
+/*
+ * Driver for voltage controller regulators
+ *
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/sort.h>
+
+struct vctrl_voltage_range {
+ int min_uV;
+ int max_uV;
+};
+
+struct vctrl_voltage_ranges {
+ struct vctrl_voltage_range ctrl;
+ struct vctrl_voltage_range out;
+};
+
+struct vctrl_voltage_table {
+ int ctrl;
+ int out;
+ int ovp_min_sel;
+};
+
+struct vctrl_data {
+ struct regulator_dev *rdev;
+ struct regulator_desc desc;
+ struct regulator *ctrl_reg;
+ bool enabled;
+ unsigned int min_slew_down_rate;
+ unsigned int ovp_threshold;
+ struct vctrl_voltage_ranges vrange;
+ struct vctrl_voltage_table *vtable;
+ unsigned int sel;
+};
+
+static int vctrl_calc_ctrl_voltage(struct vctrl_data *vctrl, int out_uV)
+{
+ struct vctrl_voltage_range *ctrl = &vctrl->vrange.ctrl;
+ struct vctrl_voltage_range *out = &vctrl->vrange.out;
+
+ return ctrl->min_uV +
+ DIV_ROUND_CLOSEST_ULL((s64)(out_uV - out->min_uV) *
+ (ctrl->max_uV - ctrl->min_uV),
+ out->max_uV - out->min_uV);
+}
+
+static int vctrl_calc_output_voltage(struct vctrl_data *vctrl, int ctrl_uV)
+{
+ struct vctrl_voltage_range *ctrl = &vctrl->vrange.ctrl;
+ struct vctrl_voltage_range *out = &vctrl->vrange.out;
+
+ if (ctrl_uV < 0) {
+ pr_err("vctrl: failed to get control voltage\n");
+ return ctrl_uV;
+ }
+
+ if (ctrl_uV < ctrl->min_uV)
+ return out->min_uV;
+
+ if (ctrl_uV > ctrl->max_uV)
+ return out->max_uV;
+
+ return out->min_uV +
+ DIV_ROUND_CLOSEST_ULL((s64)(ctrl_uV - ctrl->min_uV) *
+ (out->max_uV - out->min_uV),
+ ctrl->max_uV - ctrl->min_uV);
+}
+
+static int vctrl_get_voltage(struct regulator_dev *rdev)
+{
+ struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
+ int ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg);
+
+ return vctrl_calc_output_voltage(vctrl, ctrl_uV);
+}
+
+static int vctrl_set_voltage(struct regulator_dev *rdev,
+ int req_min_uV, int req_max_uV,
+ unsigned int *selector)
+{
+ struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
+ struct regulator *ctrl_reg = vctrl->ctrl_reg;
+ int orig_ctrl_uV = regulator_get_voltage(ctrl_reg);
+ int uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV);
+ int ret;
+
+ if (req_min_uV >= uV || !vctrl->ovp_threshold)
+ /* voltage rising or no OVP */
+ return regulator_set_voltage(
+ ctrl_reg,
+ vctrl_calc_ctrl_voltage(vctrl, req_min_uV),
+ vctrl_calc_ctrl_voltage(vctrl, req_max_uV));
+
+ while (uV > req_min_uV) {
+ int max_drop_uV = (uV * vctrl->ovp_threshold) / 100;
+ int next_uV;
+ int next_ctrl_uV;
+ int delay;
+
+ /* Make sure no infinite loop even in crazy cases */
+ if (max_drop_uV == 0)
+ max_drop_uV = 1;
+
+ next_uV = max_t(int, req_min_uV, uV - max_drop_uV);
+ next_ctrl_uV = vctrl_calc_ctrl_voltage(vctrl, next_uV);
+
+ ret = regulator_set_voltage(ctrl_reg,
+ next_ctrl_uV,
+ next_ctrl_uV);
+ if (ret)
+ goto err;
+
+ delay = DIV_ROUND_UP(uV - next_uV, vctrl->min_slew_down_rate);
+ usleep_range(delay, delay + DIV_ROUND_UP(delay, 10));
+
+ uV = next_uV;
+ }
+
+ return 0;
+
+err:
+ /* Try to go back to original voltage */
+ regulator_set_voltage(ctrl_reg, orig_ctrl_uV, orig_ctrl_uV);
+
+ return ret;
+}
+
+static int vctrl_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
+
+ return vctrl->sel;
+}
+
+static int vctrl_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
+ struct regulator *ctrl_reg = vctrl->ctrl_reg;
+ unsigned int orig_sel = vctrl->sel;
+ int ret;
+
+ if (selector >= rdev->desc->n_voltages)
+ return -EINVAL;
+
+ if (selector >= vctrl->sel || !vctrl->ovp_threshold) {
+ /* voltage rising or no OVP */
+ ret = regulator_set_voltage(ctrl_reg,
+ vctrl->vtable[selector].ctrl,
+ vctrl->vtable[selector].ctrl);
+ if (!ret)
+ vctrl->sel = selector;
+
+ return ret;
+ }
+
+ while (vctrl->sel != selector) {
+ unsigned int next_sel;
+ int delay;
+
+ if (selector >= vctrl->vtable[vctrl->sel].ovp_min_sel)
+ next_sel = selector;
+ else
+ next_sel = vctrl->vtable[vctrl->sel].ovp_min_sel;
+
+ ret = regulator_set_voltage(ctrl_reg,
+ vctrl->vtable[next_sel].ctrl,
+ vctrl->vtable[next_sel].ctrl);
+ if (ret) {
+ dev_err(&rdev->dev,
+ "failed to set control voltage to %duV\n",
+ vctrl->vtable[next_sel].ctrl);
+ goto err;
+ }
+ vctrl->sel = next_sel;
+
+ delay = DIV_ROUND_UP(vctrl->vtable[vctrl->sel].out -
+ vctrl->vtable[next_sel].out,
+ vctrl->min_slew_down_rate);
+ usleep_range(delay, delay + DIV_ROUND_UP(delay, 10));
+ }
+
+ return 0;
+
+err:
+ if (vctrl->sel != orig_sel) {
+ /* Try to go back to original voltage */
+ if (!regulator_set_voltage(ctrl_reg,
+ vctrl->vtable[orig_sel].ctrl,
+ vctrl->vtable[orig_sel].ctrl))
+ vctrl->sel = orig_sel;
+ else
+ dev_warn(&rdev->dev,
+ "failed to restore original voltage\n");
+ }
+
+ return ret;
+}
+
+static int vctrl_list_voltage(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
+
+ if (selector >= rdev->desc->n_voltages)
+ return -EINVAL;
+
+ return vctrl->vtable[selector].out;
+}
+
+static int vctrl_parse_dt(struct platform_device *pdev,
+ struct vctrl_data *vctrl)
+{
+ int ret;
+ struct device_node *np = pdev->dev.of_node;
+ u32 pval;
+ u32 vrange_ctrl[2];
+
+ vctrl->ctrl_reg = devm_regulator_get(&pdev->dev, "ctrl");
+ if (IS_ERR(vctrl->ctrl_reg))
+ return PTR_ERR(vctrl->ctrl_reg);
+
+ ret = of_property_read_u32(np, "ovp-threshold-percent", &pval);
+ if (!ret) {
+ vctrl->ovp_threshold = pval;
+ if (vctrl->ovp_threshold > 100) {
+ dev_err(&pdev->dev,
+ "ovp-threshold-percent (%u) > 100\n",
+ vctrl->ovp_threshold);
+ return -EINVAL;
+ }
+ }
+
+ ret = of_property_read_u32(np, "min-slew-down-rate", &pval);
+ if (!ret) {
+ vctrl->min_slew_down_rate = pval;
+
+ /* We use the value as int and as divider; sanity check */
+ if (vctrl->min_slew_down_rate == 0) {
+ dev_err(&pdev->dev,
+ "min-slew-down-rate must not be 0\n");
+ return -EINVAL;
+ } else if (vctrl->min_slew_down_rate > INT_MAX) {
+ dev_err(&pdev->dev, "min-slew-down-rate (%u) too big\n",
+ vctrl->min_slew_down_rate);
+ return -EINVAL;
+ }
+ }
+
+ if (vctrl->ovp_threshold && !vctrl->min_slew_down_rate) {
+ dev_err(&pdev->dev,
+ "ovp-threshold-percent requires min-slew-down-rate\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(np, "regulator-min-microvolt", &pval);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to read regulator-min-microvolt: %d\n", ret);
+ return ret;
+ }
+ vctrl->vrange.out.min_uV = pval;
+
+ ret = of_property_read_u32(np, "regulator-max-microvolt", &pval);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to read regulator-max-microvolt: %d\n", ret);
+ return ret;
+ }
+ vctrl->vrange.out.max_uV = pval;
+
+ ret = of_property_read_u32_array(np, "ctrl-voltage-range", vrange_ctrl,
+ 2);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read ctrl-voltage-range: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (vrange_ctrl[0] >= vrange_ctrl[1]) {
+ dev_err(&pdev->dev, "ctrl-voltage-range is invalid: %d-%d\n",
+ vrange_ctrl[0], vrange_ctrl[1]);
+ return -EINVAL;
+ }
+
+ vctrl->vrange.ctrl.min_uV = vrange_ctrl[0];
+ vctrl->vrange.ctrl.max_uV = vrange_ctrl[1];
+
+ return 0;
+}
+
+static int vctrl_cmp_ctrl_uV(const void *a, const void *b)
+{
+ const struct vctrl_voltage_table *at = a;
+ const struct vctrl_voltage_table *bt = b;
+
+ return at->ctrl - bt->ctrl;
+}
+
+static int vctrl_init_vtable(struct platform_device *pdev)
+{
+ struct vctrl_data *vctrl = platform_get_drvdata(pdev);
+ struct regulator_desc *rdesc = &vctrl->desc;
+ struct regulator *ctrl_reg = vctrl->ctrl_reg;
+ struct vctrl_voltage_range *vrange_ctrl = &vctrl->vrange.ctrl;
+ int n_voltages;
+ int ctrl_uV;
+ int i, idx_vt;
+
+ n_voltages = regulator_count_voltages(ctrl_reg);
+
+ rdesc->n_voltages = n_voltages;
+
+ /* determine number of steps within the range of the vctrl regulator */
+ for (i = 0; i < n_voltages; i++) {
+ ctrl_uV = regulator_list_voltage(ctrl_reg, i);
+
+ if (ctrl_uV < vrange_ctrl->min_uV ||
+ ctrl_uV > vrange_ctrl->max_uV) {
+ rdesc->n_voltages--;
+ continue;
+ }
+ }
+
+ if (rdesc->n_voltages == 0) {
+ dev_err(&pdev->dev, "invalid configuration\n");
+ return -EINVAL;
+ }
+
+ vctrl->vtable = devm_kcalloc(&pdev->dev, rdesc->n_voltages,
+ sizeof(struct vctrl_voltage_table),
+ GFP_KERNEL);
+ if (!vctrl->vtable)
+ return -ENOMEM;
+
+ /* create mapping control <=> output voltage */
+ for (i = 0, idx_vt = 0; i < n_voltages; i++) {
+ ctrl_uV = regulator_list_voltage(ctrl_reg, i);
+
+ if (ctrl_uV < vrange_ctrl->min_uV ||
+ ctrl_uV > vrange_ctrl->max_uV)
+ continue;
+
+ vctrl->vtable[idx_vt].ctrl = ctrl_uV;
+ vctrl->vtable[idx_vt].out =
+ vctrl_calc_output_voltage(vctrl, ctrl_uV);
+ idx_vt++;
+ }
+
+ /* we rely on the table to be ordered by ascending voltage */
+ sort(vctrl->vtable, rdesc->n_voltages,
+ sizeof(struct vctrl_voltage_table), vctrl_cmp_ctrl_uV,
+ NULL);
+
+ /* pre-calculate OVP-safe downward transitions */
+ for (i = rdesc->n_voltages - 1; i > 0; i--) {
+ int j;
+ int ovp_min_uV = (vctrl->vtable[i].out *
+ (100 - vctrl->ovp_threshold)) / 100;
+
+ for (j = 0; j < i; j++) {
+ if (vctrl->vtable[j].out >= ovp_min_uV) {
+ vctrl->vtable[i].ovp_min_sel = j;
+ break;
+ }
+ }
+
+ if (j == i) {
+ dev_warn(&pdev->dev, "switching down from %duV may cause OVP shutdown\n",
+ vctrl->vtable[i].out);
+ /* use next lowest voltage */
+ vctrl->vtable[i].ovp_min_sel = i - 1;
+ }
+ }
+
+ return 0;
+}
+
+static int vctrl_enable(struct regulator_dev *rdev)
+{
+ struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
+ int ret = regulator_enable(vctrl->ctrl_reg);
+
+ if (!ret)
+ vctrl->enabled = true;
+
+ return ret;
+}
+
+static int vctrl_disable(struct regulator_dev *rdev)
+{
+ struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
+ int ret = regulator_disable(vctrl->ctrl_reg);
+
+ if (!ret)
+ vctrl->enabled = false;
+
+ return ret;
+}
+
+static int vctrl_is_enabled(struct regulator_dev *rdev)
+{
+ struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
+
+ return vctrl->enabled;
+}
+
+static const struct regulator_ops vctrl_ops_cont = {
+ .enable = vctrl_enable,
+ .disable = vctrl_disable,
+ .is_enabled = vctrl_is_enabled,
+ .get_voltage = vctrl_get_voltage,
+ .set_voltage = vctrl_set_voltage,
+};
+
+static const struct regulator_ops vctrl_ops_non_cont = {
+ .enable = vctrl_enable,
+ .disable = vctrl_disable,
+ .is_enabled = vctrl_is_enabled,
+ .set_voltage_sel = vctrl_set_voltage_sel,
+ .get_voltage_sel = vctrl_get_voltage_sel,
+ .list_voltage = vctrl_list_voltage,
+ .map_voltage = regulator_map_voltage_iterate,
+};
+
+static int vctrl_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct vctrl_data *vctrl;
+ const struct regulator_init_data *init_data;
+ struct regulator_desc *rdesc;
+ struct regulator_config cfg = { };
+ struct vctrl_voltage_range *vrange_ctrl;
+ int ctrl_uV;
+ int ret;
+
+ vctrl = devm_kzalloc(&pdev->dev, sizeof(struct vctrl_data),
+ GFP_KERNEL);
+ if (!vctrl)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, vctrl);
+
+ ret = vctrl_parse_dt(pdev, vctrl);
+ if (ret)
+ return ret;
+
+ vrange_ctrl = &vctrl->vrange.ctrl;
+
+ rdesc = &vctrl->desc;
+ rdesc->name = "vctrl";
+ rdesc->type = REGULATOR_VOLTAGE;
+ rdesc->owner = THIS_MODULE;
+
+ if ((regulator_get_linear_step(vctrl->ctrl_reg) == 1) ||
+ (regulator_count_voltages(vctrl->ctrl_reg) == -EINVAL)) {
+ rdesc->continuous_voltage_range = true;
+ rdesc->ops = &vctrl_ops_cont;
+ } else {
+ rdesc->ops = &vctrl_ops_non_cont;
+ }
+
+ init_data = of_get_regulator_init_data(&pdev->dev, np, rdesc);
+ if (!init_data)
+ return -ENOMEM;
+
+ cfg.of_node = np;
+ cfg.dev = &pdev->dev;
+ cfg.driver_data = vctrl;
+ cfg.init_data = init_data;
+
+ if (!rdesc->continuous_voltage_range) {
+ ret = vctrl_init_vtable(pdev);
+ if (ret)
+ return ret;
+
+ ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg);
+ if (ctrl_uV < 0) {
+ dev_err(&pdev->dev, "failed to get control voltage\n");
+ return ctrl_uV;
+ }
+
+ /* determine current voltage selector from control voltage */
+ if (ctrl_uV < vrange_ctrl->min_uV) {
+ vctrl->sel = 0;
+ } else if (ctrl_uV > vrange_ctrl->max_uV) {
+ vctrl->sel = rdesc->n_voltages - 1;
+ } else {
+ int i;
+
+ for (i = 0; i < rdesc->n_voltages; i++) {
+ if (ctrl_uV == vctrl->vtable[i].ctrl) {
+ vctrl->sel = i;
+ break;
+ }
+ }
+ }
+ }
+
+ vctrl->rdev = devm_regulator_register(&pdev->dev, rdesc, &cfg);
+ if (IS_ERR(vctrl->rdev)) {
+ ret = PTR_ERR(vctrl->rdev);
+ dev_err(&pdev->dev, "failed to register regulator: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id vctrl_of_match[] = {
+ { .compatible = "vctrl-regulator", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, vctrl_of_match);
+
+static struct platform_driver vctrl_driver = {
+ .probe = vctrl_probe,
+ .driver = {
+ .name = "vctrl-regulator",
+ .of_match_table = of_match_ptr(vctrl_of_match),
+ },
+};
+
+module_platform_driver(vctrl_driver);
+
+MODULE_DESCRIPTION("Voltage Controlled Regulator Driver");
+MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 64faeeff698c..bfeecf179895 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -12,6 +12,8 @@
#define _ARIZONA_PDATA_H
#include <dt-bindings/mfd/arizona.h>
+#include <linux/regulator/arizona-ldo1.h>
+#include <linux/regulator/arizona-micsupp.h>
#define ARIZONA_GPN_DIR_MASK 0x8000 /* GPN_DIR */
#define ARIZONA_GPN_DIR_SHIFT 15 /* GPN_DIR */
@@ -76,13 +78,12 @@ struct arizona_micd_range {
struct arizona_pdata {
int reset; /** GPIO controlling /RESET, if any */
- int ldoena; /** GPIO controlling LODENA, if any */
/** Regulator configuration for MICVDD */
- struct regulator_init_data *micvdd;
+ struct arizona_micsupp_pdata micvdd;
/** Regulator configuration for LDO1 */
- struct regulator_init_data *ldo1;
+ struct arizona_ldo1_pdata ldo1;
/** If a direct 32kHz clock is provided on an MCLK specify it here */
int clk32k_src;
diff --git a/include/linux/platform_data/isl9305.h b/include/linux/platform_data/isl9305.h
index 1419133fa69e..4ac1a070af0a 100644
--- a/include/linux/platform_data/isl9305.h
+++ b/include/linux/platform_data/isl9305.h
@@ -24,7 +24,7 @@
struct regulator_init_data;
struct isl9305_pdata {
- struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR];
+ struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR + 1];
};
#endif
diff --git a/include/linux/regulator/arizona-ldo1.h b/include/linux/regulator/arizona-ldo1.h
new file mode 100644
index 000000000000..c685f1277c63
--- /dev/null
+++ b/include/linux/regulator/arizona-ldo1.h
@@ -0,0 +1,24 @@
+/*
+ * Platform data for Arizona LDO1 regulator
+ *
+ * Copyright 2017 Cirrus Logic
+ *
+ * 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.
+ */
+
+#ifndef ARIZONA_LDO1_H
+#define ARIZONA_LDO1_H
+
+struct regulator_init_data;
+
+struct arizona_ldo1_pdata {
+ /** GPIO controlling LDOENA, if any */
+ int ldoena;
+
+ /** Regulator configuration for LDO1 */
+ const struct regulator_init_data *init_data;
+};
+
+#endif
diff --git a/include/linux/regulator/arizona-micsupp.h b/include/linux/regulator/arizona-micsupp.h
new file mode 100644
index 000000000000..616842619c00
--- /dev/null
+++ b/include/linux/regulator/arizona-micsupp.h
@@ -0,0 +1,21 @@
+/*
+ * Platform data for Arizona micsupp regulator
+ *
+ * Copyright 2017 Cirrus Logic
+ *
+ * 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.
+ */
+
+#ifndef ARIZONA_MICSUPP_H
+#define ARIZONA_MICSUPP_H
+
+struct regulator_init_data;
+
+struct arizona_micsupp_pdata {
+ /** Regulator configuration for micsupp */
+ const struct regulator_init_data *init_data;
+};
+
+#endif
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index ea0fffa5faeb..df176d7c2b87 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -119,6 +119,7 @@ struct regmap;
#define REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE 0x200
#define REGULATOR_EVENT_PRE_DISABLE 0x400
#define REGULATOR_EVENT_ABORT_DISABLE 0x800
+#define REGULATOR_EVENT_ENABLE 0x1000
/*
* Regulator errors that can be queried using regulator_get_error_flags
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index dac8e7b16bc6..94417b4226bd 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -292,6 +292,14 @@ enum regulator_type {
* set_active_discharge
* @active_discharge_reg: Register for control when using regmap
* set_active_discharge
+ * @soft_start_reg: Register for control when using regmap set_soft_start
+ * @soft_start_mask: Mask for control when using regmap set_soft_start
+ * @soft_start_val_on: Enabling value for control when using regmap
+ * set_soft_start
+ * @pull_down_reg: Register for control when using regmap set_pull_down
+ * @pull_down_mask: Mask for control when using regmap set_pull_down
+ * @pull_down_val_on: Enabling value for control when using regmap
+ * set_pull_down
*
* @enable_time: Time taken for initial enable of regulator (in uS).
* @off_on_delay: guard time (in uS), before re-enabling a regulator
@@ -345,6 +353,12 @@ struct regulator_desc {
unsigned int active_discharge_off;
unsigned int active_discharge_mask;
unsigned int active_discharge_reg;
+ unsigned int soft_start_reg;
+ unsigned int soft_start_mask;
+ unsigned int soft_start_val_on;
+ unsigned int pull_down_reg;
+ unsigned int pull_down_mask;
+ unsigned int pull_down_val_on;
unsigned int enable_time;
@@ -429,6 +443,8 @@ struct regulator_dev {
struct regulator_enable_gpio *ena_pin;
unsigned int ena_gpio_state:1;
+ unsigned int is_switch:1;
+
/* time when this regulator was disabled last time */
unsigned long last_off_jiffy;
};
@@ -476,6 +492,8 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int new_selector);
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
+int regulator_set_soft_start_regmap(struct regulator_dev *rdev);
+int regulator_set_pull_down_regmap(struct regulator_dev *rdev);
int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
bool enable);
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index c9f795e9a2ee..117699d1f7df 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -108,6 +108,8 @@ struct regulator_state {
* @initial_state: Suspend state to set by default.
* @initial_mode: Mode to set at startup.
* @ramp_delay: Time to settle down after voltage change (unit: uV/us)
+ * @settling_time: Time to settle down after voltage change when voltage
+ * change is non-linear (unit: microseconds).
* @active_discharge: Enable/disable active discharge. The enum
* regulator_active_discharge values are used for
* initialisation.
@@ -149,6 +151,7 @@ struct regulation_constraints {
unsigned int initial_mode;
unsigned int ramp_delay;
+ unsigned int settling_time;
unsigned int enable_time;
unsigned int active_discharge;
diff --git a/include/linux/regulator/pfuze100.h b/include/linux/regulator/pfuze100.h
index 70c6c66c5bcf..e0ccf46f66cf 100644
--- a/include/linux/regulator/pfuze100.h
+++ b/include/linux/regulator/pfuze100.h
@@ -48,6 +48,7 @@
#define PFUZE200_VGEN4 10
#define PFUZE200_VGEN5 11
#define PFUZE200_VGEN6 12
+#define PFUZE200_COIN 13
#define PFUZE3000_SW1A 0
#define PFUZE3000_SW1B 1