Merge tag 'regulator-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 May 2017 19:27:53 +0000 (12:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 May 2017 19:27:53 +0000 (12:27 -0700)
Pull regulator updates from Mark Brown:
 "Quite a lot going on with the regulator API for this release, much
  more in the core than in the drivers for a change:

   - Fixes for voltage change propagation through dumb power switches.

   - A notification when regulators are enabled.

   - A new settling time property for regulators where the time taken to
     move to a new voltage is not related to the size of the change.

   - Some reorganization of the Arizona drivers in preparation for
     sharing the code with the next generation devices they've been
     integrated with.

   - Support for newer Freescale chips in the Anatop regulator.

   - A new driver for voltage controlled regulators to cope with some
     exciting ChromeOS hardware designs.

   - Support for Rohm BD9571MWV-M and TI TPS65132"

* tag 'regulator-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (51 commits)
  regulator: Add ROHM BD9571MWV-M PMIC regulator driver
  regulator: arizona-ldo1: Factor out generic initialization
  regulator: arizona-ldo1: Make arizona_ldo1 independent of struct arizona
  regulator: arizona-ldo1: Move pdata into a separate structure
  regulator: arizona-micsupp: Factor out generic initialization
  regulator: arizona-micsupp: Make arizona_micsupp independent of struct arizona
  regulator: arizona-micsupp: Move pdata into a separate structure
  regulator: arizona: Split KConfig options for LDO1 and MICSUPP regulators
  regulator: anatop: make regulator name property required
  regulator: tps65023: Fix inverted core enable logic.
  regulator: anatop: make sure regulator name is properly defined
  regulator: core: Allow dummy regulators for supplies
  regulator: core: Only propagate voltage changes to if it can change voltages
  regulator: vctrl: Fix out of bounds array access for vctrl->vtable
  regulator: tps65132: fix platform_no_drv_owner.cocci warnings
  regulator: tps65132: Fix off-by-one for .max_register setting
  regulator: anatop: set default voltage selector for pcie
  regulator: tps65132: add device-tree binding
  regulator: tps65132: add regulator driver for TI TPS65132
  regulator: anatop: remove unneeded name field of struct anatop_regulator
  ...

42 files changed:
Documentation/devicetree/bindings/regulator/anatop-regulator.txt
Documentation/devicetree/bindings/regulator/lm363x-regulator.txt
Documentation/devicetree/bindings/regulator/pfuze100.txt
Documentation/devicetree/bindings/regulator/regulator.txt
Documentation/devicetree/bindings/regulator/tps65132-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/vctrl.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/mach-s3c64xx/mach-crag6410-module.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/anatop-regulator.c
drivers/regulator/arizona-ldo1.c
drivers/regulator/arizona-micsupp.c
drivers/regulator/bd9571mwv-regulator.c [new file with mode: 0644]
drivers/regulator/core.c
drivers/regulator/helpers.c
drivers/regulator/hi655x-regulator.c
drivers/regulator/internal.h
drivers/regulator/lm363x-regulator.c
drivers/regulator/ltc3589.c
drivers/regulator/ltc3676.c
drivers/regulator/max1586.c
drivers/regulator/max77693-regulator.c
drivers/regulator/max8660.c
drivers/regulator/of_regulator.c
drivers/regulator/pfuze100-regulator.c
drivers/regulator/rk808-regulator.c
drivers/regulator/s2mpa01.c
drivers/regulator/s2mps11.c
drivers/regulator/s5m8767.c
drivers/regulator/tps65023-regulator.c
drivers/regulator/tps65132-regulator.c [new file with mode: 0644]
drivers/regulator/twl6030-regulator.c
drivers/regulator/vctrl-regulator.c [new file with mode: 0644]
include/linux/mfd/arizona/pdata.h
include/linux/platform_data/isl9305.h
include/linux/regulator/arizona-ldo1.h [new file with mode: 0644]
include/linux/regulator/arizona-micsupp.h [new file with mode: 0644]
include/linux/regulator/consumer.h
include/linux/regulator/driver.h
include/linux/regulator/machine.h
include/linux/regulator/pfuze100.h

index 1d58c8cfdbc01d8fffad426774dd730a987af2d1..a3106c72fbeaa1a862f85b49693490cd74457963 100644 (file)
@@ -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
index 8f14df9d120555adcfca9008238d7653cc7a5675..cc5a6151d85ff40c966a88098236b9fee9a6ea74 100644 (file)
@@ -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
index 9b40db88f637bd9ed7f06c5eb809e7b16ddd660d..444c47831a408c6b24d908f707117d7d3788cfde 100644 (file)
@@ -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;
+                       };
                };
        };
 
index 6ab5aef619d9fe73c1db7e62fa8c10c5c03d33f9..d18edb075e1c746debc19bf4f9bf7325aef0ecef 100644 (file)
@@ -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 (file)
index 0000000..3a35055
--- /dev/null
@@ -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 (file)
index 0000000..601328d
--- /dev/null
@@ -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>;
+       };
index 95803b7b61be292fb59f0372dbf24a62896039b5..c732ba701ae760616827363eb2cf1ddad4af5d97 100644 (file)
@@ -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.?
index ccc3ab8d58e7654f180624036feee1cd7a00e5a8..ea5f2169c850af9acf2657f77af7e43e1dab31fe 100644 (file)
@@ -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,
index be06eb29c6817bd30f5747384e2da7432f87644c..48db87d6dfef4d0bc6f2037feeab7cf88c7949c5 100644 (file)
@@ -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
index ef7725e2592adde95d4fc250f7b626091d9ade7f..dc3503fb3e30c0980acc4fe850302d0e91fd20a8 100644 (file)
@@ -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
index b041f277a38b7ba6634656785012ed5737ab03e6..7d6478e6a5037ea446767ececa7ba0cdfea0d609 100644 (file)
@@ -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;
index e76d094591e72bd1813d4d43f776644c0e314b3f..96fddfff5dc46148086a805918ec83d8bc5d8442 100644 (file)
 #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         = {
index 22bd714076229be6129d73436ac12611f4956f4a..120de94caf02d696f993265edf9d9f07e0cf9b10 100644 (file)
 #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 (file)
index 0000000..8ba206f
--- /dev/null
@@ -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");
index 53d4fc70dbd0981cdb73eabdc815346c25963b6b..c0d9ae8d0860e8e9466dee6fe1e275853b1f9e3b 100644 (file)
@@ -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);
index 379cdacc05d8ecc76465eba8f2515025c7b9fc16..2ae7c3ac5940ec29b52870f4619905e7040aaf20 100644 (file)
@@ -445,6 +445,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
  *
index 065c100e9a03592f53a4b981fe71899a1b236cba..36ae54b53814b36859b149993a198be1c269bf64 100644 (file)
@@ -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",
        },
index 1dd575b285649b04b81a0d109b09f77bd7fd01a6..66a8ea0c83868ebb9a371e52d54761fe1bcc3671 100644 (file)
@@ -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;
index f53e63301a2054d7a822f5017a8e9a2d7d5a35b4..ce5f7d9ad475f420c88a731ec9e1c44378a17c44 100644 (file)
@@ -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;
        }
index a7a1a0313bbfc68625080012e681f50916fe947f..853a06ad86d6c429cc52683b88566712ae431ea2 100644 (file)
@@ -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,
index 503cd90eba393439114a05c0c8d5e788216d7653..662ee05ea44d7c0cea7d0abf69c9503d887f3529 100644 (file)
@@ -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,
index 2c1228d5796acb1df61cb12c161fc4ba8ed2f1b8..6779c2b536744b9d95c9fd32068d9ac83c436f6e 100644 (file)
@@ -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,
index 3fce67982682c576748a8f5b5b740dc6cac447d2..e7000e777292f957f2e6a49bbcec72fbfa5a42c4 100644 (file)
@@ -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,
index b87f62dd484e0a4ca349e5a9f7d5fbb34aaab349..a6183425f27d19084c7eb261a127d678c88eab0b 100644 (file)
@@ -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,
index 4f613ec995004dc04aa62bef738091bdaf38093d..09d677d5d3f02b6dea295c8379df2cc03d8e8577 100644 (file)
@@ -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;
index e193bbbb8ffc1beebabd453a06dc8670d159fe0d..63922a2167e55a75fb5e3c3f2526bc9f06bcabf2 100644 (file)
@@ -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 */
index fb44d5215e30c8573b8eef9ad751367ef4e23e81..a16d81420612e485e2a96e1fe679d3c3b13d7d31 100644 (file)
@@ -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",
index 38ee97a085f915921d8d67b4ae839f202422eaa8..48f0ca90743cca5cec830e6b2ce74fa9f7e8d0a8 100644 (file)
@@ -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);
index d838e77dd94785144cc64d62ab5d6a188abdf446..7726b874e5399cd55be8c4b7f0963956b64af0db 100644 (file)
@@ -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,
index 27343e1c43ef8bee1b3e10dbaf79f293bd81b70f..383cd7533721cf1c2f831e91981fdfd29806da2b 100644 (file)
@@ -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,
index d2c3d7cc35f50bcffb28c949b4c24b3bcd0b5272..5ca6d21305935ae42f4abf88c1aab92df93a50f2 100644 (file)
@@ -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 (file)
index 0000000..73978dd
--- /dev/null
@@ -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");
index 716191046a70782b0007033dda6e1402c0d68ea3..56aada387887766048b822c362cb5520493bcda5 100644 (file)
@@ -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 (file)
index 0000000..78de002
--- /dev/null
@@ -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");
index 64faeeff698c2275bab11c9680f4665126a50494..bfeecf179895b09edfb2ed5489e6293ca5a100d7 100644 (file)
@@ -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;
index 1419133fa69e9be9ad07e55690fb8abeff966e32..4ac1a070af0a1967f59c02e3b18363ba83e7552f 100644 (file)
@@ -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 (file)
index 0000000..c685f12
--- /dev/null
@@ -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 (file)
index 0000000..6168426
--- /dev/null
@@ -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
index ea0fffa5faebb1688ecdb6166db8c7f4d2836c40..df176d7c2b87c00356a11b383a61185e7f3e47ae 100644 (file)
@@ -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
index dac8e7b16bc679e8550ee7781cbda5194791c535..94417b4226bd88a42d5d53c845266ee97ec30879 100644 (file)
@@ -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);
index c9f795e9a2ee26aaf562e9a97a2fe2f963a2f054..117699d1f7df4f72491bd65eccec39a160acf646 100644 (file)
@@ -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;
index 70c6c66c5bcf16cc4be324a1aaf40b1981e56413..e0ccf46f66cf34ae44296de9410fa107270aff4e 100644 (file)
@@ -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