Merge tag 'regulator-v5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Oct 2018 00:54:44 +0000 (01:54 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Oct 2018 00:54:44 +0000 (01:54 +0100)
Pull regulator updates from Mark Brown:
 "The biggest chunk of the regulator changes for this release outside of
  the new drivers is the conversion of the fixed regulator to use the
  GPIO descriptor API, there's a small addition to the GPIO API plus a
  bunch of updates to board files to implement it. This is some really
  welcome work from Linus Walleij that's had a bunch of review and has
  been sitting in -next for a while so I'm fairly happy there's no major
  issues.

   - Helpers for overlapping linear ranges.

   - Display opmode and consumer requested load in the regualtor_summary
     file in debugfs, plus a fix there.

   - Support for the fun and entertaining power off mechanism that the
     pfuze100 hardware implements.

   - Conversion of the fixed regulator API to use GPIO descriptors,
     including pulling in a bunch of patches to a bunch of board files.

   - New drivers for Cirrus Logic Lochnagar, Qualcomm PMS405, Rohm
     BD71847, ST PMIC1, and TI LM363x devices"

* tag 'regulator-v5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (36 commits)
  regulator: lochnagar: Use a consisent comment style for SPDX header
  regulator: bd718x7: Remove struct bd718xx_pmic
  regulator: Fetch enable gpiods nonexclusive
  regulator/gpio: Allow nonexclusive GPIO access
  regulator: lochnagar: Add support for the Cirrus Logic Lochnagar
  regulator: stpmic1: Return REGULATOR_MODE_INVALID for invalid mode
  regulator: stpmic1: add stpmic1 regulator driver
  dt-bindings: regulator: document stpmic1 pmic regulators
  regulator: axp20x: Mark expected switch fall-throughs
  regulator: bd718xx: fix build warning on x86_64
  regulator: fixed: Default enable high on DT regulators
  regulator: bd718xx: rename bd71837 to 718xx
  regulator: bd718XX use pickable ranges
  regulator/mfd: bd718xx: rename bd71837/bd71847 common instances
  regulator: Support regulators where voltage ranges are selectable
  mfd: dt bindings: add BD71847 device-tree binding documentation
  regulator: dt bindings: add BD71847 device-tree binding documentation
  regulator/mfd: Support ROHM BD71847 power management IC
  regulator: da905{2,5}: Remove unnecessary array check
  regulator: qcom: Add PMS405 regulators
  ...

58 files changed:
Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
Documentation/devicetree/bindings/regulator/pfuze100.txt
Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt
Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt [new file with mode: 0644]
arch/arm/mach-imx/mach-mx21ads.c
arch/arm/mach-imx/mach-mx27ads.c
arch/arm/mach-mmp/brownstone.c
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/raumfeld.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/generic.h
arch/arm/mach-sa1100/shannon.c
arch/sh/boards/mach-ecovec24/setup.c
arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c
drivers/gpio/gpiolib.c
drivers/mfd/rohm-bd718x7.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/arizona-ldo1.c
drivers/regulator/axp20x-regulator.c
drivers/regulator/bd71837-regulator.c [deleted file]
drivers/regulator/bd718x7-regulator.c [new file with mode: 0644]
drivers/regulator/core.c
drivers/regulator/da9052-regulator.c
drivers/regulator/da9055-regulator.c
drivers/regulator/da9211-regulator.c
drivers/regulator/fixed-helper.c
drivers/regulator/fixed.c
drivers/regulator/helpers.c
drivers/regulator/isl9305.c
drivers/regulator/lm363x-regulator.c
drivers/regulator/lochnagar-regulator.c [new file with mode: 0644]
drivers/regulator/lp8788-ldo.c
drivers/regulator/max8952.c
drivers/regulator/max8973-regulator.c
drivers/regulator/max8997-regulator.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/of_regulator.c
drivers/regulator/pfuze100-regulator.c
drivers/regulator/qcom-rpmh-regulator.c
drivers/regulator/qcom_smd-regulator.c
drivers/regulator/s5m8767.c
drivers/regulator/stpmic1_regulator.c [new file with mode: 0644]
drivers/regulator/tps65090-regulator.c
include/linux/gpio/consumer.h
include/linux/mfd/rohm-bd718x7.h
include/linux/regulator/driver.h
include/linux/regulator/fixed.h
kernel/reboot.c

index 3ca56fdb5ffeeb1233f39ec81716bd408104a678..a4b056761eaa94f9cbfb7ab30c4249c20a4fe34a 100644 (file)
@@ -1,16 +1,17 @@
-* ROHM BD71837 Power Management Integrated Circuit bindings
+* ROHM BD71837 and BD71847 Power Management Integrated Circuit bindings
 
-BD71837MWV is a programmable Power Management IC for powering single-core,
-dual-core, and quad-core SoCs such as NXP-i.MX 8M. It is optimized for
-low BOM cost and compact solution footprint. It integrates 8 Buck
-egulators and 7 LDOs to provide all the power rails required by the SoC and
-the commonly used peripherals.
+BD71837MWV and BD71847MWV are programmable Power Management ICs for powering
+single-core, dual-core, and quad-core SoCs such as NXP-i.MX 8M. They are
+optimized for low BOM cost and compact solution footprint. BD71837MWV
+integrates 8 Buck regulators and 7 LDOs. BD71847MWV contains 6 Buck regulators
+and 6 LDOs.
 
-Datasheet for PMIC is available at:
+Datasheet for BD71837 is available at:
 https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
 
 Required properties:
- - compatible          : Should be "rohm,bd71837".
+ - compatible          : Should be "rohm,bd71837" for bd71837
+                                   "rohm,bd71847" for bd71847.
  - reg                 : I2C slave address.
  - interrupt-parent    : Phandle to the parent interrupt controller.
  - interrupts          : The interrupt line the device is connected to.
index c7610718adfff69fd8e98068721534c4cdf7f7c7..f9be1acf891c1f60ddacef13f0204a7f71bba530 100644 (file)
@@ -12,6 +12,11 @@ Optional properties:
   disabled. This binding is a workaround to keep backward compatibility with
   old dtb's which rely on the fact that the switched regulators are always on
   and don't mark them explicit as "regulator-always-on".
+- fsl,pmic-stby-poweroff: if present, configure the PMIC to shutdown all
+  power rails when PMIC_STBY_REQ line is asserted during the power off sequence.
+  Use this option if the SoC should be powered off by external power
+  management IC (PMIC) on PMIC_STBY_REQ signal.
+  As opposite to PMIC_STBY_REQ boards can implement PMIC_ON_REQ signal.
 
 Required child node:
 - regulators: This is the list of child nodes that specify the regulator
index 58a1d97972f5aad1bf78f2f14556a8011c905237..45025b5b67f6ba1fcd60e70502642afdc06cd0e0 100644 (file)
@@ -26,6 +26,7 @@ Regulator nodes are identified by their compatible:
                    "qcom,rpm-pm8998-regulators"
                    "qcom,rpm-pma8084-regulators"
                    "qcom,rpm-pmi8998-regulators"
+                   "qcom,rpm-pms405-regulators"
 
 - vdd_s1-supply:
 - vdd_s2-supply:
@@ -188,6 +189,24 @@ Regulator nodes are identified by their compatible:
        Definition: reference to regulator supplying the input pin, as
                    described in the data sheet
 
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_s4-supply:
+- vdd_s5-supply:
+- vdd_l1_l2-supply:
+- vdd_l3_l8-supply:
+- vdd_l4-supply:
+- vdd_l5_l6-supply:
+- vdd_l7-supply:
+- vdd_l3_l8-supply:
+- vdd_l9-supply:
+- vdd_l10_l11_l12_l13-supply:
+       Usage: optional (pms405 only)
+       Value type: <phandle>
+       Definition: reference to regulator supplying the input pin, as
+                   described in the data sheet
+
 The regulator node houses sub-nodes for each regulator within the device. Each
 sub-node is identified using the node's name, with valid values listed for each
 of the pmics below.
@@ -222,6 +241,10 @@ pma8084:
 pmi8998:
        bob
 
+pms405:
+       s1, s2, s3, s4, s5, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12,
+       l13
+
 The content of each sub-node is defined by the standard binding for regulators -
 see regulator.txt.
 
index 76ead07072b130a54c84a80e88c1f965c7cc6de0..4b98ca26e61a2d0a2e64bad15193be05e849a46e 100644 (file)
@@ -1,7 +1,9 @@
-ROHM BD71837 Power Management Integrated Circuit (PMIC) regulator bindings
+ROHM BD71837 and BD71847 Power Management Integrated Circuit regulator bindings
 
 Required properties:
- - regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7"
+ - regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7" for
+                   BD71837. For BD71847 names should be "buck1", ..., "buck6"
+                  and "ldo1", ..., "ldo6"
 
 List of regulators provided by this controller. BD71837 regulators node
 should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at
@@ -16,10 +18,14 @@ disabled by driver at startup. LDO5 and LDO6 are supplied by those and
 if they are disabled at startup the voltage monitoring for LDO5/LDO6 will
 cause PMIC to reset.
 
-The valid names for regulator nodes are:
+The valid names for BD71837 regulator nodes are:
 BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8
 LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7
 
+The valid names for BD71847 regulator nodes are:
+BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6
+LDO1, LDO2, LDO3, LDO4, LDO5, LDO6
+
 Optional properties:
 - Any optional property defined in bindings/regulator/regulator.txt
 
diff --git a/Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt b/Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt
new file mode 100644 (file)
index 0000000..a3f4762
--- /dev/null
@@ -0,0 +1,68 @@
+STMicroelectronics STPMIC1 Voltage regulators
+
+Regulator Nodes are optional depending on needs.
+
+Available Regulators in STPMIC1 device are:
+  - buck1 for Buck BUCK1
+  - buck2 for Buck BUCK2
+  - buck3 for Buck BUCK3
+  - buck4 for Buck BUCK4
+  - ldo1 for LDO LDO1
+  - ldo2 for LDO LDO2
+  - ldo3 for LDO LDO3
+  - ldo4 for LDO LDO4
+  - ldo5 for LDO LDO5
+  - ldo6 for LDO LDO6
+  - vref_ddr for LDO Vref DDR
+  - boost for Buck BOOST
+  - pwr_sw1 for VBUS_OTG switch
+  - pwr_sw2 for SW_OUT switch
+
+Switches are fixed voltage regulators with only enable/disable capability.
+
+Optional properties:
+- st,mask-reset: mask reset for this regulator: the regulator configuration
+  is maintained during pmic reset.
+- regulator-pull-down: enable high pull down
+  if not specified light pull down is used
+- regulator-over-current-protection:
+    if set, all regulators are switched off in case of over-current detection
+    on this regulator,
+    if not set, the driver only sends an over-current event.
+- interrupt-parent: phandle to the parent interrupt controller
+- interrupts: index of current limit detection interrupt
+- <regulator>-supply: phandle to the parent supply/regulator node
+       each regulator supply can be described except vref_ddr.
+
+Example:
+regulators {
+       compatible = "st,stpmic1-regulators";
+
+       ldo6-supply = <&v3v3>;
+
+       vdd_core: buck1 {
+               regulator-name = "vdd_core";
+               interrupts = <IT_CURLIM_BUCK1 0>;
+               interrupt-parent = <&pmic>;
+               st,mask-reset;
+               regulator-pull-down;
+               regulator-min-microvolt = <700000>;
+               regulator-max-microvolt = <1200000>;
+       };
+
+       v3v3: buck4 {
+               regulator-name = "v3v3";
+               interrupts = <IT_CURLIM_BUCK4 0>;
+               interrupt-parent = <&mypmic>;
+
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       v1v8: ldo6 {
+               regulator-name = "v1v8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-over-current-protection;
+       };
+};
index 5e366824814fece335f41ffab2bc096642d41ab0..2e1e540f2e5a55c14bc2998b5e3e2b3d9532a035 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/physmap.h>
 #include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
 #include <linux/gpio.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
@@ -175,6 +176,7 @@ static struct resource mx21ads_mmgpio_resource =
        DEFINE_RES_MEM_NAMED(MX21ADS_IO_REG, SZ_2, "dat");
 
 static struct bgpio_pdata mx21ads_mmgpio_pdata = {
+       .label  = "mx21ads-mmgpio",
        .base   = MX21ADS_MMGPIO_BASE,
        .ngpio  = 16,
 };
@@ -203,7 +205,6 @@ static struct regulator_init_data mx21ads_lcd_regulator_init_data = {
 static struct fixed_voltage_config mx21ads_lcd_regulator_pdata = {
        .supply_name    = "LCD",
        .microvolts     = 3300000,
-       .gpio           = MX21ADS_IO_LCDON,
        .enable_high    = 1,
        .init_data      = &mx21ads_lcd_regulator_init_data,
 };
@@ -216,6 +217,14 @@ static struct platform_device mx21ads_lcd_regulator = {
        },
 };
 
+static struct gpiod_lookup_table mx21ads_lcd_regulator_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.0", /* Let's hope ID 0 is what we get */
+       .table = {
+               GPIO_LOOKUP("mx21ads-mmgpio", 9, NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 /*
  * Connected is a portrait Sharp-QVGA display
  * of type: LQ035Q7DB02
@@ -311,6 +320,7 @@ static void __init mx21ads_late_init(void)
 {
        imx21_add_mxc_mmc(0, &mx21ads_sdhc_pdata);
 
+       gpiod_add_lookup_table(&mx21ads_lcd_regulator_gpiod_table);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
        mx21ads_cs8900_resources[1].start =
index a04bb094ded1851d24537d19a7dd37494eb4464c..f5e04047ed13d2dcbec8e8e3cc48346538e03fbe 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/gpio/driver.h>
 /* Needed for gpio_to_irq() */
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -230,10 +231,17 @@ static struct regulator_init_data mx27ads_lcd_regulator_init_data = {
 static struct fixed_voltage_config mx27ads_lcd_regulator_pdata = {
        .supply_name    = "LCD",
        .microvolts     = 3300000,
-       .gpio           = MX27ADS_LCD_GPIO,
        .init_data      = &mx27ads_lcd_regulator_init_data,
 };
 
+static struct gpiod_lookup_table mx27ads_lcd_regulator_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.0", /* Let's hope ID 0 is what we get */
+       .table = {
+               GPIO_LOOKUP("LCD", 0, NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void __init mx27ads_regulator_init(void)
 {
        struct gpio_chip *vchip;
@@ -247,6 +255,8 @@ static void __init mx27ads_regulator_init(void)
        vchip->set              = vgpio_set;
        gpiochip_add_data(vchip, NULL);
 
+       gpiod_add_lookup_table(&mx27ads_lcd_regulator_gpiod_table);
+
        platform_device_register_data(NULL, "reg-fixed-voltage",
                                      PLATFORM_DEVID_AUTO,
                                      &mx27ads_lcd_regulator_pdata,
index d1613b95492636d0f7dcf6b5a393dabf51b40233..a04e249c654bc59b7c15033033a4d81f93a80fff 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/gpio-pxa.h>
+#include <linux/gpio/machine.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/max8649.h>
 #include <linux/regulator/fixed.h>
@@ -148,7 +149,6 @@ static struct regulator_init_data brownstone_v_5vp_data = {
 static struct fixed_voltage_config brownstone_v_5vp = {
        .supply_name            = "v_5vp",
        .microvolts             = 5000000,
-       .gpio                   = GPIO_5V_ENABLE,
        .enable_high            = 1,
        .enabled_at_boot        = 1,
        .init_data              = &brownstone_v_5vp_data,
@@ -162,6 +162,15 @@ static struct platform_device brownstone_v_5vp_device = {
        },
 };
 
+static struct gpiod_lookup_table brownstone_v_5vp_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.1", /* .id set to 1 above */
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_5V_ENABLE,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct max8925_platform_data brownstone_max8925_info = {
        .irq_base               = MMP_NR_IRQS,
 };
@@ -217,6 +226,7 @@ static void __init brownstone_init(void)
        mmp2_add_isram(&mmp2_isram_platdata);
 
        /* enable 5v regulator */
+       gpiod_add_lookup_table(&brownstone_v_5vp_gpiod_table);
        platform_device_register(&brownstone_v_5vp_device);
 }
 
index dd28d2614d7fecc13a49bd06a2d437ec2c88c70c..f226973f3d8cc49f057c5f264a9ce3aa19d4033f 100644 (file)
@@ -300,7 +300,6 @@ static struct regulator_init_data modem_nreset_data = {
 static struct fixed_voltage_config modem_nreset_config = {
        .supply_name            = "modem_nreset",
        .microvolts             = 3300000,
-       .gpio                   = AMS_DELTA_GPIO_PIN_MODEM_NRESET,
        .startup_delay          = 25000,
        .enable_high            = 1,
        .enabled_at_boot        = 1,
@@ -315,6 +314,15 @@ static struct platform_device modem_nreset_device = {
        },
 };
 
+static struct gpiod_lookup_table ams_delta_nreset_gpiod_table = {
+       .dev_id = "reg-fixed-voltage",
+       .table = {
+               GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_MODEM_NRESET,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 struct modem_private_data {
        struct regulator *regulator;
 };
@@ -568,7 +576,6 @@ static struct regulator_init_data keybrd_pwr_initdata = {
 static struct fixed_voltage_config keybrd_pwr_config = {
        .supply_name            = "keybrd_pwr",
        .microvolts             = 5000000,
-       .gpio                   = AMS_DELTA_GPIO_PIN_KEYBRD_PWR,
        .enable_high            = 1,
        .init_data              = &keybrd_pwr_initdata,
 };
@@ -602,6 +609,7 @@ static struct platform_device *ams_delta_devices[] __initdata = {
 };
 
 static struct gpiod_lookup_table *ams_delta_gpio_tables[] __initdata = {
+       &ams_delta_nreset_gpiod_table,
        &ams_delta_audio_gpio_table,
        &keybrd_pwr_gpio_table,
        &ams_delta_lcd_gpio_table,
index 7f02743edbe4c7880bb12feccb4d6a1683ca276d..d0f7a7cc70cbeab7f8fc16019ffae7c5acb79124 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/davinci_emac.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/of_platform.h>
@@ -328,7 +329,6 @@ static struct regulator_init_data pandora_vmmc3 = {
 static struct fixed_voltage_config pandora_vwlan = {
        .supply_name            = "vwlan",
        .microvolts             = 1800000, /* 1.8V */
-       .gpio                   = PANDORA_WIFI_NRESET_GPIO,
        .startup_delay          = 50000, /* 50ms */
        .enable_high            = 1,
        .init_data              = &pandora_vmmc3,
@@ -342,6 +342,19 @@ static struct platform_device pandora_vwlan_device = {
        },
 };
 
+static struct gpiod_lookup_table pandora_vwlan_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.1",
+       .table = {
+               /*
+                * As this is a low GPIO number it should be at the first
+                * GPIO bank.
+                */
+               GPIO_LOOKUP("gpio-0-31", PANDORA_WIFI_NRESET_GPIO,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void pandora_wl1251_init_card(struct mmc_card *card)
 {
        /*
@@ -403,6 +416,7 @@ fail:
 static void __init omap3_pandora_legacy_init(void)
 {
        platform_device_register(&pandora_backlight);
+       gpiod_add_lookup_table(&pandora_vwlan_gpiod_table);
        platform_device_register(&pandora_vwlan_device);
        omap_hsmmc_init(pandora_mmc3);
        omap_hsmmc_late_init(pandora_mmc3);
index c30d20e1fb7a1ca60c7d58c8fa61feccbd76deac..67e37df637f5ca23e7038d1c866d26ab50a40746 100644 (file)
@@ -984,7 +984,6 @@ static struct fixed_voltage_config camera_dummy_config = {
        .supply_name            = "camera_vdd",
        .input_supply           = "vcc cam",
        .microvolts             = 2800000,
-       .gpio                   = -1,
        .enable_high            = 0,
        .init_data              = &camera_dummy_initdata,
 };
index 2c90b58f347d9efe9ffcec1c677aecedd75b450a..565965e9acc7e807079919243877d300df344a65 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds-lp3944.h>
 #include <linux/platform_data/i2c-pxa.h>
@@ -698,31 +699,39 @@ static struct pxa27x_keypad_platform_data e2_keypad_platform_data = {
 
 #if defined(CONFIG_MACH_EZX_A780) || defined(CONFIG_MACH_EZX_A910)
 /* camera */
-static struct regulator_consumer_supply camera_dummy_supplies[] = {
+static struct regulator_consumer_supply camera_regulator_supplies[] = {
        REGULATOR_SUPPLY("vdd", "0-005d"),
 };
 
-static struct regulator_init_data camera_dummy_initdata = {
-       .consumer_supplies = camera_dummy_supplies,
-       .num_consumer_supplies = ARRAY_SIZE(camera_dummy_supplies),
+static struct regulator_init_data camera_regulator_initdata = {
+       .consumer_supplies = camera_regulator_supplies,
+       .num_consumer_supplies = ARRAY_SIZE(camera_regulator_supplies),
        .constraints = {
                .valid_ops_mask = REGULATOR_CHANGE_STATUS,
        },
 };
 
-static struct fixed_voltage_config camera_dummy_config = {
+static struct fixed_voltage_config camera_regulator_config = {
        .supply_name            = "camera_vdd",
        .microvolts             = 2800000,
-       .gpio                   = GPIO50_nCAM_EN,
        .enable_high            = 0,
-       .init_data              = &camera_dummy_initdata,
+       .init_data              = &camera_regulator_initdata,
 };
 
-static struct platform_device camera_supply_dummy_device = {
+static struct platform_device camera_supply_regulator_device = {
        .name   = "reg-fixed-voltage",
        .id     = 1,
        .dev    = {
-               .platform_data = &camera_dummy_config,
+               .platform_data = &camera_regulator_config,
+       },
+};
+
+static struct gpiod_lookup_table camera_supply_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.1",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO50_nCAM_EN,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
        },
 };
 #endif
@@ -800,7 +809,7 @@ static struct i2c_board_info a780_i2c_board_info[] = {
 
 static struct platform_device *a780_devices[] __initdata = {
        &a780_gpio_keys,
-       &camera_supply_dummy_device,
+       &camera_supply_regulator_device,
 };
 
 static void __init a780_init(void)
@@ -823,6 +832,7 @@ static void __init a780_init(void)
        if (a780_camera_init() == 0)
                pxa_set_camera_info(&a780_pxacamera_platform_data);
 
+       gpiod_add_lookup_table(&camera_supply_gpiod_table);
        pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(a780_devices));
@@ -1098,7 +1108,7 @@ static struct i2c_board_info __initdata a910_i2c_board_info[] = {
 
 static struct platform_device *a910_devices[] __initdata = {
        &a910_gpio_keys,
-       &camera_supply_dummy_device,
+       &camera_supply_regulator_device,
 };
 
 static void __init a910_init(void)
@@ -1121,6 +1131,7 @@ static void __init a910_init(void)
        if (a910_camera_init() == 0)
                pxa_set_camera_info(&a910_pxacamera_platform_data);
 
+       gpiod_add_lookup_table(&camera_supply_gpiod_table);
        pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
        platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
        platform_add_devices(ARRAY_AND_SIZE(a910_devices));
index c5325d1ae77b5015832eb8ff3783061f8246af81..14c0f80bc9e7cf1c7d00e73e65c8eb20e71760f7 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/mfd/htc-pasic3.h>
@@ -696,7 +697,6 @@ static struct regulator_init_data vads7846_regulator = {
 static struct fixed_voltage_config vads7846 = {
        .supply_name    = "vads7846",
        .microvolts     = 3300000, /* probably */
-       .gpio           = -EINVAL,
        .startup_delay  = 0,
        .init_data      = &vads7846_regulator,
 };
index 034345546f84a575a823cdb25b4953bf1e9f141b..bd3c23ad6ce60cb5be94d9548830b2e931eb86a3 100644 (file)
@@ -886,7 +886,6 @@ static struct regulator_init_data audio_va_initdata = {
 static struct fixed_voltage_config audio_va_config = {
        .supply_name            = "audio_va",
        .microvolts             = 5000000,
-       .gpio                   = GPIO_AUDIO_VA_ENABLE,
        .enable_high            = 1,
        .enabled_at_boot        = 0,
        .init_data              = &audio_va_initdata,
@@ -900,6 +899,15 @@ static struct platform_device audio_va_device = {
        },
 };
 
+static struct gpiod_lookup_table audio_va_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_AUDIO_VA_ENABLE,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 /* Dummy supplies for Codec's VD/VLC */
 
 static struct regulator_consumer_supply audio_dummy_supplies[] = {
@@ -918,7 +926,6 @@ static struct regulator_init_data audio_dummy_initdata = {
 static struct fixed_voltage_config audio_dummy_config = {
        .supply_name            = "audio_vd",
        .microvolts             = 3300000,
-       .gpio                   = -1,
        .init_data              = &audio_dummy_initdata,
 };
 
@@ -1033,6 +1040,7 @@ static void __init raumfeld_audio_init(void)
        else
                gpio_direction_output(GPIO_MCLK_RESET, 1);
 
+       gpiod_add_lookup_table(&audio_va_gpiod_table);
        platform_add_devices(ARRAY_AND_SIZE(audio_regulator_devices));
 }
 
index e3851795d6d7d5127679093f8f318f39ee976234..d53ea12fc76662cad69d5184472f9cfad3e5bf07 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/irq.h>
 #include <linux/pm.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/serial_8250.h>
 #include <linux/dm9000.h>
 #include <linux/mmc/host.h>
@@ -410,7 +411,6 @@ static struct regulator_init_data can_regulator_init_data = {
 static struct fixed_voltage_config can_regulator_pdata = {
        .supply_name    = "CAN_SHDN",
        .microvolts     = 3300000,
-       .gpio           = ZEUS_CAN_SHDN_GPIO,
        .init_data      = &can_regulator_init_data,
 };
 
@@ -422,6 +422,15 @@ static struct platform_device can_regulator_device = {
        },
 };
 
+static struct gpiod_lookup_table can_regulator_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", ZEUS_CAN_SHDN_GPIO,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct mcp251x_platform_data zeus_mcp2515_pdata = {
        .oscillator_frequency   = 16*1000*1000,
 };
@@ -538,7 +547,6 @@ static struct regulator_init_data zeus_ohci_regulator_data = {
 static struct fixed_voltage_config zeus_ohci_regulator_config = {
        .supply_name            = "vbus2",
        .microvolts             = 5000000, /* 5.0V */
-       .gpio                   = ZEUS_USB2_PWREN_GPIO,
        .enable_high            = 1,
        .startup_delay          = 0,
        .init_data              = &zeus_ohci_regulator_data,
@@ -552,6 +560,15 @@ static struct platform_device zeus_ohci_regulator_device = {
        },
 };
 
+static struct gpiod_lookup_table zeus_ohci_regulator_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", ZEUS_USB2_PWREN_GPIO,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct pxaohci_platform_data zeus_ohci_platform_data = {
        .port_mode      = PMM_NPS_MODE,
        /* Clear Power Control Polarity Low and set Power Sense
@@ -855,6 +872,8 @@ static void __init zeus_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(zeus_pin_config));
 
+       gpiod_add_lookup_table(&can_regulator_gpiod_table);
+       gpiod_add_lookup_table(&zeus_ohci_regulator_gpiod_table);
        platform_add_devices(zeus_devices, ARRAY_SIZE(zeus_devices));
 
        zeus_register_ohci();
index f0465029748726ab53691daf3de8686e663c3dfa..379424d72ae707dfd3879ac56b945d184a350c41 100644 (file)
@@ -352,7 +352,6 @@ static struct fixed_voltage_config wallvdd_pdata = {
        .supply_name = "WALLVDD",
        .microvolts = 5000000,
        .init_data = &wallvdd_data,
-       .gpio = -EINVAL,
 };
 
 static struct platform_device wallvdd_device = {
index c46fa5dfd2e00420aca1c35398556c0da47fc634..908e5aa831c81cb234e145e29189a1659e62908a 100644 (file)
@@ -222,7 +222,6 @@ static struct fixed_voltage_config smdk6410_b_pwr_5v_pdata = {
        .supply_name = "B_PWR_5V",
        .microvolts = 5000000,
        .init_data = &smdk6410_b_pwr_5v_data,
-       .gpio = -EINVAL,
 };
 
 static struct platform_device smdk6410_b_pwr_5v = {
index 575ec085cffaf78cac62c3f38f21f147037c0e46..3e8c0948abcc3ef52e557429211936268e4cf034 100644 (file)
@@ -101,7 +101,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val)
 
        assabet_bcr_gc = gc;
 
-       return gc->base;
+       return 0;
 }
 
 /*
@@ -471,6 +471,14 @@ static struct fixed_voltage_config assabet_cf_vcc_pdata __initdata = {
        .enable_high = 1,
 };
 
+static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = {
+       .dev_id = "reg-fixed-voltage.0",
+       .table = {
+               GPIO_LOOKUP("assabet", 0, NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void __init assabet_init(void)
 {
        /*
@@ -517,9 +525,11 @@ static void __init assabet_init(void)
                        neponset_resources, ARRAY_SIZE(neponset_resources));
 #endif
        } else {
+               gpiod_add_lookup_table(&assabet_cf_vcc_gpio_table);
                sa11x0_register_fixed_regulator(0, &assabet_cf_vcc_pdata,
-                                        assabet_cf_vcc_consumers,
-                                        ARRAY_SIZE(assabet_cf_vcc_consumers));
+                                       assabet_cf_vcc_consumers,
+                                       ARRAY_SIZE(assabet_cf_vcc_consumers),
+                                       true);
 
        }
 
@@ -802,7 +812,6 @@ fs_initcall(assabet_leds_init);
 
 void __init assabet_init_irq(void)
 {
-       unsigned int assabet_gpio_base;
        u32 def_val;
 
        sa1100_init_irq();
@@ -817,9 +826,7 @@ void __init assabet_init_irq(void)
         *
         * This must precede any driver calls to BCR_set() or BCR_clear().
         */
-       assabet_gpio_base = assabet_init_gpio((void *)&ASSABET_BCR, def_val);
-
-       assabet_cf_vcc_pdata.gpio = assabet_gpio_base + 0;
+       assabet_init_gpio((void *)&ASSABET_BCR, def_val);
 }
 
 MACHINE_START(ASSABET, "Intel-Assabet")
index 7167ddf84a0ee9b6a7d721a3a8658be663798d56..800321c6cbd8cf5edb209904b52634292f35c735 100644 (file)
@@ -348,7 +348,8 @@ void __init sa11x0_init_late(void)
 
 int __init sa11x0_register_fixed_regulator(int n,
        struct fixed_voltage_config *cfg,
-       struct regulator_consumer_supply *supplies, unsigned num_supplies)
+       struct regulator_consumer_supply *supplies, unsigned num_supplies,
+       bool uses_gpio)
 {
        struct regulator_init_data *id;
 
@@ -356,7 +357,7 @@ int __init sa11x0_register_fixed_regulator(int n,
        if (!cfg->init_data)
                return -ENOMEM;
 
-       if (cfg->gpio < 0)
+       if (!uses_gpio)
                id->constraints.always_on = 1;
        id->constraints.name = cfg->supply_name;
        id->constraints.min_uV = cfg->microvolts;
index 5f3cb52fa6ab1c16cf7cf8c0f20d34fd8ee82eb2..158a4fd5ca2472027886bd4b30493e412c52a191 100644 (file)
@@ -54,4 +54,5 @@ void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *);
 struct fixed_voltage_config;
 struct regulator_consumer_supply;
 int sa11x0_register_fixed_regulator(int n, struct fixed_voltage_config *cfg,
-       struct regulator_consumer_supply *supplies, unsigned num_supplies);
+       struct regulator_consumer_supply *supplies, unsigned num_supplies,
+       bool uses_gpio);
index 22f7fe0b809fdd7839a447830c6e3935cfde0dda..5bc82e2671c6e69944d11f8d55446873e442a274 100644 (file)
@@ -102,14 +102,14 @@ static struct fixed_voltage_config shannon_cf_vcc_pdata __initdata = {
        .supply_name = "cf-power",
        .microvolts = 3300000,
        .enabled_at_boot = 1,
-       .gpio = -EINVAL,
 };
 
 static void __init shannon_init(void)
 {
        sa11x0_register_fixed_regulator(0, &shannon_cf_vcc_pdata,
                                        shannon_cf_vcc_consumers,
-                                       ARRAY_SIZE(shannon_cf_vcc_consumers));
+                                       ARRAY_SIZE(shannon_cf_vcc_consumers),
+                                       false);
        sa11x0_register_pcmcia(0, &shannon_pcmcia0_gpio_table);
        sa11x0_register_pcmcia(1, &shannon_pcmcia1_gpio_table);
        sa11x0_ppc_configure_mcp();
index adc61d14172c63b8dd1ac2193373c24b1c5d4db4..06a894526a0b55fd972281ce43a973cdf8c9eea3 100644 (file)
@@ -633,7 +633,6 @@ static struct regulator_init_data cn12_power_init_data = {
 static struct fixed_voltage_config cn12_power_info = {
        .supply_name = "CN12 SD/MMC Vdd",
        .microvolts = 3300000,
-       .gpio = GPIO_PTB7,
        .enable_high = 1,
        .init_data = &cn12_power_init_data,
 };
@@ -646,6 +645,16 @@ static struct platform_device cn12_power = {
        },
 };
 
+static struct gpiod_lookup_table cn12_power_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.0",
+       .table = {
+               /* Offset 7 on port B */
+               GPIO_LOOKUP("sh7724_pfc", GPIO_PTB7,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
 /* SDHI0 */
 static struct regulator_consumer_supply sdhi0_power_consumers[] =
@@ -665,7 +674,6 @@ static struct regulator_init_data sdhi0_power_init_data = {
 static struct fixed_voltage_config sdhi0_power_info = {
        .supply_name = "CN11 SD/MMC Vdd",
        .microvolts = 3300000,
-       .gpio = GPIO_PTB6,
        .enable_high = 1,
        .init_data = &sdhi0_power_init_data,
 };
@@ -678,6 +686,16 @@ static struct platform_device sdhi0_power = {
        },
 };
 
+static struct gpiod_lookup_table sdhi0_power_gpiod_table = {
+       .dev_id = "reg-fixed-voltage.1",
+       .table = {
+               /* Offset 6 on port B */
+               GPIO_LOOKUP("sh7724_pfc", GPIO_PTB6,
+                           NULL, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct tmio_mmc_data sdhi0_info = {
        .chan_priv_tx   = (void *)SHDMA_SLAVE_SDHI0_TX,
        .chan_priv_rx   = (void *)SHDMA_SLAVE_SDHI0_RX,
@@ -1413,6 +1431,11 @@ static int __init arch_setup(void)
                                    DMA_MEMORY_EXCLUSIVE);
        platform_device_add(ecovec_ceu_devices[1]);
 
+       gpiod_add_lookup_table(&cn12_power_gpiod_table);
+#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
+       gpiod_add_lookup_table(&sdhi0_power_gpiod_table);
+#endif
+
        return platform_add_devices(ecovec_devices,
                                    ARRAY_SIZE(ecovec_devices));
 }
index 4392c15ed9e0785878bd0498d2eb83b87122e9ac..dbfc5cf2aa9310b62f405bb1cd53fc89a7ad4a00 100644 (file)
@@ -10,7 +10,7 @@
  * of the License.
  */
 
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
@@ -43,7 +43,6 @@ static struct fixed_voltage_config bcm43xx_vmmc = {
         * real voltage and signaling are still 1.8V.
         */
        .microvolts             = 2000000,              /* 1.8V */
-       .gpio                   = -EINVAL,
        .startup_delay          = 250 * 1000,           /* 250ms */
        .enable_high            = 1,                    /* active high */
        .enabled_at_boot        = 0,                    /* disabled at boot */
@@ -58,11 +57,23 @@ static struct platform_device bcm43xx_vmmc_regulator = {
        },
 };
 
+static struct gpiod_lookup_table bcm43xx_vmmc_gpio_table = {
+       .dev_id = "reg-fixed-voltage.0",
+       .table  = {
+               GPIO_LOOKUP("0000:00:0c.0", -1, NULL, GPIO_ACTIVE_LOW),
+               {}
+       },
+};
+
 static int __init bcm43xx_regulator_register(void)
 {
+       struct gpiod_lookup_table *table = &bcm43xx_vmmc_gpio_table;
+       struct gpiod_lookup *lookup = table->table;
        int ret;
 
-       bcm43xx_vmmc.gpio = get_gpio_by_name(WLAN_SFI_GPIO_ENABLE_NAME);
+       lookup[0].chip_hwnum = get_gpio_by_name(WLAN_SFI_GPIO_ENABLE_NAME);
+       gpiod_add_lookup_table(table);
+
        ret = platform_device_register(&bcm43xx_vmmc_regulator);
        if (ret) {
                pr_err("%s: vmmc regulator register failed\n", __func__);
index 25187403e3ace0d891feaa3b59923efbcdb45a7a..db1f4b2b092dccae1919d9791444b76b4b9dfdec 100644 (file)
@@ -3909,8 +3909,23 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
         * the device name as label
         */
        status = gpiod_request(desc, con_id ? con_id : devname);
-       if (status < 0)
-               return ERR_PTR(status);
+       if (status < 0) {
+               if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
+                       /*
+                        * This happens when there are several consumers for
+                        * the same GPIO line: we just return here without
+                        * further initialization. It is a bit if a hack.
+                        * This is necessary to support fixed regulators.
+                        *
+                        * FIXME: Make this more sane and safe.
+                        */
+                       dev_info(dev, "nonexclusive access to GPIO for %s\n",
+                                con_id ? con_id : devname);
+                       return desc;
+               } else {
+                       return ERR_PTR(status);
+               }
+       }
 
        status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
        if (status < 0) {
index 75c8ec659547ca0e234855efff23739513d271bc..a29d529a96f4af7e4a389da280cf7d691c6845dc 100644 (file)
@@ -2,26 +2,21 @@
 //
 // Copyright (C) 2018 ROHM Semiconductors
 //
-// ROHM BD71837MWV PMIC driver
+// ROHM BD71837MWV and BD71847MWV PMIC driver
 //
-// Datasheet available from
+// Datasheet for BD71837MWV available from
 // https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
 
+#include <linux/gpio_keys.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/rohm-bd718x7.h>
 #include <linux/mfd/core.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/regmap.h>
-
-/*
- * gpio_keys.h requires definiton of bool. It is brought in
- * by above includes. Keep this as last until gpio_keys.h gets fixed.
- */
-#include <linux/gpio_keys.h>
-
-static const u8 supported_revisions[] = { 0xA2 /* BD71837 */ };
+#include <linux/types.h>
 
 static struct gpio_keys_button button = {
        .code = KEY_POWER,
@@ -35,42 +30,42 @@ static struct gpio_keys_platform_data bd718xx_powerkey_data = {
        .name = "bd718xx-pwrkey",
 };
 
-static struct mfd_cell bd71837_mfd_cells[] = {
+static struct mfd_cell bd718xx_mfd_cells[] = {
        {
                .name = "gpio-keys",
                .platform_data = &bd718xx_powerkey_data,
                .pdata_size = sizeof(bd718xx_powerkey_data),
        },
-       { .name = "bd71837-clk", },
-       { .name = "bd71837-pmic", },
+       { .name = "bd718xx-clk", },
+       { .name = "bd718xx-pmic", },
 };
 
-static const struct regmap_irq bd71837_irqs[] = {
-       REGMAP_IRQ_REG(BD71837_INT_SWRST, 0, BD71837_INT_SWRST_MASK),
-       REGMAP_IRQ_REG(BD71837_INT_PWRBTN_S, 0, BD71837_INT_PWRBTN_S_MASK),
-       REGMAP_IRQ_REG(BD71837_INT_PWRBTN_L, 0, BD71837_INT_PWRBTN_L_MASK),
-       REGMAP_IRQ_REG(BD71837_INT_PWRBTN, 0, BD71837_INT_PWRBTN_MASK),
-       REGMAP_IRQ_REG(BD71837_INT_WDOG, 0, BD71837_INT_WDOG_MASK),
-       REGMAP_IRQ_REG(BD71837_INT_ON_REQ, 0, BD71837_INT_ON_REQ_MASK),
-       REGMAP_IRQ_REG(BD71837_INT_STBY_REQ, 0, BD71837_INT_STBY_REQ_MASK),
+static const struct regmap_irq bd718xx_irqs[] = {
+       REGMAP_IRQ_REG(BD718XX_INT_SWRST, 0, BD718XX_INT_SWRST_MASK),
+       REGMAP_IRQ_REG(BD718XX_INT_PWRBTN_S, 0, BD718XX_INT_PWRBTN_S_MASK),
+       REGMAP_IRQ_REG(BD718XX_INT_PWRBTN_L, 0, BD718XX_INT_PWRBTN_L_MASK),
+       REGMAP_IRQ_REG(BD718XX_INT_PWRBTN, 0, BD718XX_INT_PWRBTN_MASK),
+       REGMAP_IRQ_REG(BD718XX_INT_WDOG, 0, BD718XX_INT_WDOG_MASK),
+       REGMAP_IRQ_REG(BD718XX_INT_ON_REQ, 0, BD718XX_INT_ON_REQ_MASK),
+       REGMAP_IRQ_REG(BD718XX_INT_STBY_REQ, 0, BD718XX_INT_STBY_REQ_MASK),
 };
 
-static struct regmap_irq_chip bd71837_irq_chip = {
-       .name = "bd71837-irq",
-       .irqs = bd71837_irqs,
-       .num_irqs = ARRAY_SIZE(bd71837_irqs),
+static struct regmap_irq_chip bd718xx_irq_chip = {
+       .name = "bd718xx-irq",
+       .irqs = bd718xx_irqs,
+       .num_irqs = ARRAY_SIZE(bd718xx_irqs),
        .num_regs = 1,
        .irq_reg_stride = 1,
-       .status_base = BD71837_REG_IRQ,
-       .mask_base = BD71837_REG_MIRQ,
-       .ack_base = BD71837_REG_IRQ,
+       .status_base = BD718XX_REG_IRQ,
+       .mask_base = BD718XX_REG_MIRQ,
+       .ack_base = BD718XX_REG_IRQ,
        .init_ack_masked = true,
        .mask_invert = false,
 };
 
 static const struct regmap_range pmic_status_range = {
-       .range_min = BD71837_REG_IRQ,
-       .range_max = BD71837_REG_POW_STATE,
+       .range_min = BD718XX_REG_IRQ,
+       .range_max = BD718XX_REG_POW_STATE,
 };
 
 static const struct regmap_access_table volatile_regs = {
@@ -78,67 +73,53 @@ static const struct regmap_access_table volatile_regs = {
        .n_yes_ranges = 1,
 };
 
-static const struct regmap_config bd71837_regmap_config = {
+static const struct regmap_config bd718xx_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
        .volatile_table = &volatile_regs,
-       .max_register = BD71837_MAX_REGISTER - 1,
+       .max_register = BD718XX_MAX_REGISTER - 1,
        .cache_type = REGCACHE_RBTREE,
 };
 
-static int bd71837_i2c_probe(struct i2c_client *i2c,
+static int bd718xx_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
-       struct bd71837 *bd71837;
-       int ret, i;
-       unsigned int val;
-
-       bd71837 = devm_kzalloc(&i2c->dev, sizeof(struct bd71837), GFP_KERNEL);
+       struct bd718xx *bd718xx;
+       int ret;
 
-       if (!bd71837)
-               return -ENOMEM;
-
-       bd71837->chip_irq = i2c->irq;
-
-       if (!bd71837->chip_irq) {
+       if (!i2c->irq) {
                dev_err(&i2c->dev, "No IRQ configured\n");
                return -EINVAL;
        }
 
-       bd71837->dev = &i2c->dev;
-       dev_set_drvdata(&i2c->dev, bd71837);
+       bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL);
 
-       bd71837->regmap = devm_regmap_init_i2c(i2c, &bd71837_regmap_config);
-       if (IS_ERR(bd71837->regmap)) {
-               dev_err(&i2c->dev, "regmap initialization failed\n");
-               return PTR_ERR(bd71837->regmap);
-       }
+       if (!bd718xx)
+               return -ENOMEM;
 
-       ret = regmap_read(bd71837->regmap, BD71837_REG_REV, &val);
-       if (ret) {
-               dev_err(&i2c->dev, "Read BD71837_REG_DEVICE failed\n");
-               return ret;
-       }
-       for (i = 0; i < ARRAY_SIZE(supported_revisions); i++)
-               if (supported_revisions[i] == val)
-                       break;
+       bd718xx->chip_irq = i2c->irq;
+       bd718xx->chip_type = (unsigned int)(uintptr_t)
+                               of_device_get_match_data(&i2c->dev);
+       bd718xx->dev = &i2c->dev;
+       dev_set_drvdata(&i2c->dev, bd718xx);
 
-       if (i == ARRAY_SIZE(supported_revisions)) {
-               dev_err(&i2c->dev, "Unsupported chip revision\n");
-               return -ENODEV;
+       bd718xx->regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config);
+       if (IS_ERR(bd718xx->regmap)) {
+               dev_err(&i2c->dev, "regmap initialization failed\n");
+               return PTR_ERR(bd718xx->regmap);
        }
 
-       ret = devm_regmap_add_irq_chip(&i2c->dev, bd71837->regmap,
-                                      bd71837->chip_irq, IRQF_ONESHOT, 0,
-                                      &bd71837_irq_chip, &bd71837->irq_data);
+       ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->regmap,
+                                      bd718xx->chip_irq, IRQF_ONESHOT, 0,
+                                      &bd718xx_irq_chip, &bd718xx->irq_data);
        if (ret) {
                dev_err(&i2c->dev, "Failed to add irq_chip\n");
                return ret;
        }
 
        /* Configure short press to 10 milliseconds */
-       ret = regmap_update_bits(bd71837->regmap,
-                                BD71837_REG_PWRONCONFIG0,
+       ret = regmap_update_bits(bd718xx->regmap,
+                                BD718XX_REG_PWRONCONFIG0,
                                 BD718XX_PWRBTN_PRESS_DURATION_MASK,
                                 BD718XX_PWRBTN_SHORT_PRESS_10MS);
        if (ret) {
@@ -148,8 +129,8 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
        }
 
        /* Configure long press to 10 seconds */
-       ret = regmap_update_bits(bd71837->regmap,
-                                BD71837_REG_PWRONCONFIG1,
+       ret = regmap_update_bits(bd718xx->regmap,
+                                BD718XX_REG_PWRONCONFIG1,
                                 BD718XX_PWRBTN_PRESS_DURATION_MASK,
                                 BD718XX_PWRBTN_LONG_PRESS_10S);
 
@@ -159,7 +140,7 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       ret = regmap_irq_get_virq(bd71837->irq_data, BD71837_INT_PWRBTN_S);
+       ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
 
        if (ret < 0) {
                dev_err(&i2c->dev, "Failed to get the IRQ\n");
@@ -168,44 +149,51 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
 
        button.irq = ret;
 
-       ret = devm_mfd_add_devices(bd71837->dev, PLATFORM_DEVID_AUTO,
-                                  bd71837_mfd_cells,
-                                  ARRAY_SIZE(bd71837_mfd_cells), NULL, 0,
-                                  regmap_irq_get_domain(bd71837->irq_data));
+       ret = devm_mfd_add_devices(bd718xx->dev, PLATFORM_DEVID_AUTO,
+                                  bd718xx_mfd_cells,
+                                  ARRAY_SIZE(bd718xx_mfd_cells), NULL, 0,
+                                  regmap_irq_get_domain(bd718xx->irq_data));
        if (ret)
                dev_err(&i2c->dev, "Failed to create subdevices\n");
 
        return ret;
 }
 
-static const struct of_device_id bd71837_of_match[] = {
-       { .compatible = "rohm,bd71837", },
+static const struct of_device_id bd718xx_of_match[] = {
+       {
+               .compatible = "rohm,bd71837",
+               .data = (void *)BD718XX_TYPE_BD71837,
+       },
+       {
+               .compatible = "rohm,bd71847",
+               .data = (void *)BD718XX_TYPE_BD71847,
+       },
        { }
 };
-MODULE_DEVICE_TABLE(of, bd71837_of_match);
+MODULE_DEVICE_TABLE(of, bd718xx_of_match);
 
-static struct i2c_driver bd71837_i2c_driver = {
+static struct i2c_driver bd718xx_i2c_driver = {
        .driver = {
                .name = "rohm-bd718x7",
-               .of_match_table = bd71837_of_match,
+               .of_match_table = bd718xx_of_match,
        },
-       .probe = bd71837_i2c_probe,
+       .probe = bd718xx_i2c_probe,
 };
 
-static int __init bd71837_i2c_init(void)
+static int __init bd718xx_i2c_init(void)
 {
-       return i2c_add_driver(&bd71837_i2c_driver);
+       return i2c_add_driver(&bd718xx_i2c_driver);
 }
 
 /* Initialise early so consumer devices can complete system boot */
-subsys_initcall(bd71837_i2c_init);
+subsys_initcall(bd718xx_i2c_init);
 
-static void __exit bd71837_i2c_exit(void)
+static void __exit bd718xx_i2c_exit(void)
 {
-       i2c_del_driver(&bd71837_i2c_driver);
+       i2c_del_driver(&bd718xx_i2c_driver);
 }
-module_exit(bd71837_i2c_exit);
+module_exit(bd718xx_i2c_exit);
 
 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("ROHM BD71837 Power Management IC driver");
+MODULE_DESCRIPTION("ROHM BD71837/BD71847 Power Management IC driver");
 MODULE_LICENSE("GPL");
index 329cdd33ed624b8dc06ad1a72dee73009e630095..926cee0d0b5f98c145069baf5ced0cf60f39ff49 100644 (file)
@@ -189,7 +189,7 @@ config REGULATOR_BD718XX
          and LDO regulators.
 
          This driver can also be built as a module. If so, the module
-         will be called bd71837-regulator.
+         will be called bd718x7-regulator.
 
 config REGULATOR_BD9571MWV
        tristate "ROHM BD9571MWV Regulators"
@@ -356,6 +356,13 @@ config REGULATOR_LM363X
          One boost output voltage is configurable and always on.
          Other LDOs are used for the display module.
 
+config REGULATOR_LOCHNAGAR
+       tristate "Cirrus Logic Lochnagar regulator driver"
+       depends on MFD_LOCHNAGAR
+       help
+         This enables regulator support on the Cirrus Logic Lochnagar audio
+         development board.
+
 config REGULATOR_LP3971
        tristate "National Semiconductors LP3971 PMIC regulator driver"
        depends on I2C
@@ -803,6 +810,18 @@ config REGULATOR_STM32_VREFBUF
          This driver can also be built as a module. If so, the module
          will be called stm32-vrefbuf.
 
+config REGULATOR_STPMIC1
+       tristate "STMicroelectronics STPMIC1 PMIC Regulators"
+       depends on MFD_STPMIC1
+       help
+         This driver supports STMicroelectronics STPMIC1 PMIC voltage
+         regulators and switches. The STPMIC1 regulators supply power to
+         an application processor as well as to external system
+         peripherals such as DDR, Flash memories and system devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called stpmic1_regulator.
+
 config REGULATOR_TI_ABB
        tristate "TI Adaptive Body Bias on-chip LDO"
        depends on ARCH_OMAP
index 801d9a34a2037c5b7c7bb8e8c93a62ad1a9aebf1..72488ef11b8ad495b0e9a5b5293e56a6c11e3ca9 100644 (file)
@@ -27,7 +27,7 @@ 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_BD718XX) += bd71837-regulator.o
+obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
@@ -46,6 +46,7 @@ obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
 obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
+obj-$(CONFIG_REGULATOR_LOCHNAGAR) += lochnagar-regulator.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
 obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
@@ -101,6 +102,7 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
 obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
+obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
index e976d073f28d6ffa1562d0a7e39f6b979b926a4c..9a72eae4926d5ceabad10d478851bedb604bfef1 100644 (file)
@@ -260,7 +260,7 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
         * so clean up would happen at the wrong time
         */
        config.ena_gpiod = gpiod_get_optional(parent_dev, "wlf,ldoena",
-                                             GPIOD_OUT_LOW);
+                               GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
        if (IS_ERR(config.ena_gpiod))
                return PTR_ERR(config.ena_gpiod);
 
index 91b8ff8bac157de97e83974dcb4a2512ea3f0741..a3734039a86a7897c35d69f4f536dc94f8f27b29 100644 (file)
@@ -509,10 +509,10 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
                /*
                 * AXP803/AXP813 DCDC work frequency setting has the same
                 * range and step as AXP22X, but at a different register.
-                * Fall through to the check below.
                 * (See include/linux/mfd/axp20x.h)
                 */
                reg = AXP803_DCDC_FREQ_CTRL;
+               /* Fall through to the check below.*/
        case AXP806_ID:
                /*
                 * AXP806 also have DCDC work frequency setting register at a
@@ -520,6 +520,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
                 */
                if (axp20x->variant == AXP806_ID)
                        reg = AXP806_DCDC_FREQ_CTRL;
+               /* Fall through */
        case AXP221_ID:
        case AXP223_ID:
        case AXP809_ID:
diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c
deleted file mode 100644 (file)
index a1bd8aa..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2018 ROHM Semiconductors
-// bd71837-regulator.c ROHM BD71837MWV regulator driver
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/mfd/rohm-bd718x7.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/of_regulator.h>
-#include <linux/slab.h>
-
-struct bd71837_pmic {
-       struct regulator_desc descs[BD71837_REGULATOR_CNT];
-       struct bd71837 *mfd;
-       struct platform_device *pdev;
-       struct regulator_dev *rdev[BD71837_REGULATOR_CNT];
-};
-
-/*
- * BUCK1/2/3/4
- * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
- * 00: 10.00mV/usec 10mV 1uS
- * 01: 5.00mV/usec     10mV 2uS
- * 10: 2.50mV/usec     10mV 4uS
- * 11: 1.25mV/usec     10mV 8uS
- */
-static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev,
-                                          int ramp_delay)
-{
-       struct bd71837_pmic *pmic = rdev_get_drvdata(rdev);
-       struct bd71837 *mfd = pmic->mfd;
-       int id = rdev->desc->id;
-       unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
-
-       dev_dbg(&pmic->pdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
-               ramp_delay);
-       switch (ramp_delay) {
-       case 1 ... 1250:
-               ramp_value = BUCK_RAMPRATE_1P25MV;
-               break;
-       case 1251 ... 2500:
-               ramp_value = BUCK_RAMPRATE_2P50MV;
-               break;
-       case 2501 ... 5000:
-               ramp_value = BUCK_RAMPRATE_5P00MV;
-               break;
-       case 5001 ... 10000:
-               ramp_value = BUCK_RAMPRATE_10P00MV;
-               break;
-       default:
-               ramp_value = BUCK_RAMPRATE_10P00MV;
-               dev_err(&pmic->pdev->dev,
-                       "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
-                       rdev->desc->name, ramp_delay);
-       }
-
-       return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id,
-                                 BUCK_RAMPRATE_MASK, ramp_value << 6);
-}
-
-/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed.
- * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage
- * is changed. Hence we return -EBUSY for these if voltage is changed
- * when BUCK/LDO is enabled.
- */
-static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
-                                                   unsigned int sel)
-{
-       if (regulator_is_enabled_regmap(rdev))
-               return -EBUSY;
-
-       return regulator_set_voltage_sel_regmap(rdev, sel);
-}
-
-static struct regulator_ops bd71837_ldo_regulator_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
-       .list_voltage = regulator_list_voltage_linear_range,
-       .set_voltage_sel = bd71837_set_voltage_sel_restricted,
-       .get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
-
-static struct regulator_ops bd71837_ldo_regulator_nolinear_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
-       .list_voltage = regulator_list_voltage_table,
-       .set_voltage_sel = bd71837_set_voltage_sel_restricted,
-       .get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
-
-static struct regulator_ops bd71837_buck_regulator_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
-       .list_voltage = regulator_list_voltage_linear_range,
-       .set_voltage_sel = bd71837_set_voltage_sel_restricted,
-       .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static struct regulator_ops bd71837_buck_regulator_nolinear_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
-       .list_voltage = regulator_list_voltage_table,
-       .set_voltage_sel = bd71837_set_voltage_sel_restricted,
-       .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static struct regulator_ops bd71837_buck1234_regulator_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
-       .list_voltage = regulator_list_voltage_linear_range,
-       .set_voltage_sel = regulator_set_voltage_sel_regmap,
-       .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage_time_sel = regulator_set_voltage_time_sel,
-       .set_ramp_delay = bd71837_buck1234_set_ramp_delay,
-};
-
-/*
- * BUCK1/2/3/4
- * 0.70 to 1.30V (10mV step)
- */
-static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
-       REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
-};
-
-/*
- * BUCK5
- * 0.9V to 1.35V ()
- */
-static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
-       REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
-       REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
-};
-
-/*
- * BUCK6
- * 3.0V to 3.3V (step 100mV)
- */
-static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
-};
-
-/*
- * BUCK7
- * 000 = 1.605V
- * 001 = 1.695V
- * 010 = 1.755V
- * 011 = 1.8V (Initial)
- * 100 = 1.845V
- * 101 = 1.905V
- * 110 = 1.95V
- * 111 = 1.995V
- */
-static const unsigned int buck_7_volts[] = {
-       1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
-};
-
-/*
- * BUCK8
- * 0.8V to 1.40V (step 10mV)
- */
-static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
-       REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0),
-};
-
-/*
- * LDO1
- * 3.0 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
-};
-
-/*
- * LDO2
- * 0.8 or 0.9V
- */
-static const unsigned int ldo_2_volts[] = {
-       900000, 800000
-};
-
-/*
- * LDO3
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-/*
- * LDO4
- * 0.9 to 1.8V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
-       REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
-};
-
-/*
- * LDO5
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-/*
- * LDO6
- * 0.9 to 1.8V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
-       REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
-};
-
-/*
- * LDO7
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-static const struct regulator_desc bd71837_regulators[] = {
-       {
-               .name = "buck1",
-               .of_match = of_match_ptr("BUCK1"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_BUCK1,
-               .ops = &bd71837_buck1234_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_BUCK1_VOLTAGE_NUM,
-               .linear_ranges = bd71837_buck1234_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
-               .vsel_reg = BD71837_REG_BUCK1_VOLT_RUN,
-               .vsel_mask = BUCK1_RUN_MASK,
-               .enable_reg = BD71837_REG_BUCK1_CTRL,
-               .enable_mask = BD71837_BUCK_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck2",
-               .of_match = of_match_ptr("BUCK2"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_BUCK2,
-               .ops = &bd71837_buck1234_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_BUCK2_VOLTAGE_NUM,
-               .linear_ranges = bd71837_buck1234_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
-               .vsel_reg = BD71837_REG_BUCK2_VOLT_RUN,
-               .vsel_mask = BUCK2_RUN_MASK,
-               .enable_reg = BD71837_REG_BUCK2_CTRL,
-               .enable_mask = BD71837_BUCK_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck3",
-               .of_match = of_match_ptr("BUCK3"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_BUCK3,
-               .ops = &bd71837_buck1234_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_BUCK3_VOLTAGE_NUM,
-               .linear_ranges = bd71837_buck1234_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
-               .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
-               .vsel_mask = BUCK3_RUN_MASK,
-               .enable_reg = BD71837_REG_BUCK3_CTRL,
-               .enable_mask = BD71837_BUCK_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck4",
-               .of_match = of_match_ptr("BUCK4"),
-               .regulators_node = of_match_ptr("regulators"),
-                       .id = BD71837_BUCK4,
-               .ops = &bd71837_buck1234_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_BUCK4_VOLTAGE_NUM,
-               .linear_ranges = bd71837_buck1234_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
-               .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
-               .vsel_mask = BUCK4_RUN_MASK,
-               .enable_reg = BD71837_REG_BUCK4_CTRL,
-               .enable_mask = BD71837_BUCK_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck5",
-               .of_match = of_match_ptr("BUCK5"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_BUCK5,
-               .ops = &bd71837_buck_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
-               .linear_ranges = bd71837_buck5_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges),
-               .vsel_reg = BD71837_REG_BUCK5_VOLT,
-               .vsel_mask = BUCK5_MASK,
-               .enable_reg = BD71837_REG_BUCK5_CTRL,
-               .enable_mask = BD71837_BUCK_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck6",
-               .of_match = of_match_ptr("BUCK6"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_BUCK6,
-               .ops = &bd71837_buck_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
-               .linear_ranges = bd71837_buck6_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges),
-               .vsel_reg = BD71837_REG_BUCK6_VOLT,
-               .vsel_mask = BUCK6_MASK,
-               .enable_reg = BD71837_REG_BUCK6_CTRL,
-               .enable_mask = BD71837_BUCK_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck7",
-               .of_match = of_match_ptr("BUCK7"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_BUCK7,
-               .ops = &bd71837_buck_regulator_nolinear_ops,
-               .type = REGULATOR_VOLTAGE,
-               .volt_table = &buck_7_volts[0],
-               .n_voltages = ARRAY_SIZE(buck_7_volts),
-               .vsel_reg = BD71837_REG_BUCK7_VOLT,
-               .vsel_mask = BUCK7_MASK,
-               .enable_reg = BD71837_REG_BUCK7_CTRL,
-               .enable_mask = BD71837_BUCK_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck8",
-               .of_match = of_match_ptr("BUCK8"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_BUCK8,
-               .ops = &bd71837_buck_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_BUCK8_VOLTAGE_NUM,
-               .linear_ranges = bd71837_buck8_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges),
-               .vsel_reg = BD71837_REG_BUCK8_VOLT,
-               .vsel_mask = BUCK8_MASK,
-               .enable_reg = BD71837_REG_BUCK8_CTRL,
-               .enable_mask = BD71837_BUCK_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo1",
-               .of_match = of_match_ptr("LDO1"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_LDO1,
-               .ops = &bd71837_ldo_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_LDO1_VOLTAGE_NUM,
-               .linear_ranges = bd71837_ldo1_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges),
-               .vsel_reg = BD71837_REG_LDO1_VOLT,
-               .vsel_mask = LDO1_MASK,
-               .enable_reg = BD71837_REG_LDO1_VOLT,
-               .enable_mask = BD71837_LDO_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo2",
-               .of_match = of_match_ptr("LDO2"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_LDO2,
-               .ops = &bd71837_ldo_regulator_nolinear_ops,
-               .type = REGULATOR_VOLTAGE,
-               .volt_table = &ldo_2_volts[0],
-               .vsel_reg = BD71837_REG_LDO2_VOLT,
-               .vsel_mask = LDO2_MASK,
-               .n_voltages = ARRAY_SIZE(ldo_2_volts),
-               .n_voltages = BD71837_LDO2_VOLTAGE_NUM,
-               .enable_reg = BD71837_REG_LDO2_VOLT,
-               .enable_mask = BD71837_LDO_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo3",
-               .of_match = of_match_ptr("LDO3"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_LDO3,
-               .ops = &bd71837_ldo_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_LDO3_VOLTAGE_NUM,
-               .linear_ranges = bd71837_ldo3_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges),
-               .vsel_reg = BD71837_REG_LDO3_VOLT,
-               .vsel_mask = LDO3_MASK,
-               .enable_reg = BD71837_REG_LDO3_VOLT,
-               .enable_mask = BD71837_LDO_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo4",
-               .of_match = of_match_ptr("LDO4"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_LDO4,
-               .ops = &bd71837_ldo_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_LDO4_VOLTAGE_NUM,
-               .linear_ranges = bd71837_ldo4_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges),
-               .vsel_reg = BD71837_REG_LDO4_VOLT,
-               .vsel_mask = LDO4_MASK,
-               .enable_reg = BD71837_REG_LDO4_VOLT,
-               .enable_mask = BD71837_LDO_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo5",
-               .of_match = of_match_ptr("LDO5"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_LDO5,
-               .ops = &bd71837_ldo_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_LDO5_VOLTAGE_NUM,
-               .linear_ranges = bd71837_ldo5_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges),
-               /* LDO5 is supplied by buck6 */
-               .supply_name = "buck6",
-               .vsel_reg = BD71837_REG_LDO5_VOLT,
-               .vsel_mask = LDO5_MASK,
-               .enable_reg = BD71837_REG_LDO5_VOLT,
-               .enable_mask = BD71837_LDO_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo6",
-               .of_match = of_match_ptr("LDO6"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_LDO6,
-               .ops = &bd71837_ldo_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_LDO6_VOLTAGE_NUM,
-               .linear_ranges = bd71837_ldo6_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges),
-               /* LDO6 is supplied by buck7 */
-               .supply_name = "buck7",
-               .vsel_reg = BD71837_REG_LDO6_VOLT,
-               .vsel_mask = LDO6_MASK,
-               .enable_reg = BD71837_REG_LDO6_VOLT,
-               .enable_mask = BD71837_LDO_EN,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo7",
-               .of_match = of_match_ptr("LDO7"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD71837_LDO7,
-               .ops = &bd71837_ldo_regulator_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = BD71837_LDO7_VOLTAGE_NUM,
-               .linear_ranges = bd71837_ldo7_voltage_ranges,
-               .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges),
-               .vsel_reg = BD71837_REG_LDO7_VOLT,
-               .vsel_mask = LDO7_MASK,
-               .enable_reg = BD71837_REG_LDO7_VOLT,
-               .enable_mask = BD71837_LDO_EN,
-               .owner = THIS_MODULE,
-       },
-};
-
-struct reg_init {
-       unsigned int reg;
-       unsigned int mask;
-};
-
-static int bd71837_probe(struct platform_device *pdev)
-{
-       struct bd71837_pmic *pmic;
-       struct regulator_config config = { 0 };
-       struct reg_init pmic_regulator_inits[] = {
-               {
-                       .reg = BD71837_REG_BUCK1_CTRL,
-                       .mask = BD71837_BUCK_SEL,
-               }, {
-                       .reg = BD71837_REG_BUCK2_CTRL,
-                       .mask = BD71837_BUCK_SEL,
-               }, {
-                       .reg = BD71837_REG_BUCK3_CTRL,
-                       .mask = BD71837_BUCK_SEL,
-               }, {
-                       .reg = BD71837_REG_BUCK4_CTRL,
-                       .mask = BD71837_BUCK_SEL,
-               }, {
-                       .reg = BD71837_REG_BUCK5_CTRL,
-                       .mask = BD71837_BUCK_SEL,
-               }, {
-                       .reg = BD71837_REG_BUCK6_CTRL,
-                       .mask = BD71837_BUCK_SEL,
-               }, {
-                       .reg = BD71837_REG_BUCK7_CTRL,
-                       .mask = BD71837_BUCK_SEL,
-               }, {
-                       .reg = BD71837_REG_BUCK8_CTRL,
-                       .mask = BD71837_BUCK_SEL,
-               }, {
-                       .reg = BD71837_REG_LDO1_VOLT,
-                       .mask = BD71837_LDO_SEL,
-               }, {
-                       .reg = BD71837_REG_LDO2_VOLT,
-                       .mask = BD71837_LDO_SEL,
-               }, {
-                       .reg = BD71837_REG_LDO3_VOLT,
-                       .mask = BD71837_LDO_SEL,
-               }, {
-                       .reg = BD71837_REG_LDO4_VOLT,
-                       .mask = BD71837_LDO_SEL,
-               }, {
-                       .reg = BD71837_REG_LDO5_VOLT,
-                       .mask = BD71837_LDO_SEL,
-               }, {
-                       .reg = BD71837_REG_LDO6_VOLT,
-                       .mask = BD71837_LDO_SEL,
-               }, {
-                       .reg = BD71837_REG_LDO7_VOLT,
-                       .mask = BD71837_LDO_SEL,
-               }
-       };
-
-       int i, err;
-
-       pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
-       if (!pmic)
-               return -ENOMEM;
-
-       memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs));
-
-       pmic->pdev = pdev;
-       pmic->mfd = dev_get_drvdata(pdev->dev.parent);
-
-       if (!pmic->mfd) {
-               dev_err(&pdev->dev, "No MFD driver data\n");
-               err = -EINVAL;
-               goto err;
-       }
-       platform_set_drvdata(pdev, pmic);
-
-       /* Register LOCK release */
-       err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK,
-                                (REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
-       if (err) {
-               dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err);
-               goto err;
-       } else {
-               dev_dbg(&pmic->pdev->dev, "Unlocked lock register 0x%x\n",
-                       BD71837_REG_REGLOCK);
-       }
-
-       /*
-        * There is a HW quirk in BD71837. The shutdown sequence timings for
-        * bucks/LDOs which are controlled via register interface are changed.
-        * At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the
-        * beginning of shut-down sequence. As bucks 6 and 7 are parent
-        * supplies for LDO5 and LDO6 - this causes LDO5/6 voltage
-        * monitoring to errorneously detect under voltage and force PMIC to
-        * emergency state instead of poweroff. In order to avoid this we
-        * disable voltage monitoring for LDO5 and LDO6
-        */
-       err = regmap_update_bits(pmic->mfd->regmap, BD718XX_REG_MVRFLTMASK2,
-                                BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80,
-                                BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80);
-       if (err) {
-               dev_err(&pmic->pdev->dev,
-                       "Failed to disable voltage monitoring\n");
-               goto err;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) {
-
-               struct regulator_desc *desc;
-               struct regulator_dev *rdev;
-
-               desc = &pmic->descs[i];
-
-               config.dev = pdev->dev.parent;
-               config.driver_data = pmic;
-               config.regmap = pmic->mfd->regmap;
-
-               rdev = devm_regulator_register(&pdev->dev, desc, &config);
-               if (IS_ERR(rdev)) {
-                       dev_err(pmic->mfd->dev,
-                               "failed to register %s regulator\n",
-                               desc->name);
-                       err = PTR_ERR(rdev);
-                       goto err;
-               }
-               /* Regulator register gets the regulator constraints and
-                * applies them (set_machine_constraints). This should have
-                * turned the control register(s) to correct values and we
-                * can now switch the control from PMIC state machine to the
-                * register interface
-                */
-               err = regmap_update_bits(pmic->mfd->regmap,
-                                        pmic_regulator_inits[i].reg,
-                                        pmic_regulator_inits[i].mask,
-                                        0xFFFFFFFF);
-               if (err) {
-                       dev_err(&pmic->pdev->dev,
-                               "Failed to write BUCK/LDO SEL bit for (%s)\n",
-                               desc->name);
-                       goto err;
-               }
-
-               pmic->rdev[i] = rdev;
-       }
-
-err:
-       return err;
-}
-
-static struct platform_driver bd71837_regulator = {
-       .driver = {
-               .name = "bd71837-pmic",
-       },
-       .probe = bd71837_probe,
-};
-
-module_platform_driver(bd71837_regulator);
-
-MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD71837 voltage regulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
new file mode 100644 (file)
index 0000000..3a47e03
--- /dev/null
@@ -0,0 +1,1119 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// bd71837-regulator.c ROHM BD71837MWV/BD71847MWV regulator driver
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/rohm-bd718x7.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+/*
+ * BUCK1/2/3/4
+ * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
+ * 00: 10.00mV/usec 10mV 1uS
+ * 01: 5.00mV/usec     10mV 2uS
+ * 10: 2.50mV/usec     10mV 4uS
+ * 11: 1.25mV/usec     10mV 8uS
+ */
+static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
+                                          int ramp_delay)
+{
+       int id = rdev->desc->id;
+       unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
+
+       dev_dbg(&rdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
+               ramp_delay);
+       switch (ramp_delay) {
+       case 1 ... 1250:
+               ramp_value = BUCK_RAMPRATE_1P25MV;
+               break;
+       case 1251 ... 2500:
+               ramp_value = BUCK_RAMPRATE_2P50MV;
+               break;
+       case 2501 ... 5000:
+               ramp_value = BUCK_RAMPRATE_5P00MV;
+               break;
+       case 5001 ... 10000:
+               ramp_value = BUCK_RAMPRATE_10P00MV;
+               break;
+       default:
+               ramp_value = BUCK_RAMPRATE_10P00MV;
+               dev_err(&rdev->dev,
+                       "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
+                       rdev->desc->name, ramp_delay);
+       }
+
+       return regmap_update_bits(rdev->regmap, BD718XX_REG_BUCK1_CTRL + id,
+                                 BUCK_RAMPRATE_MASK, ramp_value << 6);
+}
+
+/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed.
+ * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage
+ * is changed. Hence we return -EBUSY for these if voltage is changed
+ * when BUCK/LDO is enabled.
+ */
+static int bd718xx_set_voltage_sel_restricted(struct regulator_dev *rdev,
+                                                   unsigned int sel)
+{
+       if (regulator_is_enabled_regmap(rdev))
+               return -EBUSY;
+
+       return regulator_set_voltage_sel_regmap(rdev, sel);
+}
+
+static int bd718xx_set_voltage_sel_pickable_restricted(
+               struct regulator_dev *rdev, unsigned int sel)
+{
+       if (regulator_is_enabled_regmap(rdev))
+               return -EBUSY;
+
+       return regulator_set_voltage_sel_pickable_regmap(rdev, sel);
+}
+
+static struct regulator_ops bd718xx_pickable_range_ldo_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_pickable_linear_range,
+       .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
+       .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+};
+
+static struct regulator_ops bd718xx_pickable_range_buck_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_pickable_linear_range,
+       .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
+       .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_ldo_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear_range,
+       .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_table,
+       .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd718xx_buck_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear_range,
+       .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_buck_regulator_nolinear_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_table,
+       .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_dvs_buck_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear_range,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .set_ramp_delay = bd718xx_buck1234_set_ramp_delay,
+};
+
+/*
+ * BD71837 BUCK1/2/3/4
+ * BD71847 BUCK1/2
+ * 0.70 to 1.30V (10mV step)
+ */
+static const struct regulator_linear_range bd718xx_dvs_buck_volts[] = {
+       REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
+       REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * BD71837 BUCK5
+ * 0.7V to 1.35V  (range 0)
+ * and
+ * 0.675 to 1.325 (range 1)
+ */
+static const struct regulator_linear_range bd71837_buck5_volts[] = {
+       /* Ranges when VOLT_SEL bit is 0 */
+       REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+       REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+       REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+       /* Ranges when VOLT_SEL bit is 1  */
+       REGULATOR_LINEAR_RANGE(675000, 0x0, 0x3, 100000),
+       REGULATOR_LINEAR_RANGE(1025000, 0x4, 0x5, 50000),
+       REGULATOR_LINEAR_RANGE(1175000, 0x6, 0x7, 150000),
+};
+
+/*
+ * Range selector for first 3 linear ranges is 0x0
+ * and 0x1 for last 3 ranges.
+ */
+static const unsigned int bd71837_buck5_volt_range_sel[] = {
+       0x0, 0x0, 0x0, 0x80, 0x80, 0x80
+};
+
+/*
+ * BD71847 BUCK3
+ */
+static const struct regulator_linear_range bd71847_buck3_volts[] = {
+       /* Ranges when VOLT_SEL bits are 00 */
+       REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+       REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+       REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+       /* Ranges when VOLT_SEL bits are 01 */
+       REGULATOR_LINEAR_RANGE(550000, 0x0, 0x7, 50000),
+       /* Ranges when VOLT_SEL bits are 11 */
+       REGULATOR_LINEAR_RANGE(675000, 0x0, 0x3, 100000),
+       REGULATOR_LINEAR_RANGE(1025000, 0x4, 0x5, 50000),
+       REGULATOR_LINEAR_RANGE(1175000, 0x6, 0x7, 150000),
+};
+
+static const unsigned int bd71847_buck3_volt_range_sel[] = {
+       0x0, 0x0, 0x0, 0x40, 0x80, 0x80, 0x80
+};
+
+static const struct regulator_linear_range bd71847_buck4_volts[] = {
+       REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+       REGULATOR_LINEAR_RANGE(2600000, 0x00, 0x03, 100000),
+};
+
+static const unsigned int bd71847_buck4_volt_range_sel[] = { 0x0, 0x40 };
+
+/*
+ * BUCK6
+ * 3.0V to 3.3V (step 100mV)
+ */
+static const struct regulator_linear_range bd71837_buck6_volts[] = {
+       REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * BD71837 BUCK7
+ * BD71847 BUCK5
+ * 000 = 1.605V
+ * 001 = 1.695V
+ * 010 = 1.755V
+ * 011 = 1.8V (Initial)
+ * 100 = 1.845V
+ * 101 = 1.905V
+ * 110 = 1.95V
+ * 111 = 1.995V
+ */
+static const unsigned int bd718xx_3rd_nodvs_buck_volts[] = {
+       1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
+};
+
+/*
+ * BUCK8
+ * 0.8V to 1.40V (step 10mV)
+ */
+static const struct regulator_linear_range bd718xx_4th_nodvs_buck_volts[] = {
+       REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
+};
+
+/*
+ * LDO1
+ * 3.0 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo1_volts[] = {
+       REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+       REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000),
+};
+
+static const unsigned int bd718xx_ldo1_volt_range_sel[] = { 0x0, 0x20 };
+
+/*
+ * LDO2
+ * 0.8 or 0.9V
+ */
+static const unsigned int ldo_2_volts[] = {
+       900000, 800000
+};
+
+/*
+ * LDO3
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo3_volts[] = {
+       REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO4
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo4_volts[] = {
+       REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+};
+
+/*
+ * LDO5 for BD71837
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo5_volts[] = {
+       REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO5 for BD71837
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71847_ldo5_volts[] = {
+       REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+       REGULATOR_LINEAR_RANGE(800000, 0x00, 0x0F, 100000),
+};
+
+static const unsigned int bd71847_ldo5_volt_range_sel[] = { 0x0, 0x20 };
+
+/*
+ * LDO6
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo6_volts[] = {
+       REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+};
+
+/*
+ * LDO7
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo7_volts[] = {
+       REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+struct reg_init {
+       unsigned int reg;
+       unsigned int mask;
+       unsigned int val;
+};
+struct bd718xx_regulator_data {
+       struct regulator_desc desc;
+       const struct reg_init init;
+       const struct reg_init *additional_inits;
+       int additional_init_amnt;
+};
+
+/*
+ * There is a HW quirk in BD71837. The shutdown sequence timings for
+ * bucks/LDOs which are controlled via register interface are changed.
+ * At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the
+ * beginning of shut-down sequence. As bucks 6 and 7 are parent
+ * supplies for LDO5 and LDO6 - this causes LDO5/6 voltage
+ * monitoring to errorneously detect under voltage and force PMIC to
+ * emergency state instead of poweroff. In order to avoid this we
+ * disable voltage monitoring for LDO5 and LDO6
+ */
+static const struct reg_init bd71837_ldo5_inits[] = {
+       {
+               .reg = BD718XX_REG_MVRFLTMASK2,
+               .mask = BD718XX_LDO5_VRMON80,
+               .val = BD718XX_LDO5_VRMON80,
+       },
+};
+
+static const struct reg_init bd71837_ldo6_inits[] = {
+       {
+               .reg = BD718XX_REG_MVRFLTMASK2,
+               .mask = BD718XX_LDO6_VRMON80,
+               .val = BD718XX_LDO6_VRMON80,
+       },
+};
+
+static const struct bd718xx_regulator_data bd71847_regulators[] = {
+       {
+               .desc = {
+                       .name = "buck1",
+                       .of_match = of_match_ptr("BUCK1"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK1,
+                       .ops = &bd718xx_dvs_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_dvs_buck_volts,
+                       .n_linear_ranges =
+                               ARRAY_SIZE(bd718xx_dvs_buck_volts),
+                       .vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN,
+                       .vsel_mask = DVS_BUCK_RUN_MASK,
+                       .enable_reg = BD718XX_REG_BUCK1_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_BUCK1_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck2",
+                       .of_match = of_match_ptr("BUCK2"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK2,
+                       .ops = &bd718xx_dvs_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_dvs_buck_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+                       .vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN,
+                       .vsel_mask = DVS_BUCK_RUN_MASK,
+                       .enable_reg = BD718XX_REG_BUCK2_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_BUCK2_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck3",
+                       .of_match = of_match_ptr("BUCK3"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK3,
+                       .ops = &bd718xx_pickable_range_buck_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD71847_BUCK3_VOLTAGE_NUM,
+                       .linear_ranges = bd71847_buck3_volts,
+                       .n_linear_ranges =
+                               ARRAY_SIZE(bd71847_buck3_volts),
+                       .vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+                       .vsel_mask = BD718XX_1ST_NODVS_BUCK_MASK,
+                       .vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+                       .vsel_range_mask = BD71847_BUCK3_RANGE_MASK,
+                       .linear_range_selectors = bd71847_buck3_volt_range_sel,
+                       .enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck4",
+                       .of_match = of_match_ptr("BUCK4"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK4,
+                       .ops = &bd718xx_pickable_range_buck_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD71847_BUCK4_VOLTAGE_NUM,
+                       .linear_ranges = bd71847_buck4_volts,
+                       .n_linear_ranges =
+                               ARRAY_SIZE(bd71847_buck4_volts),
+                       .enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+                       .vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+                       .vsel_mask = BD71847_BUCK4_MASK,
+                       .vsel_range_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+                       .vsel_range_mask = BD71847_BUCK4_RANGE_MASK,
+                       .linear_range_selectors = bd71847_buck4_volt_range_sel,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck5",
+                       .of_match = of_match_ptr("BUCK5"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK5,
+                       .ops = &bd718xx_buck_regulator_nolinear_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .volt_table = &bd718xx_3rd_nodvs_buck_volts[0],
+                       .n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts),
+                       .vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT,
+                       .vsel_mask = BD718XX_3RD_NODVS_BUCK_MASK,
+                       .enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck6",
+                       .of_match = of_match_ptr("BUCK6"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK6,
+                       .ops = &bd718xx_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_4th_nodvs_buck_volts,
+                       .n_linear_ranges =
+                               ARRAY_SIZE(bd718xx_4th_nodvs_buck_volts),
+                       .vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT,
+                       .vsel_mask = BD718XX_4TH_NODVS_BUCK_MASK,
+                       .enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo1",
+                       .of_match = of_match_ptr("LDO1"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO1,
+                       .ops = &bd718xx_pickable_range_ldo_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_ldo1_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts),
+                       .vsel_reg = BD718XX_REG_LDO1_VOLT,
+                       .vsel_mask = BD718XX_LDO1_MASK,
+                       .vsel_range_reg = BD718XX_REG_LDO1_VOLT,
+                       .vsel_range_mask = BD718XX_LDO1_RANGE_MASK,
+                       .linear_range_selectors = bd718xx_ldo1_volt_range_sel,
+                       .enable_reg = BD718XX_REG_LDO1_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO1_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo2",
+                       .of_match = of_match_ptr("LDO2"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO2,
+                       .ops = &bd718xx_ldo_regulator_nolinear_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .volt_table = &ldo_2_volts[0],
+                       .vsel_reg = BD718XX_REG_LDO2_VOLT,
+                       .vsel_mask = BD718XX_LDO2_MASK,
+                       .n_voltages = ARRAY_SIZE(ldo_2_volts),
+                       .enable_reg = BD718XX_REG_LDO2_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO2_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo3",
+                       .of_match = of_match_ptr("LDO3"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO3,
+                       .ops = &bd718xx_ldo_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_ldo3_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts),
+                       .vsel_reg = BD718XX_REG_LDO3_VOLT,
+                       .vsel_mask = BD718XX_LDO3_MASK,
+                       .enable_reg = BD718XX_REG_LDO3_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO3_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo4",
+                       .of_match = of_match_ptr("LDO4"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO4,
+                       .ops = &bd718xx_ldo_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_ldo4_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts),
+                       .vsel_reg = BD718XX_REG_LDO4_VOLT,
+                       .vsel_mask = BD718XX_LDO4_MASK,
+                       .enable_reg = BD718XX_REG_LDO4_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO4_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo5",
+                       .of_match = of_match_ptr("LDO5"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO5,
+                       .ops = &bd718xx_pickable_range_ldo_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD71847_LDO5_VOLTAGE_NUM,
+                       .linear_ranges = bd71847_ldo5_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd71847_ldo5_volts),
+                       .vsel_reg = BD718XX_REG_LDO5_VOLT,
+                       .vsel_mask = BD71847_LDO5_MASK,
+                       .vsel_range_reg = BD718XX_REG_LDO5_VOLT,
+                       .vsel_range_mask = BD71847_LDO5_RANGE_MASK,
+                       .linear_range_selectors = bd71847_ldo5_volt_range_sel,
+                       .enable_reg = BD718XX_REG_LDO5_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO5_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo6",
+                       .of_match = of_match_ptr("LDO6"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO6,
+                       .ops = &bd718xx_ldo_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_ldo6_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts),
+                       /* LDO6 is supplied by buck5 */
+                       .supply_name = "buck5",
+                       .vsel_reg = BD718XX_REG_LDO6_VOLT,
+                       .vsel_mask = BD718XX_LDO6_MASK,
+                       .enable_reg = BD718XX_REG_LDO6_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO6_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+};
+
+static const struct bd718xx_regulator_data bd71837_regulators[] = {
+       {
+               .desc = {
+                       .name = "buck1",
+                       .of_match = of_match_ptr("BUCK1"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK1,
+                       .ops = &bd718xx_dvs_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_dvs_buck_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+                       .vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN,
+                       .vsel_mask = DVS_BUCK_RUN_MASK,
+                       .enable_reg = BD718XX_REG_BUCK1_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_BUCK1_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck2",
+                       .of_match = of_match_ptr("BUCK2"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK2,
+                       .ops = &bd718xx_dvs_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_dvs_buck_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+                       .vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN,
+                       .vsel_mask = DVS_BUCK_RUN_MASK,
+                       .enable_reg = BD718XX_REG_BUCK2_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_BUCK2_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck3",
+                       .of_match = of_match_ptr("BUCK3"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK3,
+                       .ops = &bd718xx_dvs_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_dvs_buck_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+                       .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
+                       .vsel_mask = DVS_BUCK_RUN_MASK,
+                       .enable_reg = BD71837_REG_BUCK3_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD71837_REG_BUCK3_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck4",
+                       .of_match = of_match_ptr("BUCK4"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK4,
+                       .ops = &bd718xx_dvs_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_dvs_buck_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+                       .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
+                       .vsel_mask = DVS_BUCK_RUN_MASK,
+                       .enable_reg = BD71837_REG_BUCK4_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD71837_REG_BUCK4_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck5",
+                       .of_match = of_match_ptr("BUCK5"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK5,
+                       .ops = &bd718xx_pickable_range_buck_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
+                       .linear_ranges = bd71837_buck5_volts,
+                       .n_linear_ranges =
+                               ARRAY_SIZE(bd71837_buck5_volts),
+                       .vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+                       .vsel_mask = BD71837_BUCK5_MASK,
+                       .vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+                       .vsel_range_mask = BD71837_BUCK5_RANGE_MASK,
+                       .linear_range_selectors = bd71837_buck5_volt_range_sel,
+                       .enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck6",
+                       .of_match = of_match_ptr("BUCK6"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK6,
+                       .ops = &bd718xx_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
+                       .linear_ranges = bd71837_buck6_volts,
+                       .n_linear_ranges =
+                               ARRAY_SIZE(bd71837_buck6_volts),
+                       .vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+                       .vsel_mask = BD71837_BUCK6_MASK,
+                       .enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck7",
+                       .of_match = of_match_ptr("BUCK7"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK7,
+                       .ops = &bd718xx_buck_regulator_nolinear_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .volt_table = &bd718xx_3rd_nodvs_buck_volts[0],
+                       .n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts),
+                       .vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT,
+                       .vsel_mask = BD718XX_3RD_NODVS_BUCK_MASK,
+                       .enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "buck8",
+                       .of_match = of_match_ptr("BUCK8"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_BUCK8,
+                       .ops = &bd718xx_buck_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_4th_nodvs_buck_volts,
+                       .n_linear_ranges =
+                               ARRAY_SIZE(bd718xx_4th_nodvs_buck_volts),
+                       .vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT,
+                       .vsel_mask = BD718XX_4TH_NODVS_BUCK_MASK,
+                       .enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+                       .enable_mask = BD718XX_BUCK_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+                       .mask = BD718XX_BUCK_SEL,
+                       .val = BD718XX_BUCK_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo1",
+                       .of_match = of_match_ptr("LDO1"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO1,
+                       .ops = &bd718xx_pickable_range_ldo_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_ldo1_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts),
+                       .vsel_reg = BD718XX_REG_LDO1_VOLT,
+                       .vsel_mask = BD718XX_LDO1_MASK,
+                       .vsel_range_reg = BD718XX_REG_LDO1_VOLT,
+                       .vsel_range_mask = BD718XX_LDO1_RANGE_MASK,
+                       .linear_range_selectors = bd718xx_ldo1_volt_range_sel,
+                       .enable_reg = BD718XX_REG_LDO1_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO1_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo2",
+                       .of_match = of_match_ptr("LDO2"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO2,
+                       .ops = &bd718xx_ldo_regulator_nolinear_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .volt_table = &ldo_2_volts[0],
+                       .vsel_reg = BD718XX_REG_LDO2_VOLT,
+                       .vsel_mask = BD718XX_LDO2_MASK,
+                       .n_voltages = ARRAY_SIZE(ldo_2_volts),
+                       .enable_reg = BD718XX_REG_LDO2_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO2_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo3",
+                       .of_match = of_match_ptr("LDO3"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO3,
+                       .ops = &bd718xx_ldo_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_ldo3_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts),
+                       .vsel_reg = BD718XX_REG_LDO3_VOLT,
+                       .vsel_mask = BD718XX_LDO3_MASK,
+                       .enable_reg = BD718XX_REG_LDO3_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO3_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo4",
+                       .of_match = of_match_ptr("LDO4"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO4,
+                       .ops = &bd718xx_ldo_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_ldo4_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts),
+                       .vsel_reg = BD718XX_REG_LDO4_VOLT,
+                       .vsel_mask = BD718XX_LDO4_MASK,
+                       .enable_reg = BD718XX_REG_LDO4_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO4_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+       {
+               .desc = {
+                       .name = "ldo5",
+                       .of_match = of_match_ptr("LDO5"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO5,
+                       .ops = &bd718xx_ldo_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD71837_LDO5_VOLTAGE_NUM,
+                       .linear_ranges = bd71837_ldo5_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_volts),
+                       /* LDO5 is supplied by buck6 */
+                       .supply_name = "buck6",
+                       .vsel_reg = BD718XX_REG_LDO5_VOLT,
+                       .vsel_mask = BD71837_LDO5_MASK,
+                       .enable_reg = BD718XX_REG_LDO5_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO5_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+               .additional_inits = bd71837_ldo5_inits,
+               .additional_init_amnt = ARRAY_SIZE(bd71837_ldo5_inits),
+       },
+       {
+               .desc = {
+                       .name = "ldo6",
+                       .of_match = of_match_ptr("LDO6"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO6,
+                       .ops = &bd718xx_ldo_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
+                       .linear_ranges = bd718xx_ldo6_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts),
+                       /* LDO6 is supplied by buck7 */
+                       .supply_name = "buck7",
+                       .vsel_reg = BD718XX_REG_LDO6_VOLT,
+                       .vsel_mask = BD718XX_LDO6_MASK,
+                       .enable_reg = BD718XX_REG_LDO6_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD718XX_REG_LDO6_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+               .additional_inits = bd71837_ldo6_inits,
+               .additional_init_amnt = ARRAY_SIZE(bd71837_ldo6_inits),
+       },
+       {
+               .desc = {
+                       .name = "ldo7",
+                       .of_match = of_match_ptr("LDO7"),
+                       .regulators_node = of_match_ptr("regulators"),
+                       .id = BD718XX_LDO7,
+                       .ops = &bd718xx_ldo_regulator_ops,
+                       .type = REGULATOR_VOLTAGE,
+                       .n_voltages = BD71837_LDO7_VOLTAGE_NUM,
+                       .linear_ranges = bd71837_ldo7_volts,
+                       .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_volts),
+                       .vsel_reg = BD71837_REG_LDO7_VOLT,
+                       .vsel_mask = BD71837_LDO7_MASK,
+                       .enable_reg = BD71837_REG_LDO7_VOLT,
+                       .enable_mask = BD718XX_LDO_EN,
+                       .owner = THIS_MODULE,
+               },
+               .init = {
+                       .reg = BD71837_REG_LDO7_VOLT,
+                       .mask = BD718XX_LDO_SEL,
+                       .val = BD718XX_LDO_SEL,
+               },
+       },
+};
+
+struct bd718xx_pmic_inits {
+       const struct bd718xx_regulator_data (*r_datas)[];
+       unsigned int r_amount;
+};
+
+static int bd718xx_probe(struct platform_device *pdev)
+{
+       struct bd718xx *mfd;
+       struct regulator_config config = { 0 };
+       struct bd718xx_pmic_inits pmic_regulators[] = {
+               [BD718XX_TYPE_BD71837] = {
+                       .r_datas = &bd71837_regulators,
+                       .r_amount = ARRAY_SIZE(bd71837_regulators),
+               },
+               [BD718XX_TYPE_BD71847] = {
+                       .r_datas = &bd71847_regulators,
+                       .r_amount = ARRAY_SIZE(bd71847_regulators),
+               },
+       };
+
+       int i, j, err;
+
+       mfd = dev_get_drvdata(pdev->dev.parent);
+       if (!mfd) {
+               dev_err(&pdev->dev, "No MFD driver data\n");
+               err = -EINVAL;
+               goto err;
+       }
+
+       if (mfd->chip_type >= BD718XX_TYPE_AMOUNT ||
+           !pmic_regulators[mfd->chip_type].r_datas) {
+               dev_err(&pdev->dev, "Unsupported chip type\n");
+               err = -EINVAL;
+               goto err;
+       }
+
+       /* Register LOCK release */
+       err = regmap_update_bits(mfd->regmap, BD718XX_REG_REGLOCK,
+                                (REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to unlock PMIC (%d)\n", err);
+               goto err;
+       } else {
+               dev_dbg(&pdev->dev, "Unlocked lock register 0x%x\n",
+                       BD718XX_REG_REGLOCK);
+       }
+
+       for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) {
+
+               const struct regulator_desc *desc;
+               struct regulator_dev *rdev;
+               const struct bd718xx_regulator_data *r;
+
+               r = &(*pmic_regulators[mfd->chip_type].r_datas)[i];
+               desc = &r->desc;
+
+               config.dev = pdev->dev.parent;
+               config.regmap = mfd->regmap;
+
+               rdev = devm_regulator_register(&pdev->dev, desc, &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev,
+                               "failed to register %s regulator\n",
+                               desc->name);
+                       err = PTR_ERR(rdev);
+                       goto err;
+               }
+               /* Regulator register gets the regulator constraints and
+                * applies them (set_machine_constraints). This should have
+                * turned the control register(s) to correct values and we
+                * can now switch the control from PMIC state machine to the
+                * register interface
+                */
+               err = regmap_update_bits(mfd->regmap, r->init.reg,
+                                        r->init.mask, r->init.val);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Failed to write BUCK/LDO SEL bit for (%s)\n",
+                               desc->name);
+                       goto err;
+               }
+               for (j = 0; j < r->additional_init_amnt; j++) {
+                       err = regmap_update_bits(mfd->regmap,
+                                                r->additional_inits[j].reg,
+                                                r->additional_inits[j].mask,
+                                                r->additional_inits[j].val);
+                       if (err) {
+                               dev_err(&pdev->dev,
+                                       "Buck (%s) initialization failed\n",
+                                       desc->name);
+                               goto err;
+                       }
+               }
+       }
+
+err:
+       return err;
+}
+
+static struct platform_driver bd718xx_regulator = {
+       .driver = {
+               .name = "bd718xx-pmic",
+       },
+       .probe = bd718xx_probe,
+};
+
+module_platform_driver(bd718xx_regulator);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD71837/BD71847 voltage regulator driver");
+MODULE_LICENSE("GPL");
index 9577d89418468a06f1030ff69d2699f71b5710bc..2c66b528aedec02f4afdda7e8c04faf60711a70d 100644 (file)
@@ -426,19 +426,24 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(name);
 
-static ssize_t regulator_print_opmode(char *buf, int mode)
+static const char *regulator_opmode_to_str(int mode)
 {
        switch (mode) {
        case REGULATOR_MODE_FAST:
-               return sprintf(buf, "fast\n");
+               return "fast";
        case REGULATOR_MODE_NORMAL:
-               return sprintf(buf, "normal\n");
+               return "normal";
        case REGULATOR_MODE_IDLE:
-               return sprintf(buf, "idle\n");
+               return "idle";
        case REGULATOR_MODE_STANDBY:
-               return sprintf(buf, "standby\n");
+               return "standby";
        }
-       return sprintf(buf, "unknown\n");
+       return "unknown";
+}
+
+static ssize_t regulator_print_opmode(char *buf, int mode)
+{
+       return sprintf(buf, "%s\n", regulator_opmode_to_str(mode));
 }
 
 static ssize_t regulator_opmode_show(struct device *dev,
@@ -2783,6 +2788,11 @@ static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
        if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
                return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
 
+       if (desc->ops->list_voltage ==
+               regulator_list_voltage_pickable_linear_range)
+               return regulator_map_voltage_pickable_linear_range(rdev,
+                                                       min_uV, max_uV);
+
        return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
 }
 
@@ -3470,21 +3480,23 @@ out:
 }
 EXPORT_SYMBOL_GPL(regulator_set_current_limit);
 
+static int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev)
+{
+       /* sanity check */
+       if (!rdev->desc->ops->get_current_limit)
+               return -EINVAL;
+
+       return rdev->desc->ops->get_current_limit(rdev);
+}
+
 static int _regulator_get_current_limit(struct regulator_dev *rdev)
 {
        int ret;
 
        regulator_lock(rdev);
-
-       /* sanity check */
-       if (!rdev->desc->ops->get_current_limit) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = rdev->desc->ops->get_current_limit(rdev);
-out:
+       ret = _regulator_get_current_limit_unlocked(rdev);
        regulator_unlock(rdev);
+
        return ret;
 }
 
@@ -3549,21 +3561,23 @@ out:
 }
 EXPORT_SYMBOL_GPL(regulator_set_mode);
 
+static unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev)
+{
+       /* sanity check */
+       if (!rdev->desc->ops->get_mode)
+               return -EINVAL;
+
+       return rdev->desc->ops->get_mode(rdev);
+}
+
 static unsigned int _regulator_get_mode(struct regulator_dev *rdev)
 {
        int ret;
 
        regulator_lock(rdev);
-
-       /* sanity check */
-       if (!rdev->desc->ops->get_mode) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = rdev->desc->ops->get_mode(rdev);
-out:
+       ret = _regulator_get_mode_unlocked(rdev);
        regulator_unlock(rdev);
+
        return ret;
 }
 
@@ -4455,41 +4469,33 @@ void regulator_unregister(struct regulator_dev *rdev)
 EXPORT_SYMBOL_GPL(regulator_unregister);
 
 #ifdef CONFIG_SUSPEND
-static int _regulator_suspend(struct device *dev, void *data)
-{
-       struct regulator_dev *rdev = dev_to_rdev(dev);
-       suspend_state_t *state = data;
-       int ret;
-
-       regulator_lock(rdev);
-       ret = suspend_set_state(rdev, *state);
-       regulator_unlock(rdev);
-
-       return ret;
-}
-
 /**
  * regulator_suspend - prepare regulators for system wide suspend
- * @state: system suspend state
+ * @dev: ``&struct device`` pointer that is passed to _regulator_suspend()
  *
  * Configure each regulator with it's suspend operating parameters for state.
  */
 static int regulator_suspend(struct device *dev)
 {
+       struct regulator_dev *rdev = dev_to_rdev(dev);
        suspend_state_t state = pm_suspend_target_state;
+       int ret;
+
+       regulator_lock(rdev);
+       ret = suspend_set_state(rdev, state);
+       regulator_unlock(rdev);
 
-       return class_for_each_device(&regulator_class, NULL, &state,
-                                    _regulator_suspend);
+       return ret;
 }
 
-static int _regulator_resume(struct device *dev, void *data)
+static int regulator_resume(struct device *dev)
 {
-       int ret = 0;
+       suspend_state_t state = pm_suspend_target_state;
        struct regulator_dev *rdev = dev_to_rdev(dev);
-       suspend_state_t *state = data;
        struct regulator_state *rstate;
+       int ret = 0;
 
-       rstate = regulator_get_suspend_state(rdev, *state);
+       rstate = regulator_get_suspend_state(rdev, state);
        if (rstate == NULL)
                return 0;
 
@@ -4504,15 +4510,6 @@ static int _regulator_resume(struct device *dev, void *data)
 
        return ret;
 }
-
-static int regulator_resume(struct device *dev)
-{
-       suspend_state_t state = pm_suspend_target_state;
-
-       return class_for_each_device(&regulator_class, NULL, &state,
-                                    _regulator_resume);
-}
-
 #else /* !CONFIG_SUSPEND */
 
 #define regulator_suspend      NULL
@@ -4670,17 +4667,23 @@ static void regulator_summary_show_subtree(struct seq_file *s,
        struct regulation_constraints *c;
        struct regulator *consumer;
        struct summary_data summary_data;
+       unsigned int opmode;
 
        if (!rdev)
                return;
 
-       seq_printf(s, "%*s%-*s %3d %4d %6d ",
+       regulator_lock_nested(rdev, level);
+
+       opmode = _regulator_get_mode_unlocked(rdev);
+       seq_printf(s, "%*s%-*s %3d %4d %6d %7s ",
                   level * 3 + 1, "",
                   30 - level * 3, rdev_get_name(rdev),
-                  rdev->use_count, rdev->open_count, rdev->bypass_count);
+                  rdev->use_count, rdev->open_count, rdev->bypass_count,
+                  regulator_opmode_to_str(opmode));
 
        seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000);
-       seq_printf(s, "%5dmA ", _regulator_get_current_limit(rdev) / 1000);
+       seq_printf(s, "%5dmA ",
+                  _regulator_get_current_limit_unlocked(rdev) / 1000);
 
        c = rdev->constraints;
        if (c) {
@@ -4709,7 +4712,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
 
                switch (rdev->desc->type) {
                case REGULATOR_VOLTAGE:
-                       seq_printf(s, "%37dmV %5dmV",
+                       seq_printf(s, "%37dmA %5dmV %5dmV",
+                                  consumer->uA_load / 1000,
                                   consumer->voltage[PM_SUSPEND_ON].min_uV / 1000,
                                   consumer->voltage[PM_SUSPEND_ON].max_uV / 1000);
                        break;
@@ -4726,6 +4730,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
 
        class_for_each_device(&regulator_class, NULL, &summary_data,
                              regulator_summary_show_children);
+
+       regulator_unlock(rdev);
 }
 
 static int regulator_summary_show_roots(struct device *dev, void *data)
@@ -4741,8 +4747,8 @@ static int regulator_summary_show_roots(struct device *dev, void *data)
 
 static int regulator_summary_show(struct seq_file *s, void *data)
 {
-       seq_puts(s, " regulator                      use open bypass voltage current     min     max\n");
-       seq_puts(s, "-------------------------------------------------------------------------------\n");
+       seq_puts(s, " regulator                      use open bypass  opmode voltage current     min     max\n");
+       seq_puts(s, "---------------------------------------------------------------------------------------\n");
 
        class_for_each_device(&regulator_class, NULL, s,
                              regulator_summary_show_roots);
index 9ececfef42d67326d1521b5ea1e23f2dfa593908..37e4025203e34949c42edeb09378caa06d7f4ddc 100644 (file)
@@ -420,7 +420,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
        config.dev = &pdev->dev;
        config.driver_data = regulator;
        config.regmap = da9052->regmap;
-       if (pdata && pdata->regulators) {
+       if (pdata) {
                config.init_data = pdata->regulators[cell->id];
        } else {
 #ifdef CONFIG_OF
index f40c3b8644ae524e2dbb76fb1c4a4af6d0d9fcd2..588c3d2445cf364c91cdcbb2c6376aaa095750ee 100644 (file)
@@ -612,7 +612,7 @@ static int da9055_regulator_probe(struct platform_device *pdev)
        config.driver_data = regulator;
        config.regmap = da9055->regmap;
 
-       if (pdata && pdata->regulators) {
+       if (pdata) {
                config.init_data = pdata->regulators[pdev->id];
        } else {
                ret = da9055_regulator_dt_init(pdev, regulator, &config,
index 6c122b3df5d03529e5dc8b8046fbd92df31a2c30..8f68c7a05d27968970287c8811f5e1764c1ad859 100644 (file)
@@ -294,11 +294,11 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
                pdata->init_data[n] = da9211_matches[i].init_data;
                pdata->reg_node[n] = da9211_matches[i].of_node;
                pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev,
-                                                                 da9211_matches[i].of_node,
-                                                                 "enable",
-                                                                 0,
-                                                                 GPIOD_OUT_HIGH,
-                                                                 "da9211-enable");
+                                 da9211_matches[i].of_node,
+                                 "enable",
+                                 0,
+                                 GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+                                 "da9211-enable");
                n++;
        }
 
index 777fac6fb4cb0a8adc1d7e2ea0e96c768bbda343..2c6098e6f4bcec726f1af2ce0e552fc2d8077ef2 100644 (file)
@@ -43,7 +43,6 @@ struct platform_device *regulator_register_always_on(int id, const char *name,
        }
 
        data->cfg.microvolts = uv;
-       data->cfg.gpio = -EINVAL;
        data->cfg.enabled_at_boot = 1;
        data->cfg.init_data = &data->init_data;
 
index 988a7472c2ab568c3d1c03d1092c0713073a6d28..ccc29038f19a98c8d7b292ab60536cc616345c0a 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/fixed.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/machine.h>
 
@@ -78,15 +77,16 @@ of_get_fixed_voltage_config(struct device *dev,
        if (init_data->constraints.boot_on)
                config->enabled_at_boot = true;
 
-       config->gpio = of_get_named_gpio(np, "gpio", 0);
-       if ((config->gpio < 0) && (config->gpio != -ENOENT))
-               return ERR_PTR(config->gpio);
-
        of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
 
-       config->enable_high = of_property_read_bool(np, "enable-active-high");
-       config->gpio_is_open_drain = of_property_read_bool(np,
-                                                          "gpio-open-drain");
+       /*
+        * FIXME: we pulled active low/high and open drain handling into
+        * gpiolib so it will be handled there. Delete this in the second
+        * step when we also remove the custom inversion handling for all
+        * legacy boardfiles.
+        */
+       config->enable_high = 1;
+       config->gpio_is_open_drain = 0;
 
        if (of_find_property(np, "vin-supply", NULL))
                config->input_supply = "vin";
@@ -102,6 +102,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
        struct fixed_voltage_config *config;
        struct fixed_voltage_data *drvdata;
        struct regulator_config cfg = { };
+       enum gpiod_flags gflags;
        int ret;
 
        drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
@@ -150,25 +151,41 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
 
        drvdata->desc.fixed_uV = config->microvolts;
 
-       if (gpio_is_valid(config->gpio)) {
-               cfg.ena_gpio = config->gpio;
-               if (pdev->dev.of_node)
-                       cfg.ena_gpio_initialized = true;
-       }
        cfg.ena_gpio_invert = !config->enable_high;
        if (config->enabled_at_boot) {
                if (config->enable_high)
-                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+                       gflags = GPIOD_OUT_HIGH;
                else
-                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+                       gflags = GPIOD_OUT_LOW;
        } else {
                if (config->enable_high)
-                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+                       gflags = GPIOD_OUT_LOW;
                else
-                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+                       gflags = GPIOD_OUT_HIGH;
        }
-       if (config->gpio_is_open_drain)
-               cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN;
+       if (config->gpio_is_open_drain) {
+               if (gflags == GPIOD_OUT_HIGH)
+                       gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
+               else
+                       gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
+       }
+
+       /*
+        * Some fixed regulators share the enable line between two
+        * regulators which makes it necessary to get a handle on the
+        * same descriptor for two different consumers. This will get
+        * the GPIO descriptor, but only the first call will initialize
+        * it so any flags such as inversion or open drain will only
+        * be set up by the first caller and assumed identical on the
+        * next caller.
+        *
+        * FIXME: find a better way to deal with this.
+        */
+       gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
+
+       cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags);
+       if (IS_ERR(cfg.ena_gpiod))
+               return PTR_ERR(cfg.ena_gpiod);
 
        cfg.dev = &pdev->dev;
        cfg.init_data = config->init_data;
index 2ae7c3ac5940ec29b52870f4619905e7040aaf20..5686a1335bd30db829215b29a97e29ebee06b97d 100644 (file)
@@ -103,6 +103,128 @@ int regulator_disable_regmap(struct regulator_dev *rdev)
 }
 EXPORT_SYMBOL_GPL(regulator_disable_regmap);
 
+static int regulator_range_selector_to_index(struct regulator_dev *rdev,
+                                            unsigned int rval)
+{
+       int i;
+
+       if (!rdev->desc->linear_range_selectors)
+               return -EINVAL;
+
+       rval &= rdev->desc->vsel_range_mask;
+
+       for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+               if (rdev->desc->linear_range_selectors[i] == rval)
+                       return i;
+       }
+       return -EINVAL;
+}
+
+/**
+ * regulator_get_voltage_sel_pickable_regmap - pickable range get_voltage_sel
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O and use pickable
+ * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
+ * fields in their descriptor and then use this as their get_voltage_vsel
+ * operation, saving some code.
+ */
+int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev)
+{
+       unsigned int r_val;
+       int range;
+       unsigned int val;
+       int ret, i;
+       unsigned int voltages_in_range = 0;
+
+       if (!rdev->desc->linear_ranges)
+               return -EINVAL;
+
+       ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+       if (ret != 0)
+               return ret;
+
+       ret = regmap_read(rdev->regmap, rdev->desc->vsel_range_reg, &r_val);
+       if (ret != 0)
+               return ret;
+
+       val &= rdev->desc->vsel_mask;
+       val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+       range = regulator_range_selector_to_index(rdev, r_val);
+       if (range < 0)
+               return -EINVAL;
+
+       for (i = 0; i < range; i++)
+               voltages_in_range += (rdev->desc->linear_ranges[i].max_sel -
+                                    rdev->desc->linear_ranges[i].min_sel) + 1;
+
+       return val + voltages_in_range;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap);
+
+/**
+ * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O and use pickable
+ * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
+ * fields in their descriptor and then use this as their set_voltage_vsel
+ * operation, saving some code.
+ */
+int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
+                                             unsigned int sel)
+{
+       unsigned int range;
+       int ret, i;
+       unsigned int voltages_in_range = 0;
+
+       for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+               voltages_in_range = (rdev->desc->linear_ranges[i].max_sel -
+                                    rdev->desc->linear_ranges[i].min_sel) + 1;
+               if (sel < voltages_in_range)
+                       break;
+               sel -= voltages_in_range;
+       }
+
+       if (i == rdev->desc->n_linear_ranges)
+               return -EINVAL;
+
+       sel <<= ffs(rdev->desc->vsel_mask) - 1;
+       sel += rdev->desc->linear_ranges[i].min_sel;
+
+       range = rdev->desc->linear_range_selectors[i];
+
+       if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) {
+               ret = regmap_update_bits(rdev->regmap,
+                                        rdev->desc->vsel_reg,
+                                        rdev->desc->vsel_range_mask |
+                                        rdev->desc->vsel_mask, sel | range);
+       } else {
+               ret = regmap_update_bits(rdev->regmap,
+                                        rdev->desc->vsel_range_reg,
+                                        rdev->desc->vsel_range_mask, range);
+               if (ret)
+                       return ret;
+
+               ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+                                 rdev->desc->vsel_mask, sel);
+       }
+
+       if (ret)
+               return ret;
+
+       if (rdev->desc->apply_bit)
+               ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+                                        rdev->desc->apply_bit,
+                                        rdev->desc->apply_bit);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_pickable_regmap);
+
 /**
  * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
  *
@@ -321,20 +443,91 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
 
                ret += range->min_sel;
 
-               break;
+               /*
+                * Map back into a voltage to verify we're still in bounds.
+                * If we are not, then continue checking rest of the ranges.
+                */
+               voltage = rdev->desc->ops->list_voltage(rdev, ret);
+               if (voltage >= min_uV && voltage <= max_uV)
+                       break;
        }
 
        if (i == rdev->desc->n_linear_ranges)
                return -EINVAL;
 
-       /* Map back into a voltage to verify we're still in bounds */
-       voltage = rdev->desc->ops->list_voltage(rdev, ret);
-       if (voltage < min_uV || voltage > max_uV)
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+
+/**
+ * regulator_map_voltage_pickable_linear_range - map_voltage, pickable ranges
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing pickable linear_ranges in their descriptor can use
+ * this as their map_voltage() callback.
+ */
+int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
+                                               int min_uV, int max_uV)
+{
+       const struct regulator_linear_range *range;
+       int ret = -EINVAL;
+       int voltage, i;
+       unsigned int selector = 0;
+
+       if (!rdev->desc->n_linear_ranges) {
+               BUG_ON(!rdev->desc->n_linear_ranges);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+               int linear_max_uV;
+
+               range = &rdev->desc->linear_ranges[i];
+               linear_max_uV = range->min_uV +
+                       (range->max_sel - range->min_sel) * range->uV_step;
+
+               if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) {
+                       selector += (range->max_sel - range->min_sel + 1);
+                       continue;
+               }
+
+               if (min_uV <= range->min_uV)
+                       min_uV = range->min_uV;
+
+               /* range->uV_step == 0 means fixed voltage range */
+               if (range->uV_step == 0) {
+                       ret = 0;
+               } else {
+                       ret = DIV_ROUND_UP(min_uV - range->min_uV,
+                                          range->uV_step);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               ret += selector;
+
+               voltage = rdev->desc->ops->list_voltage(rdev, ret);
+
+               /*
+                * Map back into a voltage to verify we're still in bounds.
+                * We may have overlapping voltage ranges. Hence we don't
+                * exit but retry until we have checked all ranges.
+                */
+               if (voltage < min_uV || voltage > max_uV)
+                       selector += (range->max_sel - range->min_sel + 1);
+               else
+                       break;
+       }
+
+       if (i == rdev->desc->n_linear_ranges)
                return -EINVAL;
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
 
 /**
  * regulator_list_voltage_linear - List voltages with simple calculation
@@ -360,6 +553,46 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
 
+/**
+ * regulator_list_voltage_pickable_linear_range - pickable range list voltages
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * list_voltage() operation, intended to be used by drivers utilizing pickable
+ * ranges helpers.
+ */
+int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev,
+                                                unsigned int selector)
+{
+       const struct regulator_linear_range *range;
+       int i;
+       unsigned int all_sels = 0;
+
+       if (!rdev->desc->n_linear_ranges) {
+               BUG_ON(!rdev->desc->n_linear_ranges);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+               unsigned int sels_in_range;
+
+               range = &rdev->desc->linear_ranges[i];
+
+               sels_in_range = range->max_sel - range->min_sel;
+
+               if (all_sels + sels_in_range >= selector) {
+                       selector -= all_sels;
+                       return range->min_uV + (range->uV_step * selector);
+               }
+
+               all_sels += (sels_in_range + 1);
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range);
+
 /**
  * regulator_list_voltage_linear_range - List voltages for linear ranges
  *
index 257c1943e7534276a058c9e98f015c26eafeb0ee..9c2607e912cf0339830e791e50d94b960e3e7b22 100644 (file)
@@ -84,6 +84,7 @@ static const struct regulator_desc isl9305_regulators[] = {
                .enable_mask =  ISL9305_DCD1_EN,
                .supply_name =  "VINDCD1",
                .ops =          &isl9305_ops,
+               .owner =        THIS_MODULE,
        },
        [ISL9305_DCD2] = {
                .name =         "DCD2",
@@ -98,6 +99,7 @@ static const struct regulator_desc isl9305_regulators[] = {
                .enable_mask =  ISL9305_DCD2_EN,
                .supply_name =  "VINDCD2",
                .ops =          &isl9305_ops,
+               .owner =        THIS_MODULE,
        },
        [ISL9305_LDO1] = {
                .name =         "LDO1",
@@ -112,6 +114,7 @@ static const struct regulator_desc isl9305_regulators[] = {
                .enable_mask =  ISL9305_LDO1_EN,
                .supply_name =  "VINLDO1",
                .ops =          &isl9305_ops,
+               .owner =        THIS_MODULE,
        },
        [ISL9305_LDO2] = {
                .name =         "LDO2",
@@ -126,6 +129,7 @@ static const struct regulator_desc isl9305_regulators[] = {
                .enable_mask =  ISL9305_LDO2_EN,
                .supply_name =  "VINLDO2",
                .ops =          &isl9305_ops,
+               .owner =        THIS_MODULE,
        },
 };
 
index b615a413ca9f6ff3f2313349be5edd38dabb0855..bbedb08d257b602e884ff1827422215302b0011c 100644 (file)
@@ -227,9 +227,11 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
         */
        switch (id) {
        case LM3632_LDO_POS:
-               return devm_gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW);
+               return devm_gpiod_get_index_optional(dev, "enable", 0,
+                               GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
        case LM3632_LDO_NEG:
-               return devm_gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW);
+               return devm_gpiod_get_index_optional(dev, "enable", 1,
+                               GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
        default:
                return NULL;
        }
diff --git a/drivers/regulator/lochnagar-regulator.c b/drivers/regulator/lochnagar-regulator.c
new file mode 100644 (file)
index 0000000..2b5073b
--- /dev/null
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Lochnagar regulator driver
+//
+// Copyright (c) 2017-2018 Cirrus Logic, Inc. and
+//                         Cirrus Logic International Semiconductor Ltd.
+//
+// Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <linux/mfd/lochnagar.h>
+
+static const struct regulator_ops lochnagar_micvdd_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
+
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_linear_range lochnagar_micvdd_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1000000, 0,    0xC, 50000),
+       REGULATOR_LINEAR_RANGE(1700000, 0xD, 0x1F, 100000),
+};
+
+static int lochnagar_micbias_enable(struct regulator_dev *rdev)
+{
+       struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
+       int ret;
+
+       mutex_lock(&lochnagar->analogue_config_lock);
+
+       ret = regulator_enable_regmap(rdev);
+       if (ret < 0)
+               goto err;
+
+       ret = lochnagar_update_config(lochnagar);
+
+err:
+       mutex_unlock(&lochnagar->analogue_config_lock);
+
+       return ret;
+}
+
+static int lochnagar_micbias_disable(struct regulator_dev *rdev)
+{
+       struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
+       int ret;
+
+       mutex_lock(&lochnagar->analogue_config_lock);
+
+       ret = regulator_disable_regmap(rdev);
+       if (ret < 0)
+               goto err;
+
+       ret = lochnagar_update_config(lochnagar);
+
+err:
+       mutex_unlock(&lochnagar->analogue_config_lock);
+
+       return ret;
+}
+
+static const struct regulator_ops lochnagar_micbias_ops = {
+       .enable = lochnagar_micbias_enable,
+       .disable = lochnagar_micbias_disable,
+       .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_ops lochnagar_vddcore_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
+
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_linear_range lochnagar_vddcore_ranges[] = {
+       REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500),
+};
+
+enum lochnagar_regulators {
+       LOCHNAGAR_MICVDD,
+       LOCHNAGAR_MIC1VDD,
+       LOCHNAGAR_MIC2VDD,
+       LOCHNAGAR_VDDCORE,
+};
+
+static int lochnagar_micbias_of_parse(struct device_node *np,
+                                     const struct regulator_desc *desc,
+                                     struct regulator_config *config)
+{
+       struct lochnagar *lochnagar = config->driver_data;
+       int shift = (desc->id - LOCHNAGAR_MIC1VDD) *
+                   LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
+       int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
+       unsigned int val;
+       int ret;
+
+       ret = of_property_read_u32(np, "cirrus,micbias-input", &val);
+       if (ret >= 0) {
+               mutex_lock(&lochnagar->analogue_config_lock);
+               ret = regmap_update_bits(lochnagar->regmap,
+                                        LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+                                        mask, val << shift);
+               mutex_unlock(&lochnagar->analogue_config_lock);
+               if (ret < 0) {
+                       dev_err(lochnagar->dev,
+                               "Failed to update micbias source: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct regulator_desc lochnagar_regulators[] = {
+       [LOCHNAGAR_MICVDD] = {
+               .name = "MICVDD",
+               .supply_name = "SYSVDD",
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 32,
+               .ops = &lochnagar_micvdd_ops,
+
+               .id = LOCHNAGAR_MICVDD,
+               .of_match = of_match_ptr("MICVDD"),
+
+               .enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
+               .enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
+               .vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
+               .vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
+
+               .linear_ranges = lochnagar_micvdd_ranges,
+               .n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges),
+
+               .enable_time = 3000,
+               .ramp_delay = 1000,
+
+               .owner = THIS_MODULE,
+       },
+       [LOCHNAGAR_MIC1VDD] = {
+               .name = "MIC1VDD",
+               .supply_name = "MICBIAS1",
+               .type = REGULATOR_VOLTAGE,
+               .ops = &lochnagar_micbias_ops,
+
+               .id = LOCHNAGAR_MIC1VDD,
+               .of_match = of_match_ptr("MIC1VDD"),
+               .of_parse_cb = lochnagar_micbias_of_parse,
+
+               .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+               .enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
+
+               .owner = THIS_MODULE,
+       },
+       [LOCHNAGAR_MIC2VDD] = {
+               .name = "MIC2VDD",
+               .supply_name = "MICBIAS2",
+               .type = REGULATOR_VOLTAGE,
+               .ops = &lochnagar_micbias_ops,
+
+               .id = LOCHNAGAR_MIC2VDD,
+               .of_match = of_match_ptr("MIC2VDD"),
+               .of_parse_cb = lochnagar_micbias_of_parse,
+
+               .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+               .enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
+
+               .owner = THIS_MODULE,
+       },
+       [LOCHNAGAR_VDDCORE] = {
+               .name = "VDDCORE",
+               .supply_name = "SYSVDD",
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 57,
+               .ops = &lochnagar_vddcore_ops,
+
+               .id = LOCHNAGAR_VDDCORE,
+               .of_match = of_match_ptr("VDDCORE"),
+
+               .enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
+               .enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
+               .vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
+               .vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
+
+               .linear_ranges = lochnagar_vddcore_ranges,
+               .n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges),
+
+               .enable_time = 3000,
+               .ramp_delay = 1000,
+
+               .owner = THIS_MODULE,
+       },
+};
+
+static int lochnagar_regulator_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
+       struct regulator_config config = { };
+       struct regulator_dev *rdev;
+       int ret, i;
+
+       config.dev = lochnagar->dev;
+       config.regmap = lochnagar->regmap;
+       config.driver_data = lochnagar;
+
+       for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
+               const struct regulator_desc *desc = &lochnagar_regulators[i];
+
+               rdev = devm_regulator_register(dev, desc, &config);
+               if (IS_ERR(rdev)) {
+                       ret = PTR_ERR(rdev);
+                       dev_err(dev, "Failed to register %s regulator: %d\n",
+                               desc->name, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static struct platform_driver lochnagar_regulator_driver = {
+       .driver = {
+               .name = "lochnagar-regulator",
+       },
+
+       .probe = lochnagar_regulator_probe,
+};
+module_platform_driver(lochnagar_regulator_driver);
+
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_DESCRIPTION("Regulator driver for Cirrus Logic Lochnagar Board");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lochnagar-regulator");
index f2347474a106ecdc4f0f012db0d7acdaf01f4b7a..553b4790050f6650a525155b64ccd4cc3c71a6e9 100644 (file)
@@ -503,9 +503,10 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
 
        /* FIXME: check default mode for GPIO here: high or low? */
        ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev,
-                                                      "enable",
-                                                      enable_id,
-                                                      GPIOD_OUT_HIGH);
+                                              "enable",
+                                              enable_id,
+                                              GPIOD_OUT_HIGH |
+                                              GPIOD_FLAGS_BIT_NONEXCLUSIVE);
        if (IS_ERR(ldo->ena_gpiod))
                return PTR_ERR(ldo->ena_gpiod);
 
index f1e77ed5dfec942d0a711c05c5bf4f59934a9bc6..6c39fff73b8acd61c57cb3fc7fc13c3af7a64bdc 100644 (file)
@@ -230,6 +230,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
                gflags = GPIOD_OUT_HIGH;
        else
                gflags = GPIOD_OUT_LOW;
+       gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
        gpiod = devm_gpiod_get_optional(&client->dev,
                                        "max8952,en",
                                        gflags);
index 7cd493ec63157b3007f391ac6acec2540440f254..e7a58b50903203f81b669b5fa2b51031d574a090 100644 (file)
@@ -758,6 +758,7 @@ static int max8973_probe(struct i2c_client *client,
                        gflags = GPIOD_OUT_HIGH;
                else
                        gflags = GPIOD_OUT_LOW;
+               gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
                gpiod = devm_gpiod_get_optional(&client->dev,
                                                "maxim,enable",
                                                gflags);
index ad0c806b07376e55307664542a899d329eb78df9..3bf5ddfaaea89d0cbebc5e70588759a8aa5b7d1a 100644 (file)
@@ -929,8 +929,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
                                break;
 
                if (i == ARRAY_SIZE(regulators)) {
-                       dev_warn(&pdev->dev, "don't know how to configure regulator %s\n",
-                                reg_np->name);
+                       dev_warn(&pdev->dev, "don't know how to configure regulator %pOFn\n",
+                                reg_np);
                        continue;
                }
 
index da4fb98247578546f2babe0f790d47ac71656237..65eb1e0350cfd3dc3f6df6d167bcf5e70a52fa2c 100644 (file)
@@ -203,7 +203,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
 
                if (!found)
                        dev_warn(&pdev->dev,
-                                "Unknown regulator: %s\n", child->name);
+                                "Unknown regulator: %pOFn\n", child);
        }
        of_node_put(parent);
 
index 210fc20f7de7a9cd26dbbee68e24a7c0bc2dc94a..c4223b3e0dffa6d846a153a7be468cfe4c6a70fb 100644 (file)
@@ -95,8 +95,8 @@ static void of_get_regulation_constraints(struct device_node *np,
        if (!ret)
                constraints->settling_time_up = pval;
        if (constraints->settling_time_up && constraints->settling_time) {
-               pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
-                       np->name);
+               pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
+                       np);
                constraints->settling_time_up = 0;
        }
 
@@ -105,8 +105,8 @@ static void of_get_regulation_constraints(struct device_node *np,
        if (!ret)
                constraints->settling_time_down = pval;
        if (constraints->settling_time_down && constraints->settling_time) {
-               pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
-                       np->name);
+               pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
+                       np);
                constraints->settling_time_down = 0;
        }
 
@@ -127,12 +127,12 @@ static void of_get_regulation_constraints(struct device_node *np,
                if (desc && desc->of_map_mode) {
                        mode = desc->of_map_mode(pval);
                        if (mode == REGULATOR_MODE_INVALID)
-                               pr_err("%s: invalid mode %u\n", np->name, pval);
+                               pr_err("%pOFn: invalid mode %u\n", np, pval);
                        else
                                constraints->initial_mode = mode;
                } else {
-                       pr_warn("%s: mapping for mode %d not defined\n",
-                               np->name, pval);
+                       pr_warn("%pOFn: mapping for mode %d not defined\n",
+                               np, pval);
                }
        }
 
@@ -144,14 +144,14 @@ static void of_get_regulation_constraints(struct device_node *np,
                                ret = of_property_read_u32_index(np,
                                        "regulator-allowed-modes", i, &pval);
                                if (ret) {
-                                       pr_err("%s: couldn't read allowed modes index %d, ret=%d\n",
-                                               np->name, i, ret);
+                                       pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n",
+                                               np, i, ret);
                                        break;
                                }
                                mode = desc->of_map_mode(pval);
                                if (mode == REGULATOR_MODE_INVALID)
-                                       pr_err("%s: invalid regulator-allowed-modes element %u\n",
-                                               np->name, pval);
+                                       pr_err("%pOFn: invalid regulator-allowed-modes element %u\n",
+                                               np, pval);
                                else
                                        constraints->valid_modes_mask |= mode;
                        }
@@ -159,7 +159,7 @@ static void of_get_regulation_constraints(struct device_node *np,
                                constraints->valid_ops_mask
                                        |= REGULATOR_CHANGE_MODE;
                } else {
-                       pr_warn("%s: mode mapping not defined\n", np->name);
+                       pr_warn("%pOFn: mode mapping not defined\n", np);
                }
        }
 
@@ -197,13 +197,13 @@ static void of_get_regulation_constraints(struct device_node *np,
                        if (desc && desc->of_map_mode) {
                                mode = desc->of_map_mode(pval);
                                if (mode == REGULATOR_MODE_INVALID)
-                                       pr_err("%s: invalid mode %u\n",
-                                              np->name, pval);
+                                       pr_err("%pOFn: invalid mode %u\n",
+                                              np, pval);
                                else
                                        suspend_state->mode = mode;
                        } else {
-                               pr_warn("%s: mapping for mode %d not defined\n",
-                                       np->name, pval);
+                               pr_warn("%pOFn: mapping for mode %d not defined\n",
+                                       np, pval);
                        }
                }
 
@@ -349,8 +349,8 @@ int of_regulator_match(struct device *dev, struct device_node *node,
                                                           match->desc);
                        if (!match->init_data) {
                                dev_err(dev,
-                                       "failed to parse DT for regulator %s\n",
-                                       child->name);
+                                       "failed to parse DT for regulator %pOFn\n",
+                                       child);
                                of_node_put(child);
                                return -EINVAL;
                        }
@@ -399,16 +399,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
                init_data = of_get_regulator_init_data(dev, child, desc);
                if (!init_data) {
                        dev_err(dev,
-                               "failed to parse DT for regulator %s\n",
-                               child->name);
+                               "failed to parse DT for regulator %pOFn\n",
+                               child);
                        break;
                }
 
                if (desc->of_parse_cb) {
                        if (desc->of_parse_cb(child, desc, config)) {
                                dev_err(dev,
-                                       "driver callback failed to parse DT for regulator %s\n",
-                                       child->name);
+                                       "driver callback failed to parse DT for regulator %pOFn\n",
+                                       child);
                                init_data = NULL;
                                break;
                        }
index 31c3a236120a80909ede26f29caa5288011d8cbf..dd41a9bb3f5c62b7b2ef32ce27895e0db1976ecc 100644 (file)
 
 #define PFUZE100_COINVOL       0x1a
 #define PFUZE100_SW1ABVOL      0x20
+#define PFUZE100_SW1ABMODE     0x23
 #define PFUZE100_SW1CVOL       0x2e
+#define PFUZE100_SW1CMODE      0x31
 #define PFUZE100_SW2VOL                0x35
+#define PFUZE100_SW2MODE       0x38
 #define PFUZE100_SW3AVOL       0x3c
+#define PFUZE100_SW3AMODE      0x3f
 #define PFUZE100_SW3BVOL       0x43
+#define PFUZE100_SW3BMODE      0x46
 #define PFUZE100_SW4VOL                0x4a
+#define PFUZE100_SW4MODE       0x4d
 #define PFUZE100_SWBSTCON1     0x66
 #define PFUZE100_VREFDDRCON    0x6a
 #define PFUZE100_VSNVSVOL      0x6b
 #define PFUZE100_VGEN5VOL      0x70
 #define PFUZE100_VGEN6VOL      0x71
 
+#define PFUZE100_SWxMODE_MASK  0xf
+#define PFUZE100_SWxMODE_APS_APS       0x8
+#define PFUZE100_SWxMODE_APS_OFF       0x4
+
+#define PFUZE100_VGENxLPWR     BIT(6)
+#define PFUZE100_VGENxSTBY     BIT(5)
+
 enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, };
 
 struct pfuze_regulator {
@@ -559,6 +572,69 @@ static inline struct device_node *match_of_node(int index)
 }
 #endif
 
+static struct pfuze_chip *syspm_pfuze_chip;
+
+static void pfuze_power_off_prepare(void)
+{
+       dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
+
+       /* Switch from default mode: APS/APS to APS/Off */
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE,
+                          PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE,
+                          PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE,
+                          PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE,
+                          PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE,
+                          PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE,
+                          PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL,
+                          PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+                          PFUZE100_VGENxSTBY);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL,
+                          PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+                          PFUZE100_VGENxSTBY);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL,
+                          PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+                          PFUZE100_VGENxSTBY);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL,
+                          PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+                          PFUZE100_VGENxSTBY);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL,
+                          PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+                          PFUZE100_VGENxSTBY);
+       regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL,
+                          PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+                          PFUZE100_VGENxSTBY);
+}
+
+static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
+{
+       if (pfuze_chip->chip_id != PFUZE100) {
+               dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n");
+               return -ENODEV;
+       }
+
+       if (pm_power_off_prepare) {
+               dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already registered.\n");
+               return -EBUSY;
+       }
+
+       if (syspm_pfuze_chip) {
+               dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
+               return -EBUSY;
+       }
+
+       syspm_pfuze_chip = pfuze_chip;
+       pm_power_off_prepare = pfuze_power_off_prepare;
+
+       return 0;
+}
+
 static int pfuze_identify(struct pfuze_chip *pfuze_chip)
 {
        unsigned int value;
@@ -753,6 +829,20 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
                }
        }
 
+       if (of_property_read_bool(client->dev.of_node,
+                                 "fsl,pmic-stby-poweroff"))
+               return pfuze_power_off_prepare_init(pfuze_chip);
+
+       return 0;
+}
+
+static int pfuze100_regulator_remove(struct i2c_client *client)
+{
+       if (syspm_pfuze_chip) {
+               syspm_pfuze_chip = NULL;
+               pm_power_off_prepare = NULL;
+       }
+
        return 0;
 }
 
@@ -763,6 +853,7 @@ static struct i2c_driver pfuze_driver = {
                .of_match_table = pfuze_dt_ids,
        },
        .probe = pfuze100_regulator_probe,
+       .remove = pfuze100_regulator_remove,
 };
 module_i2c_driver(pfuze_driver);
 
index 9f27daebd8c8adbfbbef158c7c633672a6f7c888..39ccf53fdeb38f1d7f039a47e4cc5baaad981b56 100644 (file)
@@ -414,7 +414,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
                        break;
 
        if (!rpmh_data->name) {
-               dev_err(dev, "Unknown regulator %s\n", node->name);
+               dev_err(dev, "Unknown regulator %pOFn\n", node);
                return -EINVAL;
        }
 
@@ -423,8 +423,8 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
 
        vreg->addr = cmd_db_read_addr(rpmh_resource_name);
        if (!vreg->addr) {
-               dev_err(dev, "%s: could not find RPMh address for resource %s\n",
-                       node->name, rpmh_resource_name);
+               dev_err(dev, "%pOFn: could not find RPMh address for resource %s\n",
+                       node, rpmh_resource_name);
                return -ENODEV;
        }
 
@@ -469,13 +469,13 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
        rdev = devm_regulator_register(dev, &vreg->rdesc, &reg_config);
        if (IS_ERR(rdev)) {
                ret = PTR_ERR(rdev);
-               dev_err(dev, "%s: devm_regulator_register() failed, ret=%d\n",
-                       node->name, ret);
+               dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n",
+                       node, ret);
                return ret;
        }
 
-       dev_dbg(dev, "%s regulator registered for RPMh resource %s @ 0x%05X\n",
-               node->name, rpmh_resource_name, vreg->addr);
+       dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n",
+               node, rpmh_resource_name, vreg->addr);
 
        return 0;
 }
@@ -504,6 +504,7 @@ static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
                break;
        default:
                mode = REGULATOR_MODE_INVALID;
+               break;
        }
 
        return mode;
@@ -537,6 +538,7 @@ rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode)
                break;
        default:
                mode = REGULATOR_MODE_INVALID;
+               break;
        }
 
        return mode;
@@ -566,6 +568,7 @@ static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode)
                break;
        default:
                mode = REGULATOR_MODE_INVALID;
+               break;
        }
 
        return mode;
index fe2fb36803e0bb7603f982ea3186cf7f5e0a7cfd..f5bca77d67c1e007dd7726df594b404d7ea87b89 100644 (file)
@@ -420,6 +420,60 @@ static const struct regulator_desc pmi8998_bob = {
        .ops = &rpm_bob_ops,
 };
 
+static const struct regulator_desc pms405_hfsmps3 = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 216,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_nldo300 = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 128,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_nldo1200 = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 128,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo50 = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 129,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo150 = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 129,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo600 = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(1256000, 0, 98, 8000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 99,
+       .ops = &rpm_smps_ldo_ops,
+};
+
 struct rpm_regulator_data {
        const char *name;
        u32 type;
@@ -661,6 +715,28 @@ static const struct rpm_regulator_data rpm_pmi8998_regulators[] = {
        {}
 };
 
+static const struct rpm_regulator_data rpm_pms405_regulators[] = {
+       { "s1", QCOM_SMD_RPM_SMPA, 1, &pms405_hfsmps3, "vdd_s1" },
+       { "s2", QCOM_SMD_RPM_SMPA, 2, &pms405_hfsmps3, "vdd_s2" },
+       { "s3", QCOM_SMD_RPM_SMPA, 3, &pms405_hfsmps3, "vdd_s3" },
+       { "s4", QCOM_SMD_RPM_SMPA, 4, &pms405_hfsmps3, "vdd_s4" },
+       { "s5", QCOM_SMD_RPM_SMPA, 5, &pms405_hfsmps3, "vdd_s5" },
+       { "l1", QCOM_SMD_RPM_LDOA, 1, &pms405_nldo1200, "vdd_l1_l2" },
+       { "l2", QCOM_SMD_RPM_LDOA, 2, &pms405_nldo1200, "vdd_l1_l2" },
+       { "l3", QCOM_SMD_RPM_LDOA, 3, &pms405_nldo1200, "vdd_l3_l8" },
+       { "l4", QCOM_SMD_RPM_LDOA, 4, &pms405_nldo300, "vdd_l4" },
+       { "l5", QCOM_SMD_RPM_LDOA, 5, &pms405_pldo600, "vdd_l5_l6" },
+       { "l6", QCOM_SMD_RPM_LDOA, 6, &pms405_pldo600, "vdd_l5_l6" },
+       { "l7", QCOM_SMD_RPM_LDOA, 7, &pms405_pldo150, "vdd_l7" },
+       { "l8", QCOM_SMD_RPM_LDOA, 8, &pms405_nldo1200, "vdd_l3_l8" },
+       { "l9", QCOM_SMD_RPM_LDOA, 9, &pms405_nldo1200, "vdd_l9" },
+       { "l10", QCOM_SMD_RPM_LDOA, 10, &pms405_pldo50, "vdd_l10_l11_l12_l13" },
+       { "l11", QCOM_SMD_RPM_LDOA, 11, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+       { "l12", QCOM_SMD_RPM_LDOA, 12, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+       { "l13", QCOM_SMD_RPM_LDOA, 13, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+       {}
+};
+
 static const struct of_device_id rpm_of_match[] = {
        { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
        { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
@@ -669,6 +745,7 @@ static const struct of_device_id rpm_of_match[] = {
        { .compatible = "qcom,rpm-pm8998-regulators", .data = &rpm_pm8998_regulators },
        { .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
        { .compatible = "qcom,rpm-pmi8998-regulators", .data = &rpm_pmi8998_regulators },
+       { .compatible = "qcom,rpm-pms405-regulators", .data = &rpm_pms405_regulators },
        {}
 };
 MODULE_DEVICE_TABLE(of, rpm_of_match);
index 667d16dc83ce1506737ddc6c10fa072d31d558d9..219b9afda0cb937c6cecd424c7481b339348c4d1 100644 (file)
@@ -447,15 +447,15 @@ static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
        }
        if (mode != S5M8767_ENCTRL_USE_GPIO) {
                dev_warn(s5m8767->dev,
-                               "ext-control for %s: mismatched op_mode (%x), ignoring\n",
-                               rdata->reg_node->name, mode);
+                               "ext-control for %pOFn: mismatched op_mode (%x), ignoring\n",
+                               rdata->reg_node, mode);
                return;
        }
 
        if (!rdata->ext_control_gpiod) {
                dev_warn(s5m8767->dev,
-                               "ext-control for %s: GPIO not valid, ignoring\n",
-                        rdata->reg_node->name);
+                               "ext-control for %pOFn: GPIO not valid, ignoring\n",
+                        rdata->reg_node);
                return;
        }
 
@@ -566,17 +566,18 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
 
                if (i == ARRAY_SIZE(regulators)) {
                        dev_warn(iodev->dev,
-                       "don't know how to configure regulator %s\n",
-                       reg_np->name);
+                       "don't know how to configure regulator %pOFn\n",
+                       reg_np);
                        continue;
                }
 
-               rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(&pdev->dev,
-                                                                      reg_np,
-                                                                      "s5m8767,pmic-ext-control-gpios",
-                                                                      0,
-                                                                      GPIOD_OUT_HIGH,
-                                                                      "s5m8767");
+               rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(
+                       &pdev->dev,
+                       reg_np,
+                       "s5m8767,pmic-ext-control-gpios",
+                       0,
+                       GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+                       "s5m8767");
                if (IS_ERR(rdata->ext_control_gpiod))
                        return PTR_ERR(rdata->ext_control_gpiod);
 
diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c
new file mode 100644 (file)
index 0000000..e15634e
--- /dev/null
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2018
+// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+
+#include <linux/interrupt.h>
+#include <linux/mfd/stpmic1.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+/**
+ * stpmic1 regulator description
+ * @desc: regulator framework description
+ * @mask_reset_reg: mask reset register address
+ * @mask_reset_mask: mask rank and mask reset register mask
+ * @icc_reg: icc register address
+ * @icc_mask: icc register mask
+ */
+struct stpmic1_regulator_cfg {
+       struct regulator_desc desc;
+       u8 mask_reset_reg;
+       u8 mask_reset_mask;
+       u8 icc_reg;
+       u8 icc_mask;
+};
+
+/**
+ * stpmic1 regulator data: this structure is used as driver data
+ * @regul_id: regulator id
+ * @reg_node: DT node of regulator (unused on non-DT platforms)
+ * @cfg: stpmic specific regulator description
+ * @mask_reset: mask_reset bit value
+ * @irq_curlim: current limit interrupt number
+ * @regmap: point to parent regmap structure
+ */
+struct stpmic1_regulator {
+       unsigned int regul_id;
+       struct device_node *reg_node;
+       struct stpmic1_regulator_cfg *cfg;
+       u8 mask_reset;
+       int irq_curlim;
+       struct regmap *regmap;
+};
+
+static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode);
+static unsigned int stpmic1_get_mode(struct regulator_dev *rdev);
+static int stpmic1_set_icc(struct regulator_dev *rdev);
+static int stpmic1_regulator_parse_dt(void *driver_data);
+static unsigned int stpmic1_map_mode(unsigned int mode);
+
+enum {
+       STPMIC1_BUCK1 = 0,
+       STPMIC1_BUCK2 = 1,
+       STPMIC1_BUCK3 = 2,
+       STPMIC1_BUCK4 = 3,
+       STPMIC1_LDO1 = 4,
+       STPMIC1_LDO2 = 5,
+       STPMIC1_LDO3 = 6,
+       STPMIC1_LDO4 = 7,
+       STPMIC1_LDO5 = 8,
+       STPMIC1_LDO6 = 9,
+       STPMIC1_VREF_DDR = 10,
+       STPMIC1_BOOST = 11,
+       STPMIC1_VBUS_OTG = 12,
+       STPMIC1_SW_OUT = 13,
+};
+
+/* Enable time worst case is 5000mV/(2250uV/uS) */
+#define PMIC_ENABLE_TIME_US 2200
+
+#define STPMIC1_BUCK_MODE_NORMAL 0
+#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK
+
+struct regulator_linear_range buck1_ranges[] = {
+       REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000),
+       REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0),
+};
+
+struct regulator_linear_range buck2_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1000000, 0, 17, 0),
+       REGULATOR_LINEAR_RANGE(1050000, 18, 19, 0),
+       REGULATOR_LINEAR_RANGE(1100000, 20, 21, 0),
+       REGULATOR_LINEAR_RANGE(1150000, 22, 23, 0),
+       REGULATOR_LINEAR_RANGE(1200000, 24, 25, 0),
+       REGULATOR_LINEAR_RANGE(1250000, 26, 27, 0),
+       REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0),
+       REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0),
+       REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0),
+       REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0),
+       REGULATOR_LINEAR_RANGE(1500000, 36, 63, 0),
+};
+
+struct regulator_linear_range buck3_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1000000, 0, 19, 0),
+       REGULATOR_LINEAR_RANGE(1100000, 20, 23, 0),
+       REGULATOR_LINEAR_RANGE(1200000, 24, 27, 0),
+       REGULATOR_LINEAR_RANGE(1300000, 28, 31, 0),
+       REGULATOR_LINEAR_RANGE(1400000, 32, 35, 0),
+       REGULATOR_LINEAR_RANGE(1500000, 36, 55, 100000),
+       REGULATOR_LINEAR_RANGE(3400000, 56, 63, 0),
+
+};
+
+struct regulator_linear_range buck4_ranges[] = {
+       REGULATOR_LINEAR_RANGE(600000, 0, 27, 25000),
+       REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0),
+       REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0),
+       REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0),
+       REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0),
+       REGULATOR_LINEAR_RANGE(1500000, 36, 60, 100000),
+       REGULATOR_LINEAR_RANGE(3900000, 61, 63, 0),
+
+};
+
+struct regulator_linear_range ldo1_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+       REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+       REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0),
+
+};
+
+struct regulator_linear_range ldo2_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+       REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+       REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0),
+
+};
+
+struct regulator_linear_range ldo3_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+       REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+       REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0),
+       /* with index 31 LDO3 is in DDR mode */
+       REGULATOR_LINEAR_RANGE(500000, 31, 31, 0),
+};
+
+struct regulator_linear_range ldo5_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+       REGULATOR_LINEAR_RANGE(1700000, 8, 30, 100000),
+       REGULATOR_LINEAR_RANGE(3900000, 31, 31, 0),
+};
+
+struct regulator_linear_range ldo6_ranges[] = {
+       REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000),
+       REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0),
+};
+
+static struct regulator_ops stpmic1_ldo_ops = {
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .set_pull_down = regulator_set_pull_down_regmap,
+       .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_ldo3_ops = {
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_iterate,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .set_pull_down = regulator_set_pull_down_regmap,
+       .get_bypass = regulator_get_bypass_regmap,
+       .set_bypass = regulator_set_bypass_regmap,
+       .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = {
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .set_pull_down = regulator_set_pull_down_regmap,
+       .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_buck_ops = {
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .set_pull_down = regulator_set_pull_down_regmap,
+       .set_mode = stpmic1_set_mode,
+       .get_mode = stpmic1_get_mode,
+       .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_vref_ddr_ops = {
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .set_pull_down = regulator_set_pull_down_regmap,
+};
+
+static struct regulator_ops stpmic1_switch_regul_ops = {
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .set_over_current_protection = stpmic1_set_icc,
+};
+
+#define REG_LDO(ids, base) { \
+       .name = #ids, \
+       .id = STPMIC1_##ids, \
+       .n_voltages = 32, \
+       .ops = &stpmic1_ldo_ops, \
+       .linear_ranges = base ## _ranges, \
+       .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \
+       .type = REGULATOR_VOLTAGE, \
+       .owner = THIS_MODULE, \
+       .vsel_reg = ids##_ACTIVE_CR, \
+       .vsel_mask = LDO_VOLTAGE_MASK, \
+       .enable_reg = ids##_ACTIVE_CR, \
+       .enable_mask = LDO_ENABLE_MASK, \
+       .enable_val = 1, \
+       .disable_val = 0, \
+       .enable_time = PMIC_ENABLE_TIME_US, \
+       .pull_down_reg = ids##_PULL_DOWN_REG, \
+       .pull_down_mask = ids##_PULL_DOWN_MASK, \
+       .supply_name = #base, \
+}
+
+#define REG_LDO3(ids, base) { \
+       .name = #ids, \
+       .id = STPMIC1_##ids, \
+       .n_voltages = 32, \
+       .ops = &stpmic1_ldo3_ops, \
+       .linear_ranges = ldo3_ranges, \
+       .n_linear_ranges = ARRAY_SIZE(ldo3_ranges), \
+       .type = REGULATOR_VOLTAGE, \
+       .owner = THIS_MODULE, \
+       .vsel_reg = LDO3_ACTIVE_CR, \
+       .vsel_mask = LDO_VOLTAGE_MASK, \
+       .enable_reg = LDO3_ACTIVE_CR, \
+       .enable_mask = LDO_ENABLE_MASK, \
+       .enable_val = 1, \
+       .disable_val = 0, \
+       .enable_time = PMIC_ENABLE_TIME_US, \
+       .bypass_reg = LDO3_ACTIVE_CR, \
+       .bypass_mask = LDO_BYPASS_MASK, \
+       .bypass_val_on = LDO_BYPASS_MASK, \
+       .bypass_val_off = 0, \
+       .pull_down_reg = ids##_PULL_DOWN_REG, \
+       .pull_down_mask = ids##_PULL_DOWN_MASK, \
+       .supply_name = #base, \
+}
+
+#define REG_LDO4(ids, base) { \
+       .name = #ids, \
+       .id = STPMIC1_##ids, \
+       .n_voltages = 1, \
+       .ops = &stpmic1_ldo4_fixed_regul_ops, \
+       .type = REGULATOR_VOLTAGE, \
+       .owner = THIS_MODULE, \
+       .min_uV = 3300000, \
+       .fixed_uV = 3300000, \
+       .enable_reg = LDO4_ACTIVE_CR, \
+       .enable_mask = LDO_ENABLE_MASK, \
+       .enable_val = 1, \
+       .disable_val = 0, \
+       .enable_time = PMIC_ENABLE_TIME_US, \
+       .pull_down_reg = ids##_PULL_DOWN_REG, \
+       .pull_down_mask = ids##_PULL_DOWN_MASK, \
+       .supply_name = #base, \
+}
+
+#define REG_BUCK(ids, base) { \
+       .name = #ids, \
+       .id = STPMIC1_##ids, \
+       .ops = &stpmic1_buck_ops, \
+       .n_voltages = 64, \
+       .linear_ranges = base ## _ranges, \
+       .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \
+       .type = REGULATOR_VOLTAGE, \
+       .owner = THIS_MODULE, \
+       .vsel_reg = ids##_ACTIVE_CR, \
+       .vsel_mask = BUCK_VOLTAGE_MASK, \
+       .enable_reg = ids##_ACTIVE_CR, \
+       .enable_mask = BUCK_ENABLE_MASK, \
+       .enable_val = 1, \
+       .disable_val = 0, \
+       .enable_time = PMIC_ENABLE_TIME_US, \
+       .of_map_mode = stpmic1_map_mode, \
+       .pull_down_reg = ids##_PULL_DOWN_REG, \
+       .pull_down_mask = ids##_PULL_DOWN_MASK, \
+       .supply_name = #base, \
+}
+
+#define REG_VREF_DDR(ids, base) { \
+       .name = #ids, \
+       .id = STPMIC1_##ids, \
+       .n_voltages = 1, \
+       .ops = &stpmic1_vref_ddr_ops, \
+       .type = REGULATOR_VOLTAGE, \
+       .owner = THIS_MODULE, \
+       .min_uV = 500000, \
+       .fixed_uV = 500000, \
+       .enable_reg = VREF_DDR_ACTIVE_CR, \
+       .enable_mask = BUCK_ENABLE_MASK, \
+       .enable_val = 1, \
+       .disable_val = 0, \
+       .enable_time = PMIC_ENABLE_TIME_US, \
+       .pull_down_reg = ids##_PULL_DOWN_REG, \
+       .pull_down_mask = ids##_PULL_DOWN_MASK, \
+       .supply_name = #base, \
+}
+
+#define REG_SWITCH(ids, base, reg, mask, val) { \
+       .name = #ids, \
+       .id = STPMIC1_##ids, \
+       .n_voltages = 1, \
+       .ops = &stpmic1_switch_regul_ops, \
+       .type = REGULATOR_VOLTAGE, \
+       .owner = THIS_MODULE, \
+       .min_uV = 0, \
+       .fixed_uV = 5000000, \
+       .enable_reg = (reg), \
+       .enable_mask = (mask), \
+       .enable_val = (val), \
+       .disable_val = 0, \
+       .enable_time = PMIC_ENABLE_TIME_US, \
+       .supply_name = #base, \
+}
+
+struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = {
+       [STPMIC1_BUCK1] = {
+               .desc = REG_BUCK(BUCK1, buck1),
+               .icc_reg = BUCKS_ICCTO_CR,
+               .icc_mask = BIT(0),
+               .mask_reset_reg = BUCKS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(0),
+       },
+       [STPMIC1_BUCK2] = {
+               .desc = REG_BUCK(BUCK2, buck2),
+               .icc_reg = BUCKS_ICCTO_CR,
+               .icc_mask = BIT(1),
+               .mask_reset_reg = BUCKS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(1),
+       },
+       [STPMIC1_BUCK3] = {
+               .desc = REG_BUCK(BUCK3, buck3),
+               .icc_reg = BUCKS_ICCTO_CR,
+               .icc_mask = BIT(2),
+               .mask_reset_reg = BUCKS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(2),
+       },
+       [STPMIC1_BUCK4] = {
+               .desc = REG_BUCK(BUCK4, buck4),
+               .icc_reg = BUCKS_ICCTO_CR,
+               .icc_mask = BIT(3),
+               .mask_reset_reg = BUCKS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(3),
+       },
+       [STPMIC1_LDO1] = {
+               .desc = REG_LDO(LDO1, ldo1),
+               .icc_reg = LDOS_ICCTO_CR,
+               .icc_mask = BIT(0),
+               .mask_reset_reg = LDOS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(0),
+       },
+       [STPMIC1_LDO2] = {
+               .desc = REG_LDO(LDO2, ldo2),
+               .icc_reg = LDOS_ICCTO_CR,
+               .icc_mask = BIT(1),
+               .mask_reset_reg = LDOS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(1),
+       },
+       [STPMIC1_LDO3] = {
+               .desc = REG_LDO3(LDO3, ldo3),
+               .icc_reg = LDOS_ICCTO_CR,
+               .icc_mask = BIT(2),
+               .mask_reset_reg = LDOS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(2),
+       },
+       [STPMIC1_LDO4] = {
+               .desc = REG_LDO4(LDO4, ldo4),
+               .icc_reg = LDOS_ICCTO_CR,
+               .icc_mask = BIT(3),
+               .mask_reset_reg = LDOS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(3),
+       },
+       [STPMIC1_LDO5] = {
+               .desc = REG_LDO(LDO5, ldo5),
+               .icc_reg = LDOS_ICCTO_CR,
+               .icc_mask = BIT(4),
+               .mask_reset_reg = LDOS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(4),
+       },
+       [STPMIC1_LDO6] = {
+               .desc = REG_LDO(LDO6, ldo6),
+               .icc_reg = LDOS_ICCTO_CR,
+               .icc_mask = BIT(5),
+               .mask_reset_reg = LDOS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(5),
+       },
+       [STPMIC1_VREF_DDR] = {
+               .desc = REG_VREF_DDR(VREF_DDR, vref_ddr),
+               .mask_reset_reg = LDOS_MASK_RESET_CR,
+               .mask_reset_mask = BIT(6),
+       },
+       [STPMIC1_BOOST] = {
+               .desc = REG_SWITCH(BOOST, boost, BST_SW_CR,
+                                  BOOST_ENABLED,
+                                  BOOST_ENABLED),
+               .icc_reg = BUCKS_ICCTO_CR,
+               .icc_mask = BIT(6),
+       },
+       [STPMIC1_VBUS_OTG] = {
+               .desc = REG_SWITCH(VBUS_OTG, pwr_sw1, BST_SW_CR,
+                                  USBSW_OTG_SWITCH_ENABLED,
+                                  USBSW_OTG_SWITCH_ENABLED),
+               .icc_reg = BUCKS_ICCTO_CR,
+               .icc_mask = BIT(4),
+       },
+       [STPMIC1_SW_OUT] = {
+               .desc = REG_SWITCH(SW_OUT, pwr_sw2, BST_SW_CR,
+                                  SWIN_SWOUT_ENABLED,
+                                  SWIN_SWOUT_ENABLED),
+               .icc_reg = BUCKS_ICCTO_CR,
+               .icc_mask = BIT(5),
+       },
+};
+
+static unsigned int stpmic1_map_mode(unsigned int mode)
+{
+       switch (mode) {
+       case STPMIC1_BUCK_MODE_NORMAL:
+               return REGULATOR_MODE_NORMAL;
+       case STPMIC1_BUCK_MODE_LP:
+               return REGULATOR_MODE_STANDBY;
+       default:
+               return REGULATOR_MODE_INVALID;
+       }
+}
+
+static unsigned int stpmic1_get_mode(struct regulator_dev *rdev)
+{
+       int value;
+
+       regmap_read(rdev->regmap, rdev->desc->enable_reg, &value);
+
+       if (value & STPMIC1_BUCK_MODE_LP)
+               return REGULATOR_MODE_STANDBY;
+
+       return REGULATOR_MODE_NORMAL;
+}
+
+static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       int value;
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               value = STPMIC1_BUCK_MODE_NORMAL;
+               break;
+       case REGULATOR_MODE_STANDBY:
+               value = STPMIC1_BUCK_MODE_LP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                                 STPMIC1_BUCK_MODE_LP, value);
+}
+
+static int stpmic1_set_icc(struct regulator_dev *rdev)
+{
+       struct stpmic1_regulator *regul = rdev_get_drvdata(rdev);
+
+       /* enable switch off in case of over current */
+       return regmap_update_bits(regul->regmap, regul->cfg->icc_reg,
+                                 regul->cfg->icc_mask, regul->cfg->icc_mask);
+}
+
+static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data)
+{
+       struct regulator_dev *rdev = (struct regulator_dev *)data;
+
+       mutex_lock(&rdev->mutex);
+
+       /* Send an overcurrent notification */
+       regulator_notifier_call_chain(rdev,
+                                     REGULATOR_EVENT_OVER_CURRENT,
+                                     NULL);
+
+       mutex_unlock(&rdev->mutex);
+
+       return IRQ_HANDLED;
+}
+
+static int stpmic1_regulator_init(struct platform_device *pdev,
+                                 struct regulator_dev *rdev)
+{
+       struct stpmic1_regulator *regul = rdev_get_drvdata(rdev);
+       int ret = 0;
+
+       /* set mask reset */
+       if (regul->mask_reset && regul->cfg->mask_reset_reg != 0) {
+               ret = regmap_update_bits(regul->regmap,
+                                        regul->cfg->mask_reset_reg,
+                                        regul->cfg->mask_reset_mask,
+                                        regul->cfg->mask_reset_mask);
+               if (ret) {
+                       dev_err(&pdev->dev, "set mask reset failed\n");
+                       return ret;
+               }
+       }
+
+       /* setup an irq handler for over-current detection */
+       if (regul->irq_curlim > 0) {
+               ret = devm_request_threaded_irq(&pdev->dev,
+                                               regul->irq_curlim, NULL,
+                                               stpmic1_curlim_irq_handler,
+                                               IRQF_ONESHOT | IRQF_SHARED,
+                                               pdev->name, rdev);
+               if (ret) {
+                       dev_err(&pdev->dev, "Request IRQ failed\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+#define MATCH(_name, _id) \
+       [STPMIC1_##_id] = { \
+               .name = #_name, \
+               .desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \
+       }
+
+static struct of_regulator_match stpmic1_regulators_matches[] = {
+       MATCH(buck1, BUCK1),
+       MATCH(buck2, BUCK2),
+       MATCH(buck3, BUCK3),
+       MATCH(buck4, BUCK4),
+       MATCH(ldo1, LDO1),
+       MATCH(ldo2, LDO2),
+       MATCH(ldo3, LDO3),
+       MATCH(ldo4, LDO4),
+       MATCH(ldo5, LDO5),
+       MATCH(ldo6, LDO6),
+       MATCH(vref_ddr, VREF_DDR),
+       MATCH(boost, BOOST),
+       MATCH(pwr_sw1, VBUS_OTG),
+       MATCH(pwr_sw2, SW_OUT),
+};
+
+static int stpmic1_regulator_parse_dt(void *driver_data)
+{
+       struct stpmic1_regulator *regul =
+               (struct stpmic1_regulator *)driver_data;
+
+       if (!regul)
+               return -EINVAL;
+
+       if (of_get_property(regul->reg_node, "st,mask-reset", NULL))
+               regul->mask_reset = 1;
+
+       regul->irq_curlim = of_irq_get(regul->reg_node, 0);
+
+       return 0;
+}
+
+static struct
+regulator_dev *stpmic1_regulator_register(struct platform_device *pdev, int id,
+                                         struct regulator_init_data *init_data,
+                                         struct stpmic1_regulator *regul)
+{
+       struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_dev *rdev;
+       struct regulator_config config = {};
+
+       config.dev = &pdev->dev;
+       config.init_data = init_data;
+       config.of_node = stpmic1_regulators_matches[id].of_node;
+       config.regmap = pmic_dev->regmap;
+       config.driver_data = regul;
+
+       regul->regul_id = id;
+       regul->reg_node = config.of_node;
+       regul->cfg = &stpmic1_regulator_cfgs[id];
+       regul->regmap = pmic_dev->regmap;
+
+       rdev = devm_regulator_register(&pdev->dev, &regul->cfg->desc, &config);
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "failed to register %s regulator\n",
+                       regul->cfg->desc.name);
+       }
+
+       return rdev;
+}
+
+static int stpmic1_regulator_probe(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev;
+       struct stpmic1_regulator *regul;
+       struct regulator_init_data *init_data;
+       struct device_node *np;
+       int i, ret;
+
+       np = pdev->dev.of_node;
+
+       ret = of_regulator_match(&pdev->dev, np,
+                                stpmic1_regulators_matches,
+                                ARRAY_SIZE(stpmic1_regulators_matches));
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "Error in PMIC regulator device tree node");
+               return ret;
+       }
+
+       regul = devm_kzalloc(&pdev->dev, ARRAY_SIZE(stpmic1_regulator_cfgs) *
+                            sizeof(struct stpmic1_regulator),
+                            GFP_KERNEL);
+       if (!regul)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) {
+               /* Parse DT & find regulators to register */
+               init_data = stpmic1_regulators_matches[i].init_data;
+               if (init_data)
+                       init_data->regulator_init = &stpmic1_regulator_parse_dt;
+
+               rdev = stpmic1_regulator_register(pdev, i, init_data, regul);
+               if (IS_ERR(rdev))
+                       return PTR_ERR(rdev);
+
+               ret = stpmic1_regulator_init(pdev, rdev);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed to initialize regulator %d\n", ret);
+                       return ret;
+               }
+
+               regul++;
+       }
+
+       dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n");
+
+       return 0;
+}
+
+static const struct of_device_id of_pmic_regulator_match[] = {
+       { .compatible = "st,stpmic1-regulators" },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, of_pmic_regulator_match);
+
+static struct platform_driver stpmic1_regulator_driver = {
+       .driver = {
+               .name = "stpmic1-regulator",
+               .of_match_table = of_match_ptr(of_pmic_regulator_match),
+       },
+       .probe = stpmic1_regulator_probe,
+};
+
+module_platform_driver(stpmic1_regulator_driver);
+
+MODULE_DESCRIPTION("STPMIC1 PMIC voltage regulator driver");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
index edaef9e4dc74ea7e1994343a2e2eb6a4e7bf02ef..db714d5edafc8846285b2bf500e4eb1a4ab334aa 100644 (file)
@@ -374,6 +374,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
                                gflags = GPIOD_OUT_HIGH;
                        else
                                gflags = GPIOD_OUT_LOW;
+                       gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
 
                        rpdata->gpiod = devm_gpiod_get_from_of_node(&pdev->dev,
                                                                    tps65090_matches[idx].of_node,
index 21ddbe4400308ee51e8b29fe85acfe08022879ec..33695a1d8b35bf32b2eb3566513b3a16236fc151 100644 (file)
@@ -30,6 +30,7 @@ struct gpio_descs {
 #define GPIOD_FLAGS_BIT_DIR_OUT                BIT(1)
 #define GPIOD_FLAGS_BIT_DIR_VAL                BIT(2)
 #define GPIOD_FLAGS_BIT_OPEN_DRAIN     BIT(3)
+#define GPIOD_FLAGS_BIT_NONEXCLUSIVE   BIT(4)
 
 /**
  * Optional flags that can be passed to one of gpiod_* to configure direction
index e8338e5dc10bfd5e6bb415337ff3667c39e008f1..fd194bfc836f49f79bae3a5c0403ed945a860f1c 100644 (file)
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 /* Copyright (C) 2018 ROHM Semiconductors */
 
-#ifndef __LINUX_MFD_BD71837_H__
-#define __LINUX_MFD_BD71837_H__
+#ifndef __LINUX_MFD_BD718XX_H__
+#define __LINUX_MFD_BD718XX_H__
 
 #include <linux/regmap.h>
 
 enum {
-       BD71837_BUCK1   =       0,
-       BD71837_BUCK2,
-       BD71837_BUCK3,
-       BD71837_BUCK4,
-       BD71837_BUCK5,
-       BD71837_BUCK6,
-       BD71837_BUCK7,
-       BD71837_BUCK8,
-       BD71837_LDO1,
-       BD71837_LDO2,
-       BD71837_LDO3,
-       BD71837_LDO4,
-       BD71837_LDO5,
-       BD71837_LDO6,
-       BD71837_LDO7,
-       BD71837_REGULATOR_CNT,
+       BD718XX_TYPE_BD71837 = 0,
+       BD718XX_TYPE_BD71847,
+       BD718XX_TYPE_AMOUNT
 };
 
-#define BD71837_BUCK1_VOLTAGE_NUM      0x40
-#define BD71837_BUCK2_VOLTAGE_NUM      0x40
-#define BD71837_BUCK3_VOLTAGE_NUM      0x40
-#define BD71837_BUCK4_VOLTAGE_NUM      0x40
+enum {
+       BD718XX_BUCK1 = 0,
+       BD718XX_BUCK2,
+       BD718XX_BUCK3,
+       BD718XX_BUCK4,
+       BD718XX_BUCK5,
+       BD718XX_BUCK6,
+       BD718XX_BUCK7,
+       BD718XX_BUCK8,
+       BD718XX_LDO1,
+       BD718XX_LDO2,
+       BD718XX_LDO3,
+       BD718XX_LDO4,
+       BD718XX_LDO5,
+       BD718XX_LDO6,
+       BD718XX_LDO7,
+       BD718XX_REGULATOR_AMOUNT,
+};
+
+/* Common voltage configurations */
+#define BD718XX_DVS_BUCK_VOLTAGE_NUM           0x3D
+#define BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM     0x3D
 
-#define BD71837_BUCK5_VOLTAGE_NUM      0x08
+#define BD718XX_LDO1_VOLTAGE_NUM       0x08
+#define BD718XX_LDO2_VOLTAGE_NUM       0x02
+#define BD718XX_LDO3_VOLTAGE_NUM       0x10
+#define BD718XX_LDO4_VOLTAGE_NUM       0x0A
+#define BD718XX_LDO6_VOLTAGE_NUM       0x0A
+
+/* BD71837 specific voltage configurations */
+#define BD71837_BUCK5_VOLTAGE_NUM      0x10
 #define BD71837_BUCK6_VOLTAGE_NUM      0x04
 #define BD71837_BUCK7_VOLTAGE_NUM      0x08
-#define BD71837_BUCK8_VOLTAGE_NUM      0x40
-
-#define BD71837_LDO1_VOLTAGE_NUM       0x04
-#define BD71837_LDO2_VOLTAGE_NUM       0x02
-#define BD71837_LDO3_VOLTAGE_NUM       0x10
-#define BD71837_LDO4_VOLTAGE_NUM       0x10
 #define BD71837_LDO5_VOLTAGE_NUM       0x10
-#define BD71837_LDO6_VOLTAGE_NUM       0x10
 #define BD71837_LDO7_VOLTAGE_NUM       0x10
 
+/* BD71847 specific voltage configurations */
+#define BD71847_BUCK3_VOLTAGE_NUM      0x18
+#define BD71847_BUCK4_VOLTAGE_NUM      0x08
+#define BD71847_LDO5_VOLTAGE_NUM       0x20
+
+/* Registers specific to BD71837 */
 enum {
-       BD71837_REG_REV                = 0x00,
-       BD71837_REG_SWRESET            = 0x01,
-       BD71837_REG_I2C_DEV            = 0x02,
-       BD71837_REG_PWRCTRL0           = 0x03,
-       BD71837_REG_PWRCTRL1           = 0x04,
-       BD71837_REG_BUCK1_CTRL         = 0x05,
-       BD71837_REG_BUCK2_CTRL         = 0x06,
-       BD71837_REG_BUCK3_CTRL         = 0x07,
-       BD71837_REG_BUCK4_CTRL         = 0x08,
-       BD71837_REG_BUCK5_CTRL         = 0x09,
-       BD71837_REG_BUCK6_CTRL         = 0x0A,
-       BD71837_REG_BUCK7_CTRL         = 0x0B,
-       BD71837_REG_BUCK8_CTRL         = 0x0C,
-       BD71837_REG_BUCK1_VOLT_RUN     = 0x0D,
-       BD71837_REG_BUCK1_VOLT_IDLE    = 0x0E,
-       BD71837_REG_BUCK1_VOLT_SUSP    = 0x0F,
-       BD71837_REG_BUCK2_VOLT_RUN     = 0x10,
-       BD71837_REG_BUCK2_VOLT_IDLE    = 0x11,
-       BD71837_REG_BUCK3_VOLT_RUN     = 0x12,
-       BD71837_REG_BUCK4_VOLT_RUN     = 0x13,
-       BD71837_REG_BUCK5_VOLT         = 0x14,
-       BD71837_REG_BUCK6_VOLT         = 0x15,
-       BD71837_REG_BUCK7_VOLT         = 0x16,
-       BD71837_REG_BUCK8_VOLT         = 0x17,
-       BD71837_REG_LDO1_VOLT          = 0x18,
-       BD71837_REG_LDO2_VOLT          = 0x19,
-       BD71837_REG_LDO3_VOLT          = 0x1A,
-       BD71837_REG_LDO4_VOLT          = 0x1B,
-       BD71837_REG_LDO5_VOLT          = 0x1C,
-       BD71837_REG_LDO6_VOLT          = 0x1D,
-       BD71837_REG_LDO7_VOLT          = 0x1E,
-       BD71837_REG_TRANS_COND0        = 0x1F,
-       BD71837_REG_TRANS_COND1        = 0x20,
-       BD71837_REG_VRFAULTEN          = 0x21,
-       BD718XX_REG_MVRFLTMASK0        = 0x22,
-       BD718XX_REG_MVRFLTMASK1        = 0x23,
-       BD718XX_REG_MVRFLTMASK2        = 0x24,
-       BD71837_REG_RCVCFG             = 0x25,
-       BD71837_REG_RCVNUM             = 0x26,
-       BD71837_REG_PWRONCONFIG0       = 0x27,
-       BD71837_REG_PWRONCONFIG1       = 0x28,
-       BD71837_REG_RESETSRC           = 0x29,
-       BD71837_REG_MIRQ               = 0x2A,
-       BD71837_REG_IRQ                = 0x2B,
-       BD71837_REG_IN_MON             = 0x2C,
-       BD71837_REG_POW_STATE          = 0x2D,
-       BD71837_REG_OUT32K             = 0x2E,
-       BD71837_REG_REGLOCK            = 0x2F,
-       BD71837_REG_OTPVER             = 0xFF,
-       BD71837_MAX_REGISTER           = 0x100,
+       BD71837_REG_BUCK3_CTRL =        0x07,
+       BD71837_REG_BUCK4_CTRL =        0x08,
+       BD71837_REG_BUCK3_VOLT_RUN =    0x12,
+       BD71837_REG_BUCK4_VOLT_RUN =    0x13,
+       BD71837_REG_LDO7_VOLT =         0x1E,
+};
+
+/* Registers common for BD71837 and BD71847 */
+enum {
+       BD718XX_REG_REV =                       0x00,
+       BD718XX_REG_SWRESET =                   0x01,
+       BD718XX_REG_I2C_DEV =                   0x02,
+       BD718XX_REG_PWRCTRL0 =                  0x03,
+       BD718XX_REG_PWRCTRL1 =                  0x04,
+       BD718XX_REG_BUCK1_CTRL =                0x05,
+       BD718XX_REG_BUCK2_CTRL =                0x06,
+       BD718XX_REG_1ST_NODVS_BUCK_CTRL =       0x09,
+       BD718XX_REG_2ND_NODVS_BUCK_CTRL =       0x0A,
+       BD718XX_REG_3RD_NODVS_BUCK_CTRL =       0x0B,
+       BD718XX_REG_4TH_NODVS_BUCK_CTRL =       0x0C,
+       BD718XX_REG_BUCK1_VOLT_RUN =            0x0D,
+       BD718XX_REG_BUCK1_VOLT_IDLE =           0x0E,
+       BD718XX_REG_BUCK1_VOLT_SUSP =           0x0F,
+       BD718XX_REG_BUCK2_VOLT_RUN =            0x10,
+       BD718XX_REG_BUCK2_VOLT_IDLE =           0x11,
+       BD718XX_REG_1ST_NODVS_BUCK_VOLT =       0x14,
+       BD718XX_REG_2ND_NODVS_BUCK_VOLT =       0x15,
+       BD718XX_REG_3RD_NODVS_BUCK_VOLT =       0x16,
+       BD718XX_REG_4TH_NODVS_BUCK_VOLT =       0x17,
+       BD718XX_REG_LDO1_VOLT =                 0x18,
+       BD718XX_REG_LDO2_VOLT =                 0x19,
+       BD718XX_REG_LDO3_VOLT =                 0x1A,
+       BD718XX_REG_LDO4_VOLT =                 0x1B,
+       BD718XX_REG_LDO5_VOLT =                 0x1C,
+       BD718XX_REG_LDO6_VOLT =                 0x1D,
+       BD718XX_REG_TRANS_COND0 =               0x1F,
+       BD718XX_REG_TRANS_COND1 =               0x20,
+       BD718XX_REG_VRFAULTEN =                 0x21,
+       BD718XX_REG_MVRFLTMASK0 =               0x22,
+       BD718XX_REG_MVRFLTMASK1 =               0x23,
+       BD718XX_REG_MVRFLTMASK2 =               0x24,
+       BD718XX_REG_RCVCFG =                    0x25,
+       BD718XX_REG_RCVNUM =                    0x26,
+       BD718XX_REG_PWRONCONFIG0 =              0x27,
+       BD718XX_REG_PWRONCONFIG1 =              0x28,
+       BD718XX_REG_RESETSRC =                  0x29,
+       BD718XX_REG_MIRQ =                      0x2A,
+       BD718XX_REG_IRQ =                       0x2B,
+       BD718XX_REG_IN_MON =                    0x2C,
+       BD718XX_REG_POW_STATE =                 0x2D,
+       BD718XX_REG_OUT32K =                    0x2E,
+       BD718XX_REG_REGLOCK =                   0x2F,
+       BD718XX_REG_OTPVER =                    0xFF,
+       BD718XX_MAX_REGISTER =                  0x100,
 };
 
 #define REGLOCK_PWRSEQ 0x1
 #define REGLOCK_VREG   0x10
 
 /* Generic BUCK control masks */
-#define BD71837_BUCK_SEL       0x02
-#define BD71837_BUCK_EN                0x01
-#define BD71837_BUCK_RUN_ON    0x04
+#define BD718XX_BUCK_SEL       0x02
+#define BD718XX_BUCK_EN                0x01
+#define BD718XX_BUCK_RUN_ON    0x04
 
 /* Generic LDO masks */
-#define BD71837_LDO_SEL                0x80
-#define BD71837_LDO_EN         0x40
+#define BD718XX_LDO_SEL                0x80
+#define BD718XX_LDO_EN         0x40
 
 /* BD71837 BUCK ramp rate CTRL reg bits */
 #define BUCK_RAMPRATE_MASK     0xC0
@@ -115,49 +130,35 @@ enum {
 #define BUCK_RAMPRATE_2P50MV   0x2
 #define BUCK_RAMPRATE_1P25MV   0x3
 
-/* BD71837_REG_BUCK1_VOLT_RUN bits */
-#define BUCK1_RUN_MASK         0x3F
-#define BUCK1_RUN_DEFAULT      0x14
-
-/* BD71837_REG_BUCK1_VOLT_SUSP bits */
-#define BUCK1_SUSP_MASK                0x3F
-#define BUCK1_SUSP_DEFAULT     0x14
+#define DVS_BUCK_RUN_MASK      0x3F
+#define DVS_BUCK_SUSP_MASK     0x3F
+#define DVS_BUCK_IDLE_MASK     0x3F
 
-/* BD71837_REG_BUCK1_VOLT_IDLE bits */
-#define BUCK1_IDLE_MASK                0x3F
-#define BUCK1_IDLE_DEFAULT     0x14
+#define BD718XX_1ST_NODVS_BUCK_MASK    0x07
+#define BD718XX_3RD_NODVS_BUCK_MASK    0x07
+#define BD718XX_4TH_NODVS_BUCK_MASK    0x3F
 
-/* BD71837_REG_BUCK2_VOLT_RUN bits */
-#define BUCK2_RUN_MASK         0x3F
-#define BUCK2_RUN_DEFAULT      0x1E
+#define BD71847_BUCK3_MASK             0x07
+#define BD71847_BUCK3_RANGE_MASK       0xC0
+#define BD71847_BUCK4_MASK             0x03
+#define BD71847_BUCK4_RANGE_MASK       0x40
 
-/* BD71837_REG_BUCK2_VOLT_IDLE bits */
-#define BUCK2_IDLE_MASK                0x3F
-#define BUCK2_IDLE_DEFAULT     0x14
+#define BD71837_BUCK5_MASK             0x07
+#define BD71837_BUCK5_RANGE_MASK       0x80
+#define BD71837_BUCK6_MASK             0x03
 
-/* BD71837_REG_BUCK3_VOLT_RUN bits */
-#define BUCK3_RUN_MASK         0x3F
-#define BUCK3_RUN_DEFAULT      0x1E
+#define BD718XX_LDO1_MASK              0x03
+#define BD718XX_LDO1_RANGE_MASK                0x20
+#define BD718XX_LDO2_MASK              0x20
+#define BD718XX_LDO3_MASK              0x0F
+#define BD718XX_LDO4_MASK              0x0F
+#define BD718XX_LDO6_MASK              0x0F
 
-/* BD71837_REG_BUCK4_VOLT_RUN bits */
-#define BUCK4_RUN_MASK         0x3F
-#define BUCK4_RUN_DEFAULT      0x1E
+#define BD71837_LDO5_MASK              0x0F
+#define BD71847_LDO5_MASK              0x0F
+#define BD71847_LDO5_RANGE_MASK                0x20
 
-/* BD71837_REG_BUCK5_VOLT bits */
-#define BUCK5_MASK             0x07
-#define BUCK5_DEFAULT          0x02
-
-/* BD71837_REG_BUCK6_VOLT bits */
-#define BUCK6_MASK             0x03
-#define BUCK6_DEFAULT          0x03
-
-/* BD71837_REG_BUCK7_VOLT bits */
-#define BUCK7_MASK             0x07
-#define BUCK7_DEFAULT          0x03
-
-/* BD71837_REG_BUCK8_VOLT bits */
-#define BUCK8_MASK             0x3F
-#define BUCK8_DEFAULT          0x1E
+#define BD71837_LDO7_MASK              0x0F
 
 /* BD718XX Voltage monitoring masks */
 #define BD718XX_BUCK1_VRMON80           0x1
@@ -186,7 +187,7 @@ enum {
 #define BD71837_BUCK4_VRMON130          0x80
 #define BD71837_LDO7_VRMON80            0x40
 
-/* BD71837_REG_IRQ bits */
+/* BD718XX_REG_IRQ bits */
 #define IRQ_SWRST              0x40
 #define IRQ_PWRON_S            0x20
 #define IRQ_PWRON_L            0x10
@@ -195,52 +196,31 @@ enum {
 #define IRQ_ON_REQ             0x02
 #define IRQ_STBY_REQ           0x01
 
-/* BD71837_REG_OUT32K bits */
-#define BD71837_OUT32K_EN      0x01
+/* BD718XX_REG_OUT32K bits */
+#define BD718XX_OUT32K_EN      0x01
 
-/* BD71837 gated clock rate */
-#define BD71837_CLK_RATE 32768
+/* BD7183XX gated clock rate */
+#define BD718XX_CLK_RATE 32768
 
-/* ROHM BD71837 irqs */
+/* ROHM BD718XX irqs */
 enum {
-       BD71837_INT_STBY_REQ,
-       BD71837_INT_ON_REQ,
-       BD71837_INT_WDOG,
-       BD71837_INT_PWRBTN,
-       BD71837_INT_PWRBTN_L,
-       BD71837_INT_PWRBTN_S,
-       BD71837_INT_SWRST
+       BD718XX_INT_STBY_REQ,
+       BD718XX_INT_ON_REQ,
+       BD718XX_INT_WDOG,
+       BD718XX_INT_PWRBTN,
+       BD718XX_INT_PWRBTN_L,
+       BD718XX_INT_PWRBTN_S,
+       BD718XX_INT_SWRST
 };
 
-/* ROHM BD71837 interrupt masks */
-#define BD71837_INT_SWRST_MASK         0x40
-#define BD71837_INT_PWRBTN_S_MASK      0x20
-#define BD71837_INT_PWRBTN_L_MASK      0x10
-#define BD71837_INT_PWRBTN_MASK                0x8
-#define BD71837_INT_WDOG_MASK          0x4
-#define BD71837_INT_ON_REQ_MASK                0x2
-#define BD71837_INT_STBY_REQ_MASK      0x1
-
-/* BD71837_REG_LDO1_VOLT bits */
-#define LDO1_MASK              0x03
-
-/* BD71837_REG_LDO1_VOLT bits */
-#define LDO2_MASK              0x20
-
-/* BD71837_REG_LDO3_VOLT bits */
-#define LDO3_MASK              0x0F
-
-/* BD71837_REG_LDO4_VOLT bits */
-#define LDO4_MASK              0x0F
-
-/* BD71837_REG_LDO5_VOLT bits */
-#define LDO5_MASK              0x0F
-
-/* BD71837_REG_LDO6_VOLT bits */
-#define LDO6_MASK              0x0F
-
-/* BD71837_REG_LDO7_VOLT bits */
-#define LDO7_MASK              0x0F
+/* ROHM BD718XX interrupt masks */
+#define BD718XX_INT_SWRST_MASK         0x40
+#define BD718XX_INT_PWRBTN_S_MASK      0x20
+#define BD718XX_INT_PWRBTN_L_MASK      0x10
+#define BD718XX_INT_PWRBTN_MASK                0x8
+#define BD718XX_INT_WDOG_MASK          0x4
+#define BD718XX_INT_ON_REQ_MASK                0x2
+#define BD718XX_INT_STBY_REQ_MASK      0x1
 
 /* Register write induced reset settings */
 
@@ -250,13 +230,13 @@ enum {
  * write 1 to it we will trigger the action. So always write 0 to it when
  * changning SWRESET action - no matter what we read from it.
  */
-#define BD71837_SWRESET_TYPE_MASK      7
-#define BD71837_SWRESET_TYPE_DISABLED  0
-#define BD71837_SWRESET_TYPE_COLD      4
-#define BD71837_SWRESET_TYPE_WARM      6
+#define BD718XX_SWRESET_TYPE_MASK      7
+#define BD718XX_SWRESET_TYPE_DISABLED  0
+#define BD718XX_SWRESET_TYPE_COLD      4
+#define BD718XX_SWRESET_TYPE_WARM      6
 
-#define BD71837_SWRESET_RESET_MASK     1
-#define BD71837_SWRESET_RESET          1
+#define BD718XX_SWRESET_RESET_MASK     1
+#define BD718XX_SWRESET_RESET          1
 
 /* Poweroff state transition conditions */
 
@@ -341,10 +321,10 @@ enum {
        BD718XX_PWRBTN_LONG_PRESS_15S
 };
 
-struct bd71837_pmic;
-struct bd71837_clk;
+struct bd718xx_clk;
 
-struct bd71837 {
+struct bd718xx {
+       unsigned int chip_type;
        struct device *dev;
        struct regmap *regmap;
        unsigned long int id;
@@ -352,8 +332,7 @@ struct bd71837 {
        int chip_irq;
        struct regmap_irq_chip_data *irq_data;
 
-       struct bd71837_pmic *pmic;
-       struct bd71837_clk *clk;
+       struct bd718xx_clk *clk;
 };
 
-#endif /* __LINUX_MFD_BD71837_H__ */
+#endif /* __LINUX_MFD_BD718XX_H__ */
index 0fd8fbb74763e4be6cb80e9137921f9bb5339f37..a9c030192147dffd23610082ae8a22426dc000c7 100644 (file)
@@ -271,9 +271,16 @@ enum regulator_type {
  * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
  * @min_dropout_uV: The minimum dropout voltage this regulator can handle
  * @linear_ranges: A constant table of possible voltage ranges.
- * @n_linear_ranges: Number of entries in the @linear_ranges table.
+ * @linear_range_selectors: A constant table of voltage range selectors.
+ *                         If pickable ranges are used each range must
+ *                         have corresponding selector here.
+ * @n_linear_ranges: Number of entries in the @linear_ranges (and in
+ *                  linear_range_selectors if used) table(s).
  * @volt_table: Voltage mapping table (if table based mapping)
  *
+ * @vsel_range_reg: Register for range selector when using pickable ranges
+ *                 and regulator_regmap_X_voltage_X_pickable functions.
+ * @vsel_range_mask: Mask for register bitfield used for range selector
  * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
  * @vsel_mask: Mask for register bitfield used for selector
  * @csel_reg: Register for TPS65218 LS3 current regulator
@@ -338,10 +345,14 @@ struct regulator_desc {
        int min_dropout_uV;
 
        const struct regulator_linear_range *linear_ranges;
+       const unsigned int *linear_range_selectors;
+
        int n_linear_ranges;
 
        const unsigned int *volt_table;
 
+       unsigned int vsel_range_reg;
+       unsigned int vsel_range_mask;
        unsigned int vsel_reg;
        unsigned int vsel_mask;
        unsigned int csel_reg;
@@ -498,18 +509,25 @@ int regulator_mode_to_status(unsigned int);
 
 int regulator_list_voltage_linear(struct regulator_dev *rdev,
                                  unsigned int selector);
+int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev,
+                                                  unsigned int selector);
 int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
                                        unsigned int selector);
 int regulator_list_voltage_table(struct regulator_dev *rdev,
                                  unsigned int selector);
 int regulator_map_voltage_linear(struct regulator_dev *rdev,
                                  int min_uV, int max_uV);
+int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
+                                                 int min_uV, int max_uV);
 int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
                                       int min_uV, int max_uV);
 int regulator_map_voltage_iterate(struct regulator_dev *rdev,
                                  int min_uV, int max_uV);
 int regulator_map_voltage_ascend(struct regulator_dev *rdev,
                                  int min_uV, int max_uV);
+int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev);
+int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
+                                               unsigned int sel);
 int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev);
 int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel);
 int regulator_is_enabled_regmap(struct regulator_dev *rdev);
index 48918be649d499b55bfaf762b23d9d7ae0df201e..1a4340ed8e2bb51d82cd3ab9a98b7589d89d6108 100644 (file)
@@ -24,8 +24,6 @@ struct regulator_init_data;
  * @supply_name:       Name of the regulator supply
  * @input_supply:      Name of the input regulator supply
  * @microvolts:                Output voltage of regulator
- * @gpio:              GPIO to use for enable control
- *                     set to -EINVAL if not used
  * @startup_delay:     Start-up time in microseconds
  * @gpio_is_open_drain: Gpio pin is open drain or normal type.
  *                     If it is open drain type then HIGH will be set
@@ -49,7 +47,6 @@ struct fixed_voltage_config {
        const char *supply_name;
        const char *input_supply;
        int microvolts;
-       int gpio;
        unsigned startup_delay;
        unsigned gpio_is_open_drain:1;
        unsigned enable_high:1;
index 8fb44dec9ad75799e9269504ddea7083db654f9b..e1b79b6a273550516a57d3f7db10c236fcdf0305 100644 (file)
@@ -49,6 +49,7 @@ int reboot_force;
  */
 
 void (*pm_power_off_prepare)(void);
+EXPORT_SYMBOL_GPL(pm_power_off_prepare);
 
 /**
  *     emergency_restart - reboot the system