diff --git a/Documentation/devicetree/bindings/regulator/mp8859.txt b/Documentation/devicetree/bindings/regulator/mp8859.txt new file mode 100644 index 000000000000..74ad69730989 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mp8859.txt @@ -0,0 +1,22 @@ +Monolithic Power Systems MP8859 voltage regulator + +Required properties: +- compatible: "mps,mp8859"; +- reg: I2C slave address. + +Optional subnode for regulator: "mp8859_dcdc", using common regulator +bindings given in . + +Example: + + mp8859: regulator@66 { + compatible = "mps,mp8859"; + reg = <0x66>; + dc_12v: mp8859_dcdc { + regulator-name = "dc_12v"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-boot-on; + regulator-always-on; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml new file mode 100644 index 000000000000..a682af0dc67e --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/mps,mpq7920.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Monolithic Power System MPQ7920 PMIC + +maintainers: + - Saravanan Sekar + +properties: + $nodename: + pattern: "pmic@[0-9a-f]{1,2}" + compatible: + enum: + - mps,mpq7920 + + reg: + maxItems: 1 + + regulators: + type: object + allOf: + - $ref: regulator.yaml# + description: | + list of regulators provided by this controller, must be named + after their hardware counterparts BUCK[1-4], one LDORTC, and LDO[2-5] + + properties: + mps,switch-freq: + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint8" + enum: [ 0, 1, 2, 3 ] + default: 2 + description: | + switching frequency must be one of following corresponding value + 1.1MHz, 1.65MHz, 2.2MHz, 2.75MHz + + patternProperties: + "^ldo[1-4]$": + type: object + allOf: + - $ref: regulator.yaml# + + "^ldortc$": + type: object + allOf: + - $ref: regulator.yaml# + + "^buck[1-4]$": + type: object + allOf: + - $ref: regulator.yaml# + + properties: + mps,buck-softstart: + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint8" + enum: [ 0, 1, 2, 3 ] + description: | + defines the soft start time of this buck, must be one of the following + corresponding values 150us, 300us, 610us, 920us + + mps,buck-phase-delay: + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint8" + enum: [ 0, 1, 2, 3 ] + description: | + defines the phase delay of this buck, must be one of the following + corresponding values 0deg, 90deg, 180deg, 270deg + + mps,buck-ovp-disable: + type: boolean + description: | + disables over voltage protection of this buck + + additionalProperties: false + additionalProperties: false + +required: + - compatible + - reg + - regulators + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@69 { + compatible = "mps,mpq7920"; + reg = <0x69>; + + regulators { + mps,switch-freq = /bits/ 8 <1>; + + buck1 { + regulator-name = "buck1"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <3587500>; + regulator-min-microamp = <460000>; + regulator-max-microamp = <7600000>; + regulator-boot-on; + mps,buck-ovp-disable; + mps,buck-phase-delay = /bits/ 8 <2>; + mps,buck-softstart = /bits/ 8 <1>; + }; + + ldo2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <3587500>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71828-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd71828-regulator.yaml new file mode 100644 index 000000000000..71ce032b8cf8 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/rohm,bd71828-regulator.yaml @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/rohm,bd71828-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD71828 Power Management Integrated Circuit regulators + +maintainers: + - Matti Vaittinen + +description: | + This module is part of the ROHM BD71828 MFD device. For more details + see Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml. + + The regulator controller is represented as a sub-node of the PMIC node + on the device tree. + + Regulator nodes should be named to BUCK_ and LDO_. + The valid names for BD71828 regulator nodes are + BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7 + LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7 + +patternProperties: + "^LDO[1-7]$": + type: object + allOf: + - $ref: regulator.yaml# + description: + Properties for single LDO regulator. + + properties: + regulator-name: + pattern: "^ldo[1-7]$" + description: + should be "ldo1", ..., "ldo7" + + "^BUCK[1-7]$": + type: object + allOf: + - $ref: regulator.yaml# + description: + Properties for single BUCK regulator. + + properties: + regulator-name: + pattern: "^buck[1-7]$" + description: + should be "buck1", ..., "buck7" + + rohm,dvs-run-voltage: + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint32" + - minimum: 0 + maximum: 3300000 + description: + PMIC default "RUN" state voltage in uV. See below table for + bucks which support this. 0 means disabled. + + rohm,dvs-idle-voltage: + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint32" + - minimum: 0 + maximum: 3300000 + description: + PMIC default "IDLE" state voltage in uV. See below table for + bucks which support this. 0 means disabled. + + rohm,dvs-suspend-voltage: + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint32" + - minimum: 0 + maximum: 3300000 + description: + PMIC default "SUSPEND" state voltage in uV. See below table for + bucks which support this. 0 means disabled. + + rohm,dvs-lpsr-voltage: + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint32" + - minimum: 0 + maximum: 3300000 + description: + PMIC default "LPSR" state voltage in uV. See below table for + bucks which support this. 0 means disabled. + + # Supported default DVS states: + # buck | run | idle | suspend | lpsr + #-------------------------------------------------------------- + # 1, 2, 6, and 7 | supported | supported | supported (*) + #-------------------------------------------------------------- + # 3, 4, and 5 | supported (**) + #-------------------------------------------------------------- + # + #(*) LPSR and SUSPEND states use same voltage but both states have own + # enable / + # disable settings. Voltage 0 can be specified for a state to make + # regulator disabled on that state. + # + #(**) All states use same voltage but have own enable / disable + # settings. Voltage 0 can be specified for a state to make + # regulator disabled on that state. + + required: + - regulator-name + additionalProperties: false +additionalProperties: false diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-booster.txt b/Documentation/devicetree/bindings/regulator/st,stm32-booster.txt deleted file mode 100644 index 479ad4c8758e..000000000000 --- a/Documentation/devicetree/bindings/regulator/st,stm32-booster.txt +++ /dev/null @@ -1,18 +0,0 @@ -STM32 BOOSTER - Booster for ADC analog input switches - -Some STM32 devices embed a 3.3V booster supplied by Vdda, that can be used -to supply ADC analog input switches. - -Required properties: -- compatible: Should be one of: - "st,stm32h7-booster" - "st,stm32mp1-booster" -- st,syscfg: Phandle to system configuration controller. -- vdda-supply: Phandle to the vdda input analog voltage. - -Example: - booster: regulator-booster { - compatible = "st,stm32mp1-booster"; - st,syscfg = <&syscfg>; - vdda-supply = <&vdda>; - }; diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-booster.yaml b/Documentation/devicetree/bindings/regulator/st,stm32-booster.yaml new file mode 100644 index 000000000000..64f1183ce841 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/st,stm32-booster.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/st,stm32-booster.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32 booster for ADC analog input switches bindings + +maintainers: + - Fabrice Gasnier + +description: | + Some STM32 devices embed a 3.3V booster supplied by Vdda, that can be used + to supply ADC analog input switches. + +allOf: + - $ref: "regulator.yaml#" + +properties: + compatible: + enum: + - st,stm32h7-booster + - st,stm32mp1-booster + + st,syscfg: + allOf: + - $ref: "/schemas/types.yaml#/definitions/phandle-array" + description: phandle to system configuration controller. + + vdda-supply: + description: phandle to the vdda input analog voltage. + +required: + - compatible + - st,syscfg + - vdda-supply + +examples: + - | + regulator-booster { + compatible = "st,stm32mp1-booster"; + st,syscfg = <&syscfg>; + vdda-supply = <&vdda>; + }; + +... diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt deleted file mode 100644 index 5ddb8500a929..000000000000 --- a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt +++ /dev/null @@ -1,20 +0,0 @@ -STM32 VREFBUF - Voltage reference buffer - -Some STM32 devices embed a voltage reference buffer which can be used as -voltage reference for ADCs, DACs and also as voltage reference for external -components through the dedicated VREF+ pin. - -Required properties: -- compatible: Must be "st,stm32-vrefbuf". -- reg: Offset and length of VREFBUF register set. -- clocks: Must contain an entry for peripheral clock. - -Example: - vrefbuf: regulator@58003c00 { - compatible = "st,stm32-vrefbuf"; - reg = <0x58003C00 0x8>; - clocks = <&rcc VREF_CK>; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <2500000>; - vdda-supply = <&vdda>; - }; diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.yaml b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.yaml new file mode 100644 index 000000000000..33cdaeb25aee --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/st,stm32-vrefbuf.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32 Voltage reference buffer bindings + +description: | + Some STM32 devices embed a voltage reference buffer which can be used as + voltage reference for ADCs, DACs and also as voltage reference for external + components through the dedicated VREF+ pin. + +maintainers: + - Fabrice Gasnier + +allOf: + - $ref: "regulator.yaml#" + +properties: + compatible: + const: st,stm32-vrefbuf + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + vdda-supply: + description: phandle to the vdda input analog voltage. + +required: + - compatible + - reg + - clocks + - vdda-supply + +examples: + - | + #include + vrefbuf@50025000 { + compatible = "st,stm32-vrefbuf"; + reg = <0x50025000 0x8>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2500000>; + clocks = <&rcc VREF>; + vdda-supply = <&vdda>; + }; + +... + diff --git a/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.txt b/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.txt deleted file mode 100644 index e372dd3f0c8a..000000000000 --- a/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.txt +++ /dev/null @@ -1,43 +0,0 @@ -STM32MP1 PWR Regulators ------------------------ - -Available Regulators in STM32MP1 PWR block are: - - reg11 for regulator 1V1 - - reg18 for regulator 1V8 - - usb33 for the swtich USB3V3 - -Required properties: -- compatible: Must be "st,stm32mp1,pwr-reg" -- list of child nodes that specify the regulator reg11, reg18 or usb33 - initialization data for defined regulators. The definition for each of - these nodes is defined using the standard binding for regulators found at - Documentation/devicetree/bindings/regulator/regulator.txt. -- vdd-supply: phandle to the parent supply/regulator node for vdd input -- vdd_3v3_usbfs-supply: phandle to the parent supply/regulator node for usb33 - -Example: - -pwr_regulators: pwr@50001000 { - compatible = "st,stm32mp1,pwr-reg"; - reg = <0x50001000 0x10>; - vdd-supply = <&vdd>; - vdd_3v3_usbfs-supply = <&vdd_usb>; - - reg11: reg11 { - regulator-name = "reg11"; - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <1100000>; - }; - - reg18: reg18 { - regulator-name = "reg18"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - - usb33: usb33 { - regulator-name = "usb33"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; -}; diff --git a/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.yaml b/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.yaml new file mode 100644 index 000000000000..8d8f38fe85dc --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/st,stm32mp1-pwr-reg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STM32MP1 PWR voltage regulators + +maintainers: + - Pascal Paillet + +properties: + compatible: + const: st,stm32mp1,pwr-reg + + reg: + maxItems: 1 + + vdd-supply: + description: Input supply phandle(s) for vdd input + + vdd_3v3_usbfs-supply: + description: Input supply phandle(s) for vdd_3v3_usbfs input + +patternProperties: + "^(reg11|reg18|usb33)$": + type: object + + allOf: + - $ref: "regulator.yaml#" + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + pwr@50001000 { + compatible = "st,stm32mp1,pwr-reg"; + reg = <0x50001000 0x10>; + vdd-supply = <&vdd>; + vdd_3v3_usbfs-supply = <&vdd_usb>; + + reg11 { + regulator-name = "reg11"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + }; + + reg18 { + regulator-name = "reg18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + usb33 { + regulator-name = "usb33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 1575d416f2db..5924365f36b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11174,6 +11174,13 @@ S: Maintained F: Documentation/driver-api/serial/moxa-smartio.rst F: drivers/tty/mxser.* +MONOLITHIC POWER SYSTEM PMIC DRIVER +M: Saravanan Sekar +S: Maintained +F: Documentation/devicetree/bindings/regulator/mpq7920.yaml +F: drivers/regulator/mpq7920.c +F: drivers/regulator/mpq7920.h + MR800 AVERMEDIA USB FM RADIO DRIVER M: Alexey Klimov L: linux-media@vger.kernel.org diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 74eb5af7295f..97bfdd47954f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -194,6 +194,18 @@ config REGULATOR_BD70528 This driver can also be built as a module. If so, the module will be called bd70528-regulator. +config REGULATOR_BD71828 + tristate "ROHM BD71828 Power Regulator" + depends on MFD_ROHM_BD71828 + select REGULATOR_ROHM + help + This driver supports voltage regulators on ROHM BD71828 PMIC. + This will enable support for the software controllable buck + and LDO regulators. + + This driver can also be built as a module. If so, the module + will be called bd71828-regulator. + config REGULATOR_BD718XX tristate "ROHM BD71837 Power Regulator" depends on MFD_ROHM_BD718XX @@ -600,6 +612,27 @@ config REGULATOR_MCP16502 through the regulator interface. In addition it enables suspend-to-ram/standby transition. +config REGULATOR_MP8859 + tristate "MPS MP8859 regulator driver" + depends on I2C + select REGMAP_I2C + help + Say y here to support the MP8859 voltage regulator. This driver + supports basic operations (get/set voltage) through the regulator + interface. + Say M here if you want to include support for the regulator as a + module. The module will be named "mp8859". + +config REGULATOR_MPQ7920 + tristate "Monolithic MPQ7920 PMIC" + depends on I2C && OF + select REGMAP_I2C + help + Say y here to support the MPQ7920 PMIC. This will enable supports + the software controllable 4 buck and 5 LDO regulators. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6311 tristate "MediaTek MT6311 PMIC" depends on I2C @@ -1077,6 +1110,13 @@ config REGULATOR_VEXPRESS This driver provides support for voltage regulators available on the ARM Ltd's Versatile Express platform. +config REGULATOR_VQMMC_IPQ4019 + tristate "IPQ4019 VQMMC SD LDO regulator support" + depends on ARCH_QCOM + help + This driver provides support for the VQMMC LDO I/0 + voltage regulator of the IPQ4019 SD/EMMC controller. + config REGULATOR_WM831X tristate "Wolfson Microelectronics WM831x PMIC regulators" depends on MFD_WM831X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 2210ba56f9bd..07bc977c52b0 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o +obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o @@ -77,6 +78,8 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o +obj-$(CONFIG_REGULATOR_MP8859) += mp8859.o +obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o @@ -132,6 +135,7 @@ obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o +obj-$(CONFIG_REGULATOR_VQMMC_IPQ4019) += vqmmc-ipq4019-regulator.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c new file mode 100644 index 000000000000..b2fa17be4988 --- /dev/null +++ b/drivers/regulator/bd71828-regulator.c @@ -0,0 +1,807 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2019 ROHM Semiconductors +// bd71828-regulator.c ROHM BD71828GW-DS1 regulator driver +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct reg_init { + unsigned int reg; + unsigned int mask; + unsigned int val; +}; +struct bd71828_regulator_data { + struct regulator_desc desc; + const struct rohm_dvs_config dvs; + const struct reg_init *reg_inits; + int reg_init_amnt; +}; + +static const struct reg_init buck1_inits[] = { + /* + * DVS Buck voltages can be changed by register values or via GPIO. + * Use register accesses by default. + */ + { + .reg = BD71828_REG_PS_CTRL_1, + .mask = BD71828_MASK_DVS_BUCK1_CTRL, + .val = BD71828_DVS_BUCK1_CTRL_I2C, + }, +}; + +static const struct reg_init buck2_inits[] = { + { + .reg = BD71828_REG_PS_CTRL_1, + .mask = BD71828_MASK_DVS_BUCK2_CTRL, + .val = BD71828_DVS_BUCK2_CTRL_I2C, + }, +}; + +static const struct reg_init buck6_inits[] = { + { + .reg = BD71828_REG_PS_CTRL_1, + .mask = BD71828_MASK_DVS_BUCK6_CTRL, + .val = BD71828_DVS_BUCK6_CTRL_I2C, + }, +}; + +static const struct reg_init buck7_inits[] = { + { + .reg = BD71828_REG_PS_CTRL_1, + .mask = BD71828_MASK_DVS_BUCK7_CTRL, + .val = BD71828_DVS_BUCK7_CTRL_I2C, + }, +}; + +static const struct regulator_linear_range bd71828_buck1267_volts[] = { + REGULATOR_LINEAR_RANGE(500000, 0x00, 0xef, 6250), + REGULATOR_LINEAR_RANGE(2000000, 0xf0, 0xff, 0), +}; + +static const struct regulator_linear_range bd71828_buck3_volts[] = { + REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x0f, 50000), + REGULATOR_LINEAR_RANGE(2000000, 0x10, 0x1f, 0), +}; + +static const struct regulator_linear_range bd71828_buck4_volts[] = { + REGULATOR_LINEAR_RANGE(1000000, 0x00, 0x1f, 25000), + REGULATOR_LINEAR_RANGE(1800000, 0x20, 0x3f, 0), +}; + +static const struct regulator_linear_range bd71828_buck5_volts[] = { + REGULATOR_LINEAR_RANGE(2500000, 0x00, 0x0f, 50000), + REGULATOR_LINEAR_RANGE(3300000, 0x10, 0x1f, 0), +}; + +static const struct regulator_linear_range bd71828_ldo_volts[] = { + REGULATOR_LINEAR_RANGE(800000, 0x00, 0x31, 50000), + REGULATOR_LINEAR_RANGE(3300000, 0x32, 0x3f, 0), +}; + +static int bd71828_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + unsigned int val; + + switch (ramp_delay) { + case 1 ... 2500: + val = 0; + break; + case 2501 ... 5000: + val = 1; + break; + case 5001 ... 10000: + val = 2; + break; + case 10001 ... 20000: + val = 3; + break; + default: + val = 3; + dev_err(&rdev->dev, + "ramp_delay: %d not supported, setting 20mV/uS", + ramp_delay); + } + + /* + * On BD71828 the ramp delay level control reg is at offset +2 to + * enable reg + */ + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg + 2, + BD71828_MASK_RAMP_DELAY, + val << (ffs(BD71828_MASK_RAMP_DELAY) - 1)); +} + +static int buck_set_hw_dvs_levels(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + struct bd71828_regulator_data *data; + + data = container_of(desc, struct bd71828_regulator_data, desc); + + return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap); +} + +static int ldo6_parse_dt(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + int ret, i; + uint32_t uv = 0; + unsigned int en; + struct regmap *regmap = cfg->regmap; + static const char * const props[] = { "rohm,dvs-run-voltage", + "rohm,dvs-idle-voltage", + "rohm,dvs-suspend-voltage", + "rohm,dvs-lpsr-voltage" }; + unsigned int mask[] = { BD71828_MASK_RUN_EN, BD71828_MASK_IDLE_EN, + BD71828_MASK_SUSP_EN, BD71828_MASK_LPSR_EN }; + + for (i = 0; i < ARRAY_SIZE(props); i++) { + ret = of_property_read_u32(np, props[i], &uv); + if (ret) { + if (ret != -EINVAL) + return ret; + continue; + } + if (uv) + en = 0xffffffff; + else + en = 0; + + ret = regmap_update_bits(regmap, desc->enable_reg, mask[i], en); + if (ret) + return ret; + } + return 0; +} + +static const struct regulator_ops bd71828_buck_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, +}; + +static const struct regulator_ops bd71828_dvs_buck_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 = bd71828_set_ramp_delay, +}; + +static const struct regulator_ops bd71828_ldo_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, +}; + +static const struct regulator_ops bd71828_ldo6_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct bd71828_regulator_data bd71828_rdata[] = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("BUCK1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_BUCK1, + .ops = &bd71828_dvs_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_buck1267_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_buck1267_volts), + .n_voltages = BD71828_BUCK1267_VOLTS, + .enable_reg = BD71828_REG_BUCK1_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_BUCK1_VOLT, + .vsel_mask = BD71828_MASK_BUCK1267_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK1_VOLT, + .run_mask = BD71828_MASK_BUCK1267_VOLT, + .idle_reg = BD71828_REG_BUCK1_IDLE_VOLT, + .idle_mask = BD71828_MASK_BUCK1267_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_reg = BD71828_REG_BUCK1_SUSP_VOLT, + .suspend_mask = BD71828_MASK_BUCK1267_VOLT, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + /* + * LPSR voltage is same as SUSPEND voltage. Allow + * setting it so that regulator can be set enabled at + * LPSR state + */ + .lpsr_reg = BD71828_REG_BUCK1_SUSP_VOLT, + .lpsr_mask = BD71828_MASK_BUCK1267_VOLT, + }, + .reg_inits = buck1_inits, + .reg_init_amnt = ARRAY_SIZE(buck1_inits), + }, + { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("BUCK2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_BUCK2, + .ops = &bd71828_dvs_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_buck1267_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_buck1267_volts), + .n_voltages = BD71828_BUCK1267_VOLTS, + .enable_reg = BD71828_REG_BUCK2_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_BUCK2_VOLT, + .vsel_mask = BD71828_MASK_BUCK1267_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK2_VOLT, + .run_mask = BD71828_MASK_BUCK1267_VOLT, + .idle_reg = BD71828_REG_BUCK2_IDLE_VOLT, + .idle_mask = BD71828_MASK_BUCK1267_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_reg = BD71828_REG_BUCK2_SUSP_VOLT, + .suspend_mask = BD71828_MASK_BUCK1267_VOLT, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + .lpsr_reg = BD71828_REG_BUCK2_SUSP_VOLT, + .lpsr_mask = BD71828_MASK_BUCK1267_VOLT, + }, + .reg_inits = buck2_inits, + .reg_init_amnt = ARRAY_SIZE(buck2_inits), + }, + { + .desc = { + .name = "buck3", + .of_match = of_match_ptr("BUCK3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_BUCK3, + .ops = &bd71828_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_buck3_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_buck3_volts), + .n_voltages = BD71828_BUCK3_VOLTS, + .enable_reg = BD71828_REG_BUCK3_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_BUCK3_VOLT, + .vsel_mask = BD71828_MASK_BUCK3_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * BUCK3 only supports single voltage for all states. + * voltage can be individually enabled for each state + * though => allow setting all states to support + * enabling power rail on different states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK3_VOLT, + .idle_reg = BD71828_REG_BUCK3_VOLT, + .suspend_reg = BD71828_REG_BUCK3_VOLT, + .lpsr_reg = BD71828_REG_BUCK3_VOLT, + .run_mask = BD71828_MASK_BUCK3_VOLT, + .idle_mask = BD71828_MASK_BUCK3_VOLT, + .suspend_mask = BD71828_MASK_BUCK3_VOLT, + .lpsr_mask = BD71828_MASK_BUCK3_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + }, + { + .desc = { + .name = "buck4", + .of_match = of_match_ptr("BUCK4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_BUCK4, + .ops = &bd71828_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_buck4_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_buck4_volts), + .n_voltages = BD71828_BUCK4_VOLTS, + .enable_reg = BD71828_REG_BUCK4_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_BUCK4_VOLT, + .vsel_mask = BD71828_MASK_BUCK4_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * BUCK4 only supports single voltage for all states. + * voltage can be individually enabled for each state + * though => allow setting all states to support + * enabling power rail on different states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK4_VOLT, + .idle_reg = BD71828_REG_BUCK4_VOLT, + .suspend_reg = BD71828_REG_BUCK4_VOLT, + .lpsr_reg = BD71828_REG_BUCK4_VOLT, + .run_mask = BD71828_MASK_BUCK4_VOLT, + .idle_mask = BD71828_MASK_BUCK4_VOLT, + .suspend_mask = BD71828_MASK_BUCK4_VOLT, + .lpsr_mask = BD71828_MASK_BUCK4_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + }, + { + .desc = { + .name = "buck5", + .of_match = of_match_ptr("BUCK5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_BUCK5, + .ops = &bd71828_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_buck5_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_buck5_volts), + .n_voltages = BD71828_BUCK5_VOLTS, + .enable_reg = BD71828_REG_BUCK5_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_BUCK5_VOLT, + .vsel_mask = BD71828_MASK_BUCK5_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * BUCK5 only supports single voltage for all states. + * voltage can be individually enabled for each state + * though => allow setting all states to support + * enabling power rail on different states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK5_VOLT, + .idle_reg = BD71828_REG_BUCK5_VOLT, + .suspend_reg = BD71828_REG_BUCK5_VOLT, + .lpsr_reg = BD71828_REG_BUCK5_VOLT, + .run_mask = BD71828_MASK_BUCK5_VOLT, + .idle_mask = BD71828_MASK_BUCK5_VOLT, + .suspend_mask = BD71828_MASK_BUCK5_VOLT, + .lpsr_mask = BD71828_MASK_BUCK5_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + }, + { + .desc = { + .name = "buck6", + .of_match = of_match_ptr("BUCK6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_BUCK6, + .ops = &bd71828_dvs_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_buck1267_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_buck1267_volts), + .n_voltages = BD71828_BUCK1267_VOLTS, + .enable_reg = BD71828_REG_BUCK6_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_BUCK6_VOLT, + .vsel_mask = BD71828_MASK_BUCK1267_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK6_VOLT, + .run_mask = BD71828_MASK_BUCK1267_VOLT, + .idle_reg = BD71828_REG_BUCK6_IDLE_VOLT, + .idle_mask = BD71828_MASK_BUCK1267_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_reg = BD71828_REG_BUCK6_SUSP_VOLT, + .suspend_mask = BD71828_MASK_BUCK1267_VOLT, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + .lpsr_reg = BD71828_REG_BUCK6_SUSP_VOLT, + .lpsr_mask = BD71828_MASK_BUCK1267_VOLT, + }, + .reg_inits = buck6_inits, + .reg_init_amnt = ARRAY_SIZE(buck6_inits), + }, + { + .desc = { + .name = "buck7", + .of_match = of_match_ptr("BUCK7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_BUCK7, + .ops = &bd71828_dvs_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_buck1267_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_buck1267_volts), + .n_voltages = BD71828_BUCK1267_VOLTS, + .enable_reg = BD71828_REG_BUCK7_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_BUCK7_VOLT, + .vsel_mask = BD71828_MASK_BUCK1267_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK7_VOLT, + .run_mask = BD71828_MASK_BUCK1267_VOLT, + .idle_reg = BD71828_REG_BUCK7_IDLE_VOLT, + .idle_mask = BD71828_MASK_BUCK1267_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_reg = BD71828_REG_BUCK7_SUSP_VOLT, + .suspend_mask = BD71828_MASK_BUCK1267_VOLT, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + .lpsr_reg = BD71828_REG_BUCK7_SUSP_VOLT, + .lpsr_mask = BD71828_MASK_BUCK1267_VOLT, + }, + .reg_inits = buck7_inits, + .reg_init_amnt = ARRAY_SIZE(buck7_inits), + }, + { + .desc = { + .name = "ldo1", + .of_match = of_match_ptr("LDO1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_LDO1, + .ops = &bd71828_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts), + .n_voltages = BD71828_LDO_VOLTS, + .enable_reg = BD71828_REG_LDO1_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_LDO1_VOLT, + .vsel_mask = BD71828_MASK_LDO_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * LDO1 only supports single voltage for all states. + * voltage can be individually enabled for each state + * though => allow setting all states to support + * enabling power rail on different states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO1_VOLT, + .idle_reg = BD71828_REG_LDO1_VOLT, + .suspend_reg = BD71828_REG_LDO1_VOLT, + .lpsr_reg = BD71828_REG_LDO1_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, + .idle_mask = BD71828_MASK_LDO_VOLT, + .suspend_mask = BD71828_MASK_LDO_VOLT, + .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + }, { + .desc = { + .name = "ldo2", + .of_match = of_match_ptr("LDO2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_LDO2, + .ops = &bd71828_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts), + .n_voltages = BD71828_LDO_VOLTS, + .enable_reg = BD71828_REG_LDO2_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_LDO2_VOLT, + .vsel_mask = BD71828_MASK_LDO_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * LDO2 only supports single voltage for all states. + * voltage can be individually enabled for each state + * though => allow setting all states to support + * enabling power rail on different states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO2_VOLT, + .idle_reg = BD71828_REG_LDO2_VOLT, + .suspend_reg = BD71828_REG_LDO2_VOLT, + .lpsr_reg = BD71828_REG_LDO2_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, + .idle_mask = BD71828_MASK_LDO_VOLT, + .suspend_mask = BD71828_MASK_LDO_VOLT, + .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + }, { + .desc = { + .name = "ldo3", + .of_match = of_match_ptr("LDO3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_LDO3, + .ops = &bd71828_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts), + .n_voltages = BD71828_LDO_VOLTS, + .enable_reg = BD71828_REG_LDO3_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_LDO3_VOLT, + .vsel_mask = BD71828_MASK_LDO_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * LDO3 only supports single voltage for all states. + * voltage can be individually enabled for each state + * though => allow setting all states to support + * enabling power rail on different states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO3_VOLT, + .idle_reg = BD71828_REG_LDO3_VOLT, + .suspend_reg = BD71828_REG_LDO3_VOLT, + .lpsr_reg = BD71828_REG_LDO3_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, + .idle_mask = BD71828_MASK_LDO_VOLT, + .suspend_mask = BD71828_MASK_LDO_VOLT, + .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + + }, { + .desc = { + .name = "ldo4", + .of_match = of_match_ptr("LDO4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_LDO4, + .ops = &bd71828_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts), + .n_voltages = BD71828_LDO_VOLTS, + .enable_reg = BD71828_REG_LDO4_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_LDO4_VOLT, + .vsel_mask = BD71828_MASK_LDO_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * LDO1 only supports single voltage for all states. + * voltage can be individually enabled for each state + * though => allow setting all states to support + * enabling power rail on different states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO4_VOLT, + .idle_reg = BD71828_REG_LDO4_VOLT, + .suspend_reg = BD71828_REG_LDO4_VOLT, + .lpsr_reg = BD71828_REG_LDO4_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, + .idle_mask = BD71828_MASK_LDO_VOLT, + .suspend_mask = BD71828_MASK_LDO_VOLT, + .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + }, { + .desc = { + .name = "ldo5", + .of_match = of_match_ptr("LDO5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_LDO5, + .ops = &bd71828_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts), + .n_voltages = BD71828_LDO_VOLTS, + .enable_reg = BD71828_REG_LDO5_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_LDO5_VOLT, + .vsel_mask = BD71828_MASK_LDO_VOLT, + .of_parse_cb = buck_set_hw_dvs_levels, + .owner = THIS_MODULE, + }, + /* + * LDO5 is special. It can choose vsel settings to be configured + * from 2 different registers (by GPIO). + * + * This driver supports only configuration where + * BD71828_REG_LDO5_VOLT_L is used. + */ + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO5_VOLT, + .idle_reg = BD71828_REG_LDO5_VOLT, + .suspend_reg = BD71828_REG_LDO5_VOLT, + .lpsr_reg = BD71828_REG_LDO5_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, + .idle_mask = BD71828_MASK_LDO_VOLT, + .suspend_mask = BD71828_MASK_LDO_VOLT, + .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + + }, { + .desc = { + .name = "ldo6", + .of_match = of_match_ptr("LDO6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_LDO6, + .ops = &bd71828_ldo6_ops, + .type = REGULATOR_VOLTAGE, + .fixed_uV = BD71828_LDO_6_VOLTAGE, + .n_voltages = 1, + .enable_reg = BD71828_REG_LDO6_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .owner = THIS_MODULE, + /* + * LDO6 only supports enable/disable for all states. + * Voltage for LDO6 is fixed. + */ + .of_parse_cb = ldo6_parse_dt, + }, + }, { + .desc = { + /* SNVS LDO in data-sheet */ + .name = "ldo7", + .of_match = of_match_ptr("LDO7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71828_LDO_SNVS, + .ops = &bd71828_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd71828_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts), + .n_voltages = BD71828_LDO_VOLTS, + .enable_reg = BD71828_REG_LDO7_EN, + .enable_mask = BD71828_MASK_RUN_EN, + .vsel_reg = BD71828_REG_LDO7_VOLT, + .vsel_mask = BD71828_MASK_LDO_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * LDO7 only supports single voltage for all states. + * voltage can be individually enabled for each state + * though => allow setting all states to support + * enabling power rail on different states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO7_VOLT, + .idle_reg = BD71828_REG_LDO7_VOLT, + .suspend_reg = BD71828_REG_LDO7_VOLT, + .lpsr_reg = BD71828_REG_LDO7_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, + .idle_mask = BD71828_MASK_LDO_VOLT, + .suspend_mask = BD71828_MASK_LDO_VOLT, + .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + + }, +}; + +static int bd71828_probe(struct platform_device *pdev) +{ + struct rohm_regmap_dev *bd71828; + int i, j, ret; + struct regulator_config config = { + .dev = pdev->dev.parent, + }; + + bd71828 = dev_get_drvdata(pdev->dev.parent); + if (!bd71828) { + dev_err(&pdev->dev, "No MFD driver data\n"); + return -EINVAL; + } + + config.regmap = bd71828->regmap; + + for (i = 0; i < ARRAY_SIZE(bd71828_rdata); i++) { + struct regulator_dev *rdev; + const struct bd71828_regulator_data *rd; + + rd = &bd71828_rdata[i]; + rdev = devm_regulator_register(&pdev->dev, + &rd->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "failed to register %s regulator\n", + rd->desc.name); + return PTR_ERR(rdev); + } + for (j = 0; j < rd->reg_init_amnt; j++) { + ret = regmap_update_bits(bd71828->regmap, + rd->reg_inits[j].reg, + rd->reg_inits[j].mask, + rd->reg_inits[j].val); + if (ret) { + dev_err(&pdev->dev, + "regulator %s init failed\n", + rd->desc.name); + return ret; + } + } + } + return 0; +} + +static struct platform_driver bd71828_regulator = { + .driver = { + .name = "bd71828-pmic" + }, + .probe = bd71828_probe, +}; + +module_platform_driver(bd71828_regulator); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("BD71828 voltage regulator driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bd71828-pmic"); diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index 13a43eee2e46..8f9b2d8eaf10 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -1142,28 +1142,14 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { }, }; -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[ROHM_CHIP_TYPE_AMOUNT] = { - [ROHM_CHIP_TYPE_BD71837] = { - .r_datas = bd71837_regulators, - .r_amount = ARRAY_SIZE(bd71837_regulators), - }, - [ROHM_CHIP_TYPE_BD71847] = { - .r_datas = bd71847_regulators, - .r_amount = ARRAY_SIZE(bd71847_regulators), - }, - }; - int i, j, err; bool use_snvs; + const struct bd718xx_regulator_data *reg_data; + unsigned int num_reg_data; mfd = dev_get_drvdata(pdev->dev.parent); if (!mfd) { @@ -1172,8 +1158,16 @@ static int bd718xx_probe(struct platform_device *pdev) goto err; } - if (mfd->chip.chip_type >= ROHM_CHIP_TYPE_AMOUNT || - !pmic_regulators[mfd->chip.chip_type].r_datas) { + switch (mfd->chip.chip_type) { + case ROHM_CHIP_TYPE_BD71837: + reg_data = bd71837_regulators; + num_reg_data = ARRAY_SIZE(bd71837_regulators); + break; + case ROHM_CHIP_TYPE_BD71847: + reg_data = bd71847_regulators; + num_reg_data = ARRAY_SIZE(bd71847_regulators); + break; + default: dev_err(&pdev->dev, "Unsupported chip type\n"); err = -EINVAL; goto err; @@ -1215,13 +1209,13 @@ static int bd718xx_probe(struct platform_device *pdev) } } - for (i = 0; i < pmic_regulators[mfd->chip.chip_type].r_amount; i++) { + for (i = 0; i < num_reg_data; i++) { const struct regulator_desc *desc; struct regulator_dev *rdev; const struct bd718xx_regulator_data *r; - r = &pmic_regulators[mfd->chip.chip_type].r_datas[i]; + r = ®_data[i]; desc = &r->desc; config.dev = pdev->dev.parent; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 03d79fee2987..d015d99cb59d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3470,6 +3470,7 @@ int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, out: return ret; } +EXPORT_SYMBOL_GPL(regulator_set_voltage_rdev); static int regulator_limit_voltage_step(struct regulator_dev *rdev, int *current_uV, int *min_uV) @@ -4034,6 +4035,7 @@ int regulator_get_voltage_rdev(struct regulator_dev *rdev) return ret; return ret - rdev->constraints->uV_offset; } +EXPORT_SYMBOL_GPL(regulator_get_voltage_rdev); /** * regulator_get_voltage - get regulator output voltage diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f9448ed50e05..0cdeb6186529 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -131,8 +131,7 @@ static const struct of_device_id da9210_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, da9210_dt_ids); -static int da9210_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da9210_i2c_probe(struct i2c_client *i2c) { struct da9210 *chip; struct device *dev = &i2c->dev; @@ -228,7 +227,7 @@ static struct i2c_driver da9210_regulator_driver = { .name = "da9210", .of_match_table = of_match_ptr(da9210_dt_ids), }, - .probe = da9210_i2c_probe, + .probe_new = da9210_i2c_probe, .id_table = da9210_i2c_id, }; diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 523dc1b95826..2ea4362ffa5c 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -416,8 +416,7 @@ static int da9211_regulator_init(struct da9211 *chip) /* * I2C driver interface functions */ -static int da9211_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da9211_i2c_probe(struct i2c_client *i2c) { struct da9211 *chip; int error, ret; @@ -526,7 +525,7 @@ static struct i2c_driver da9211_regulator_driver = { .name = "da9211", .of_match_table = of_match_ptr(da9211_dt_ids), }, - .probe = da9211_i2c_probe, + .probe_new = da9211_i2c_probe, .id_table = da9211_i2c_id, }; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index ca3dc3f3bb29..bb16c465426e 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -13,6 +13,8 @@ #include #include +#include "internal.h" + /** * regulator_is_enabled_regmap - standard is_enabled() for regmap users * @@ -881,3 +883,15 @@ void regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers, consumers[i].supply = supply_names[i]; } EXPORT_SYMBOL_GPL(regulator_bulk_set_supply_names); + +/** + * regulator_is_equal - test whether two regulators are the same + * + * @reg1: first regulator to operate on + * @reg2: second regulator to operate on + */ +bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2) +{ + return reg1->rdev == reg2->rdev; +} +EXPORT_SYMBOL_GPL(regulator_is_equal); diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c index 978f5e903cae..cfb765986d0d 100644 --- a/drivers/regulator/isl9305.c +++ b/drivers/regulator/isl9305.c @@ -137,8 +137,7 @@ static const struct regmap_config isl9305_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int isl9305_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int isl9305_i2c_probe(struct i2c_client *i2c) { struct regulator_config config = { }; struct isl9305_pdata *pdata = i2c->dev.platform_data; @@ -198,7 +197,7 @@ static struct i2c_driver isl9305_regulator_driver = { .name = "isl9305", .of_match_table = of_match_ptr(isl9305_dt_ids), }, - .probe = isl9305_i2c_probe, + .probe_new = isl9305_i2c_probe, .id_table = isl9305_i2c_id, }; diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index bc96e65ef7c0..8be252f81b09 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -400,8 +400,7 @@ static int setup_regulators(struct lp3971 *lp3971, return 0; } -static int lp3971_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int lp3971_i2c_probe(struct i2c_client *i2c) { struct lp3971 *lp3971; struct lp3971_platform_data *pdata = dev_get_platdata(&i2c->dev); @@ -449,7 +448,7 @@ static struct i2c_driver lp3971_i2c_driver = { .driver = { .name = "LP3971", }, - .probe = lp3971_i2c_probe, + .probe_new = lp3971_i2c_probe, .id_table = lp3971_i2c_id, }; diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c index d934540eb8c4..e12e52c69e52 100644 --- a/drivers/regulator/ltc3676.c +++ b/drivers/regulator/ltc3676.c @@ -301,8 +301,7 @@ static irqreturn_t ltc3676_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int ltc3676_regulator_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc3676_regulator_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct regulator_init_data *init_data = dev_get_platdata(dev); @@ -380,7 +379,7 @@ static struct i2c_driver ltc3676_driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ltc3676_of_match), }, - .probe = ltc3676_regulator_probe, + .probe_new = ltc3676_regulator_probe, .id_table = ltc3676_i2c_id, }; module_i2c_driver(ltc3676_driver); diff --git a/drivers/regulator/mp8859.c b/drivers/regulator/mp8859.c new file mode 100644 index 000000000000..1d26b506ee5b --- /dev/null +++ b/drivers/regulator/mp8859.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2019 five technologies GmbH +// Author: Markus Reichl + +#include +#include +#include +#include +#include + + +#define VOL_MIN_IDX 0x00 +#define VOL_MAX_IDX 0x7ff + +/* Register definitions */ +#define MP8859_VOUT_L_REG 0 //3 lo Bits +#define MP8859_VOUT_H_REG 1 //8 hi Bits +#define MP8859_VOUT_GO_REG 2 +#define MP8859_IOUT_LIM_REG 3 +#define MP8859_CTL1_REG 4 +#define MP8859_CTL2_REG 5 +#define MP8859_RESERVED1_REG 6 +#define MP8859_RESERVED2_REG 7 +#define MP8859_RESERVED3_REG 8 +#define MP8859_STATUS_REG 9 +#define MP8859_INTERRUPT_REG 0x0A +#define MP8859_MASK_REG 0x0B +#define MP8859_ID1_REG 0x0C +#define MP8859_MFR_ID_REG 0x27 +#define MP8859_DEV_ID_REG 0x28 +#define MP8859_IC_REV_REG 0x29 + +#define MP8859_MAX_REG 0x29 + +#define MP8859_GO_BIT 0x01 + + +static int mp8859_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) +{ + int ret; + + ret = regmap_write(rdev->regmap, MP8859_VOUT_L_REG, sel & 0x7); + + if (ret) + return ret; + ret = regmap_write(rdev->regmap, MP8859_VOUT_H_REG, sel >> 3); + + if (ret) + return ret; + ret = regmap_update_bits(rdev->regmap, MP8859_VOUT_GO_REG, + MP8859_GO_BIT, 1); + return ret; +} + +static int mp8859_get_voltage_sel(struct regulator_dev *rdev) +{ + unsigned int val_tmp; + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, MP8859_VOUT_H_REG, &val_tmp); + + if (ret) + return ret; + val = val_tmp << 3; + + ret = regmap_read(rdev->regmap, MP8859_VOUT_L_REG, &val_tmp); + + if (ret) + return ret; + val |= val_tmp & 0x07; + return val; +} + +static const struct regulator_linear_range mp8859_dcdc_ranges[] = { + REGULATOR_LINEAR_RANGE(0, VOL_MIN_IDX, VOL_MAX_IDX, 10000), +}; + +static const struct regmap_config mp8859_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MP8859_MAX_REG, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct regulator_ops mp8859_ops = { + .set_voltage_sel = mp8859_set_voltage_sel, + .get_voltage_sel = mp8859_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, +}; + +static const struct regulator_desc mp8859_regulators[] = { + { + .id = 0, + .type = REGULATOR_VOLTAGE, + .name = "mp8859_dcdc", + .of_match = of_match_ptr("mp8859_dcdc"), + .n_voltages = VOL_MAX_IDX + 1, + .linear_ranges = mp8859_dcdc_ranges, + .n_linear_ranges = 1, + .ops = &mp8859_ops, + .owner = THIS_MODULE, + }, +}; + +static int mp8859_i2c_probe(struct i2c_client *i2c) +{ + int ret; + struct regulator_config config = {.dev = &i2c->dev}; + struct regmap *regmap = devm_regmap_init_i2c(i2c, &mp8859_regmap); + struct regulator_dev *rdev; + + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "regmap init failed: %d\n", ret); + return ret; + } + rdev = devm_regulator_register(&i2c->dev, &mp8859_regulators[0], + &config); + + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&i2c->dev, "failed to register %s: %d\n", + mp8859_regulators[0].name, ret); + return ret; + } + return 0; +} + +static const struct of_device_id mp8859_dt_id[] = { + {.compatible = "mps,mp8859"}, + {}, +}; +MODULE_DEVICE_TABLE(of, mp8859_dt_id); + +static const struct i2c_device_id mp8859_i2c_id[] = { + { "mp8859", }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, mp8859_i2c_id); + +static struct i2c_driver mp8859_regulator_driver = { + .driver = { + .name = "mp8859", + .of_match_table = of_match_ptr(mp8859_dt_id), + }, + .probe_new = mp8859_i2c_probe, + .id_table = mp8859_i2c_id, +}; + +module_i2c_driver(mp8859_regulator_driver); + +MODULE_DESCRIPTION("Monolithic Power Systems MP8859 voltage regulator driver"); +MODULE_AUTHOR("Markus Reichl "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/mpq7920.c b/drivers/regulator/mpq7920.c new file mode 100644 index 000000000000..54c862edf571 --- /dev/null +++ b/drivers/regulator/mpq7920.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// mpq7920.c - regulator driver for mps mpq7920 +// +// Copyright 2019 Monolithic Power Systems, Inc +// +// Author: Saravanan Sekar + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpq7920.h" + +#define MPQ7920_BUCK_VOLT_RANGE \ + ((MPQ7920_VOLT_MAX - MPQ7920_BUCK_VOLT_MIN)/MPQ7920_VOLT_STEP + 1) +#define MPQ7920_LDO_VOLT_RANGE \ + ((MPQ7920_VOLT_MAX - MPQ7920_LDO_VOLT_MIN)/MPQ7920_VOLT_STEP + 1) + +#define MPQ7920BUCK(_name, _id, _ilim) \ + [MPQ7920_BUCK ## _id] = { \ + .id = MPQ7920_BUCK ## _id, \ + .name = _name, \ + .of_match = _name, \ + .regulators_node = "regulators", \ + .of_parse_cb = mpq7920_parse_cb, \ + .ops = &mpq7920_buck_ops, \ + .min_uV = MPQ7920_BUCK_VOLT_MIN, \ + .uV_step = MPQ7920_VOLT_STEP, \ + .n_voltages = MPQ7920_BUCK_VOLT_RANGE, \ + .curr_table = _ilim, \ + .n_current_limits = ARRAY_SIZE(_ilim), \ + .csel_reg = MPQ7920_BUCK ##_id## _REG_C, \ + .csel_mask = MPQ7920_MASK_BUCK_ILIM, \ + .enable_reg = MPQ7920_REG_REGULATOR_EN, \ + .enable_mask = BIT(MPQ7920_REGULATOR_EN_OFFSET - \ + MPQ7920_BUCK ## _id), \ + .vsel_reg = MPQ7920_BUCK ##_id## _REG_A, \ + .vsel_mask = MPQ7920_MASK_VREF, \ + .active_discharge_on = MPQ7920_DISCHARGE_ON, \ + .active_discharge_reg = MPQ7920_BUCK ##_id## _REG_B, \ + .active_discharge_mask = MPQ7920_MASK_DISCHARGE, \ + .soft_start_reg = MPQ7920_BUCK ##_id## _REG_C, \ + .soft_start_mask = MPQ7920_MASK_SOFTSTART, \ + .owner = THIS_MODULE, \ + } + +#define MPQ7920LDO(_name, _id, _ops, _ilim, _ilim_sz, _creg, _cmask) \ + [MPQ7920_LDO ## _id] = { \ + .id = MPQ7920_LDO ## _id, \ + .name = _name, \ + .of_match = _name, \ + .regulators_node = "regulators", \ + .ops = _ops, \ + .min_uV = MPQ7920_LDO_VOLT_MIN, \ + .uV_step = MPQ7920_VOLT_STEP, \ + .n_voltages = MPQ7920_LDO_VOLT_RANGE, \ + .vsel_reg = MPQ7920_LDO ##_id## _REG_A, \ + .vsel_mask = MPQ7920_MASK_VREF, \ + .curr_table = _ilim, \ + .n_current_limits = _ilim_sz, \ + .csel_reg = _creg, \ + .csel_mask = _cmask, \ + .enable_reg = (_id == 1) ? 0 : MPQ7920_REG_REGULATOR_EN,\ + .enable_mask = BIT(MPQ7920_REGULATOR_EN_OFFSET - \ + MPQ7920_LDO ##_id + 1), \ + .active_discharge_on = MPQ7920_DISCHARGE_ON, \ + .active_discharge_mask = MPQ7920_MASK_DISCHARGE, \ + .active_discharge_reg = MPQ7920_LDO ##_id## _REG_B, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +enum mpq7920_regulators { + MPQ7920_BUCK1, + MPQ7920_BUCK2, + MPQ7920_BUCK3, + MPQ7920_BUCK4, + MPQ7920_LDO1, /* LDORTC */ + MPQ7920_LDO2, + MPQ7920_LDO3, + MPQ7920_LDO4, + MPQ7920_LDO5, + MPQ7920_MAX_REGULATORS, +}; + +struct mpq7920_regulator_info { + struct regmap *regmap; + struct regulator_desc *rdesc; +}; + +static const struct regmap_config mpq7920_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x25, +}; + +/* Current limits array (in uA) + * ILIM1 & ILIM3 + */ +static const unsigned int mpq7920_I_limits1[] = { + 4600000, 6600000, 7600000, 9300000 +}; + +/* ILIM2 & ILIM4 */ +static const unsigned int mpq7920_I_limits2[] = { + 2700000, 3900000, 5100000, 6100000 +}; + +/* LDO4 & LDO5 */ +static const unsigned int mpq7920_I_limits3[] = { + 300000, 700000 +}; + +static int mpq7920_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay); +static int mpq7920_parse_cb(struct device_node *np, + const struct regulator_desc *rdesc, + struct regulator_config *config); + +/* RTCLDO not controllable, always ON */ +static const struct regulator_ops mpq7920_ldortc_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_ops mpq7920_ldo_wo_current_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +static const struct regulator_ops mpq7920_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .get_current_limit = regulator_get_current_limit_regmap, + .set_current_limit = regulator_set_current_limit_regmap, +}; + +static const struct regulator_ops mpq7920_buck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_soft_start = regulator_set_soft_start_regmap, + .set_ramp_delay = mpq7920_set_ramp_delay, +}; + +static struct regulator_desc mpq7920_regulators_desc[MPQ7920_MAX_REGULATORS] = { + MPQ7920BUCK("buck1", 1, mpq7920_I_limits1), + MPQ7920BUCK("buck2", 2, mpq7920_I_limits2), + MPQ7920BUCK("buck3", 3, mpq7920_I_limits1), + MPQ7920BUCK("buck4", 4, mpq7920_I_limits2), + MPQ7920LDO("ldortc", 1, &mpq7920_ldortc_ops, NULL, 0, 0, 0), + MPQ7920LDO("ldo2", 2, &mpq7920_ldo_wo_current_ops, NULL, 0, 0, 0), + MPQ7920LDO("ldo3", 3, &mpq7920_ldo_wo_current_ops, NULL, 0, 0, 0), + MPQ7920LDO("ldo4", 4, &mpq7920_ldo_ops, mpq7920_I_limits3, + ARRAY_SIZE(mpq7920_I_limits3), MPQ7920_LDO4_REG_B, + MPQ7920_MASK_LDO_ILIM), + MPQ7920LDO("ldo5", 5, &mpq7920_ldo_ops, mpq7920_I_limits3, + ARRAY_SIZE(mpq7920_I_limits3), MPQ7920_LDO5_REG_B, + MPQ7920_MASK_LDO_ILIM), +}; + +/* + * DVS ramp rate BUCK1 to BUCK4 + * 00-01: Reserved + * 10: 8mV/us + * 11: 4mV/us + */ +static int mpq7920_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + unsigned int ramp_val; + + if (ramp_delay > 8000 || ramp_delay < 0) + return -EINVAL; + + if (ramp_delay <= 4000) + ramp_val = 3; + else + ramp_val = 2; + + return regmap_update_bits(rdev->regmap, MPQ7920_REG_CTL0, + MPQ7920_MASK_DVS_SLEWRATE, ramp_val << 6); +} + +static int mpq7920_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + uint8_t val; + int ret; + struct mpq7920_regulator_info *info = config->driver_data; + struct regulator_desc *rdesc = &info->rdesc[desc->id]; + + if (of_property_read_bool(np, "mps,buck-ovp-disable")) { + regmap_update_bits(config->regmap, + MPQ7920_BUCK1_REG_B + (rdesc->id * 4), + MPQ7920_MASK_OVP, MPQ7920_OVP_DISABLE); + } + + ret = of_property_read_u8(np, "mps,buck-phase-delay", &val); + if (!ret) { + regmap_update_bits(config->regmap, + MPQ7920_BUCK1_REG_C + (rdesc->id * 4), + MPQ7920_MASK_BUCK_PHASE_DEALY, + (val & 3) << 4); + } + + ret = of_property_read_u8(np, "mps,buck-softstart", &val); + if (!ret) + rdesc->soft_start_val_on = (val & 3) << 2; + + return 0; +} + +static void mpq7920_parse_dt(struct device *dev, + struct mpq7920_regulator_info *info) +{ + int ret; + struct device_node *np = dev->of_node; + uint8_t freq; + + np = of_get_child_by_name(np, "regulators"); + if (!np) { + dev_err(dev, "missing 'regulators' subnode in DT\n"); + return; + } + + ret = of_property_read_u8(np, "mps,switch-freq", &freq); + if (!ret) { + regmap_update_bits(info->regmap, MPQ7920_REG_CTL0, + MPQ7920_MASK_SWITCH_FREQ, + (freq & 3) << 4); + } + + of_node_put(np); +} + +static int mpq7920_i2c_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct mpq7920_regulator_info *info; + struct regulator_config config = { NULL, }; + struct regulator_dev *rdev; + struct regmap *regmap; + int i; + + info = devm_kzalloc(dev, sizeof(struct mpq7920_regulator_info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->rdesc = mpq7920_regulators_desc; + regmap = devm_regmap_init_i2c(client, &mpq7920_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "Failed to allocate regmap!\n"); + return PTR_ERR(regmap); + } + + i2c_set_clientdata(client, info); + info->regmap = regmap; + if (client->dev.of_node) + mpq7920_parse_dt(&client->dev, info); + + config.dev = dev; + config.regmap = regmap; + config.driver_data = info; + + for (i = 0; i < MPQ7920_MAX_REGULATORS; i++) { + rdev = devm_regulator_register(dev, + &mpq7920_regulators_desc[i], + &config); + if (IS_ERR(rdev)) { + dev_err(dev, "Failed to register regulator!\n"); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct of_device_id mpq7920_of_match[] = { + { .compatible = "mps,mpq7920"}, + {}, +}; +MODULE_DEVICE_TABLE(of, mpq7920_of_match); + +static const struct i2c_device_id mpq7920_id[] = { + { "mpq7920", }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, mpq7920_id); + +static struct i2c_driver mpq7920_regulator_driver = { + .driver = { + .name = "mpq7920", + .of_match_table = of_match_ptr(mpq7920_of_match), + }, + .probe_new = mpq7920_i2c_probe, + .id_table = mpq7920_id, +}; +module_i2c_driver(mpq7920_regulator_driver); + +MODULE_AUTHOR("Saravanan Sekar "); +MODULE_DESCRIPTION("MPQ7920 PMIC regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/mpq7920.h b/drivers/regulator/mpq7920.h new file mode 100644 index 000000000000..489924655a96 --- /dev/null +++ b/drivers/regulator/mpq7920.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * mpq7920.h - Regulator definitions for mpq7920 + * + * Copyright 2019 Monolithic Power Systems, Inc + * + */ + +#ifndef __MPQ7920_H__ +#define __MPQ7920_H__ + +#define MPQ7920_REG_CTL0 0x00 +#define MPQ7920_REG_CTL1 0x01 +#define MPQ7920_REG_CTL2 0x02 +#define MPQ7920_BUCK1_REG_A 0x03 +#define MPQ7920_BUCK1_REG_B 0x04 +#define MPQ7920_BUCK1_REG_C 0x05 +#define MPQ7920_BUCK1_REG_D 0x06 +#define MPQ7920_BUCK2_REG_A 0x07 +#define MPQ7920_BUCK2_REG_B 0x08 +#define MPQ7920_BUCK2_REG_C 0x09 +#define MPQ7920_BUCK2_REG_D 0x0a +#define MPQ7920_BUCK3_REG_A 0x0b +#define MPQ7920_BUCK3_REG_B 0x0c +#define MPQ7920_BUCK3_REG_C 0x0d +#define MPQ7920_BUCK3_REG_D 0x0e +#define MPQ7920_BUCK4_REG_A 0x0f +#define MPQ7920_BUCK4_REG_B 0x10 +#define MPQ7920_BUCK4_REG_C 0x11 +#define MPQ7920_BUCK4_REG_D 0x12 +#define MPQ7920_LDO1_REG_A 0x13 +#define MPQ7920_LDO1_REG_B 0x0 +#define MPQ7920_LDO2_REG_A 0x14 +#define MPQ7920_LDO2_REG_B 0x15 +#define MPQ7920_LDO2_REG_C 0x16 +#define MPQ7920_LDO3_REG_A 0x17 +#define MPQ7920_LDO3_REG_B 0x18 +#define MPQ7920_LDO3_REG_C 0x19 +#define MPQ7920_LDO4_REG_A 0x1a +#define MPQ7920_LDO4_REG_B 0x1b +#define MPQ7920_LDO4_REG_C 0x1c +#define MPQ7920_LDO5_REG_A 0x1d +#define MPQ7920_LDO5_REG_B 0x1e +#define MPQ7920_LDO5_REG_C 0x1f +#define MPQ7920_REG_MODE 0x20 +#define MPQ7920_REG_REGULATOR_EN 0x22 + +#define MPQ7920_MASK_VREF 0x7f +#define MPQ7920_MASK_BUCK_ILIM 0xc0 +#define MPQ7920_MASK_LDO_ILIM BIT(6) +#define MPQ7920_MASK_DISCHARGE BIT(5) +#define MPQ7920_MASK_MODE 0xc0 +#define MPQ7920_MASK_SOFTSTART 0x0c +#define MPQ7920_MASK_SWITCH_FREQ 0x30 +#define MPQ7920_MASK_BUCK_PHASE_DEALY 0x30 +#define MPQ7920_MASK_DVS_SLEWRATE 0xc0 +#define MPQ7920_MASK_OVP 0x40 +#define MPQ7920_OVP_DISABLE ~(0x40) +#define MPQ7920_DISCHARGE_ON BIT(5) + +#define MPQ7920_REGULATOR_EN_OFFSET 7 + +/* values in mV */ +#define MPQ7920_BUCK_VOLT_MIN 400000 +#define MPQ7920_LDO_VOLT_MIN 650000 +#define MPQ7920_VOLT_MAX 3587500 +#define MPQ7920_VOLT_STEP 12500 + +#endif /* __MPQ7920_H__ */ diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c index af95449d3590..69e6af3cd505 100644 --- a/drivers/regulator/mt6311-regulator.c +++ b/drivers/regulator/mt6311-regulator.c @@ -85,8 +85,7 @@ static const struct regulator_desc mt6311_regulators[] = { /* * I2C driver interface functions */ -static int mt6311_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int mt6311_i2c_probe(struct i2c_client *i2c) { struct regulator_config config = { }; struct regulator_dev *rdev; @@ -154,7 +153,7 @@ static struct i2c_driver mt6311_regulator_driver = { .name = "mt6311", .of_match_table = of_match_ptr(mt6311_dt_ids), }, - .probe = mt6311_i2c_probe, + .probe_new = mt6311_i2c_probe, .id_table = mt6311_i2c_id, }; diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c index 3d3415839ba2..787ced918372 100644 --- a/drivers/regulator/pv88060-regulator.c +++ b/drivers/regulator/pv88060-regulator.c @@ -279,8 +279,7 @@ static irqreturn_t pv88060_irq_handler(int irq, void *data) /* * I2C driver interface functions */ -static int pv88060_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int pv88060_i2c_probe(struct i2c_client *i2c) { struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); struct pv88060 *chip; @@ -385,7 +384,7 @@ static struct i2c_driver pv88060_regulator_driver = { .name = "pv88060", .of_match_table = of_match_ptr(pv88060_dt_ids), }, - .probe = pv88060_i2c_probe, + .probe_new = pv88060_i2c_probe, .id_table = pv88060_i2c_id, }; diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c index b1d0d97ae935..784729ec2182 100644 --- a/drivers/regulator/pv88090-regulator.c +++ b/drivers/regulator/pv88090-regulator.c @@ -272,8 +272,7 @@ static irqreturn_t pv88090_irq_handler(int irq, void *data) /* * I2C driver interface functions */ -static int pv88090_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int pv88090_i2c_probe(struct i2c_client *i2c) { struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); struct pv88090 *chip; @@ -406,7 +405,7 @@ static struct i2c_driver pv88090_regulator_driver = { .name = "pv88090", .of_match_table = of_match_ptr(pv88090_dt_ids), }, - .probe = pv88090_i2c_probe, + .probe_new = pv88090_i2c_probe, .id_table = pv88090_i2c_id, }; diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 5b4003226484..31f79fda3238 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -1282,7 +1282,7 @@ static int rk808_regulator_dt_parse_pdata(struct device *dev, } if (!pdata->dvs_gpio[i]) { - dev_warn(dev, "there is no dvs%d gpio\n", i); + dev_info(dev, "there is no dvs%d gpio\n", i); continue; } diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c index 51f7e8b74d8c..115f59530852 100644 --- a/drivers/regulator/s2mpa01.c +++ b/drivers/regulator/s2mpa01.c @@ -390,5 +390,5 @@ module_platform_driver(s2mpa01_pmic_driver); /* Module information */ MODULE_AUTHOR("Sangbeom Kim "); MODULE_AUTHOR("Sachin Kamat "); -MODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver"); +MODULE_DESCRIPTION("Samsung S2MPA01 Regulator Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 4f2dc5ebffdc..23d288278957 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1265,5 +1265,5 @@ module_platform_driver(s2mps11_pmic_driver); /* Module information */ MODULE_AUTHOR("Sangbeom Kim "); -MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14/S2MPS15/S2MPU02 Regulator Driver"); +MODULE_DESCRIPTION("Samsung S2MPS11/S2MPS14/S2MPS15/S2MPU02 Regulator Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 12d6b8d2e97e..4abd3ed31f60 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -1015,5 +1015,5 @@ module_exit(s5m8767_pmic_exit); /* Module information */ MODULE_AUTHOR("Sangbeom Kim "); -MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver"); +MODULE_DESCRIPTION("Samsung S5M8767 Regulator Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/slg51000-regulator.c b/drivers/regulator/slg51000-regulator.c index bf1a3508ebc4..44e4cecbf6de 100644 --- a/drivers/regulator/slg51000-regulator.c +++ b/drivers/regulator/slg51000-regulator.c @@ -439,8 +439,7 @@ static void slg51000_clear_fault_log(struct slg51000 *chip) dev_dbg(chip->dev, "Fault log: FLT_POR\n"); } -static int slg51000_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int slg51000_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct slg51000 *chip; @@ -509,7 +508,7 @@ static struct i2c_driver slg51000_regulator_driver = { .driver = { .name = "slg51000-regulator", }, - .probe = slg51000_i2c_probe, + .probe_new = slg51000_i2c_probe, .id_table = slg51000_i2c_id, }; diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c index 42e03b2c10a0..2222e739e62b 100644 --- a/drivers/regulator/sy8106a-regulator.c +++ b/drivers/regulator/sy8106a-regulator.c @@ -61,8 +61,7 @@ static const struct regulator_desc sy8106a_reg = { /* * I2C driver interface functions */ -static int sy8106a_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sy8106a_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct regulator_dev *rdev; @@ -141,7 +140,7 @@ static struct i2c_driver sy8106a_regulator_driver = { .name = "sy8106a", .of_match_table = of_match_ptr(sy8106a_i2c_of_match), }, - .probe = sy8106a_i2c_probe, + .probe_new = sy8106a_i2c_probe, .id_table = sy8106a_i2c_id, }; diff --git a/drivers/regulator/sy8824x.c b/drivers/regulator/sy8824x.c index 92adb4f3ee19..62d243f3b904 100644 --- a/drivers/regulator/sy8824x.c +++ b/drivers/regulator/sy8824x.c @@ -112,8 +112,7 @@ static const struct regmap_config sy8824_regmap_config = { .val_bits = 8, }; -static int sy8824_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sy8824_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device_node *np = dev->of_node; @@ -222,7 +221,7 @@ static struct i2c_driver sy8824_regulator_driver = { .name = "sy8824-regulator", .of_match_table = of_match_ptr(sy8824_dt_ids), }, - .probe = sy8824_i2c_probe, + .probe_new = sy8824_i2c_probe, .id_table = sy8824_id, }; module_i2c_driver(sy8824_regulator_driver); diff --git a/drivers/regulator/tps65132-regulator.c b/drivers/regulator/tps65132-regulator.c index 7b0e38f8d627..0edc83089ba2 100644 --- a/drivers/regulator/tps65132-regulator.c +++ b/drivers/regulator/tps65132-regulator.c @@ -220,8 +220,7 @@ static const struct regmap_config tps65132_regmap_config = { .wr_table = &tps65132_no_reg_table, }; -static int tps65132_probe(struct i2c_client *client, - const struct i2c_device_id *client_id) +static int tps65132_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tps65132_regulator *tps; @@ -272,7 +271,7 @@ static struct i2c_driver tps65132_i2c_driver = { .driver = { .name = "tps65132", }, - .probe = tps65132_probe, + .probe_new = tps65132_probe, .id_table = tps65132_id, }; diff --git a/drivers/regulator/vctrl-regulator.c b/drivers/regulator/vctrl-regulator.c index 9a9ee8188109..cbadb1c99679 100644 --- a/drivers/regulator/vctrl-regulator.c +++ b/drivers/regulator/vctrl-regulator.c @@ -11,10 +11,13 @@ #include #include #include +#include #include #include #include +#include "internal.h" + struct vctrl_voltage_range { int min_uV; int max_uV; @@ -79,7 +82,7 @@ static int vctrl_calc_output_voltage(struct vctrl_data *vctrl, int ctrl_uV) static int vctrl_get_voltage(struct regulator_dev *rdev) { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); - int ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg); + int ctrl_uV = regulator_get_voltage_rdev(vctrl->ctrl_reg->rdev); return vctrl_calc_output_voltage(vctrl, ctrl_uV); } @@ -90,16 +93,16 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); struct regulator *ctrl_reg = vctrl->ctrl_reg; - int orig_ctrl_uV = regulator_get_voltage(ctrl_reg); + int orig_ctrl_uV = regulator_get_voltage_rdev(ctrl_reg->rdev); int uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV); int ret; if (req_min_uV >= uV || !vctrl->ovp_threshold) /* voltage rising or no OVP */ - return regulator_set_voltage( - ctrl_reg, + return regulator_set_voltage_rdev(ctrl_reg->rdev, vctrl_calc_ctrl_voltage(vctrl, req_min_uV), - vctrl_calc_ctrl_voltage(vctrl, req_max_uV)); + vctrl_calc_ctrl_voltage(vctrl, req_max_uV), + PM_SUSPEND_ON); while (uV > req_min_uV) { int max_drop_uV = (uV * vctrl->ovp_threshold) / 100; @@ -114,9 +117,10 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, next_uV = max_t(int, req_min_uV, uV - max_drop_uV); next_ctrl_uV = vctrl_calc_ctrl_voltage(vctrl, next_uV); - ret = regulator_set_voltage(ctrl_reg, + ret = regulator_set_voltage_rdev(ctrl_reg->rdev, next_ctrl_uV, - next_ctrl_uV); + next_ctrl_uV, + PM_SUSPEND_ON); if (ret) goto err; @@ -130,7 +134,8 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, err: /* Try to go back to original voltage */ - regulator_set_voltage(ctrl_reg, orig_ctrl_uV, orig_ctrl_uV); + regulator_set_voltage_rdev(ctrl_reg->rdev, orig_ctrl_uV, orig_ctrl_uV, + PM_SUSPEND_ON); return ret; } @@ -155,9 +160,10 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, if (selector >= vctrl->sel || !vctrl->ovp_threshold) { /* voltage rising or no OVP */ - ret = regulator_set_voltage(ctrl_reg, + ret = regulator_set_voltage_rdev(ctrl_reg->rdev, vctrl->vtable[selector].ctrl, - vctrl->vtable[selector].ctrl); + vctrl->vtable[selector].ctrl, + PM_SUSPEND_ON); if (!ret) vctrl->sel = selector; @@ -173,9 +179,10 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, else next_sel = vctrl->vtable[vctrl->sel].ovp_min_sel; - ret = regulator_set_voltage(ctrl_reg, + ret = regulator_set_voltage_rdev(ctrl_reg->rdev, vctrl->vtable[next_sel].ctrl, - vctrl->vtable[next_sel].ctrl); + vctrl->vtable[next_sel].ctrl, + PM_SUSPEND_ON); if (ret) { dev_err(&rdev->dev, "failed to set control voltage to %duV\n", @@ -195,9 +202,10 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, err: if (vctrl->sel != orig_sel) { /* Try to go back to original voltage */ - if (!regulator_set_voltage(ctrl_reg, + if (!regulator_set_voltage_rdev(ctrl_reg->rdev, vctrl->vtable[orig_sel].ctrl, - vctrl->vtable[orig_sel].ctrl)) + vctrl->vtable[orig_sel].ctrl, + PM_SUSPEND_ON)) vctrl->sel = orig_sel; else dev_warn(&rdev->dev, @@ -482,7 +490,7 @@ static int vctrl_probe(struct platform_device *pdev) if (ret) return ret; - ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg); + ctrl_uV = regulator_get_voltage_rdev(vctrl->ctrl_reg->rdev); if (ctrl_uV < 0) { dev_err(&pdev->dev, "failed to get control voltage\n"); return ctrl_uV; diff --git a/drivers/regulator/vqmmc-ipq4019-regulator.c b/drivers/regulator/vqmmc-ipq4019-regulator.c new file mode 100644 index 000000000000..6d5ae25d08d1 --- /dev/null +++ b/drivers/regulator/vqmmc-ipq4019-regulator.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2019 Mantas Pucka +// Copyright (c) 2019 Robert Marko +// +// Driver for IPQ4019 SD/MMC controller's I/O LDO voltage regulator + +#include +#include +#include +#include +#include +#include +#include +#include + +static const unsigned int ipq4019_vmmc_voltages[] = { + 1500000, 1800000, 2500000, 3000000, +}; + +static const struct regulator_ops ipq4019_regulator_voltage_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_desc vmmc_regulator = { + .name = "vmmcq", + .ops = &ipq4019_regulator_voltage_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .volt_table = ipq4019_vmmc_voltages, + .n_voltages = ARRAY_SIZE(ipq4019_vmmc_voltages), + .vsel_reg = 0, + .vsel_mask = 0x3, +}; + +static const struct regmap_config ipq4019_vmmcq_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static int ipq4019_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regulator_init_data *init_data; + struct regulator_config cfg = {}; + struct regulator_dev *rdev; + struct resource *res; + struct regmap *rmap; + void __iomem *base; + + init_data = of_get_regulator_init_data(dev, dev->of_node, + &vmmc_regulator); + if (!init_data) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + rmap = devm_regmap_init_mmio(dev, base, &ipq4019_vmmcq_regmap_config); + if (IS_ERR(rmap)) + return PTR_ERR(rmap); + + cfg.dev = dev; + cfg.init_data = init_data; + cfg.of_node = dev->of_node; + cfg.regmap = rmap; + + rdev = devm_regulator_register(dev, &vmmc_regulator, &cfg); + if (IS_ERR(rdev)) { + dev_err(dev, "Failed to register regulator: %ld\n", + PTR_ERR(rdev)); + return PTR_ERR(rdev); + } + platform_set_drvdata(pdev, rdev); + + return 0; +} + +static const struct of_device_id regulator_ipq4019_of_match[] = { + { .compatible = "qcom,vqmmc-ipq4019-regulator", }, + {}, +}; + +static struct platform_driver ipq4019_regulator_driver = { + .probe = ipq4019_regulator_probe, + .driver = { + .name = "vqmmc-ipq4019-regulator", + .of_match_table = of_match_ptr(regulator_ipq4019_of_match), + }, +}; +module_platform_driver(ipq4019_regulator_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mantas Pucka "); +MODULE_DESCRIPTION("IPQ4019 VQMMC voltage regulator"); diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 337a46391527..6a92fd3105a3 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -287,6 +287,8 @@ void regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers, const char *const *supply_names, unsigned int num_supplies); +bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2); + #else /* @@ -593,6 +595,11 @@ regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers, { } +static inline bool +regulator_is_equal(struct regulator *reg1, struct regulator *reg2) +{ + return false; +} #endif static inline int regulator_set_voltage_triplet(struct regulator *regulator,