summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig161
-rw-r--r--drivers/regulator/Makefile15
-rw-r--r--drivers/regulator/act8865-regulator.c2
-rw-r--r--drivers/regulator/ad5398.c30
-rw-r--r--drivers/regulator/adp5055-regulator.c424
-rw-r--r--drivers/regulator/arizona-micsupp.c8
-rw-r--r--drivers/regulator/axp20x-regulator.c24
-rw-r--r--drivers/regulator/bcm590xx-regulator.c1289
-rw-r--r--drivers/regulator/bd71815-regulator.c8
-rw-r--r--drivers/regulator/bd71828-regulator.c4
-rw-r--r--drivers/regulator/bd718x7-regulator.c35
-rw-r--r--drivers/regulator/bd96801-regulator.c577
-rw-r--r--drivers/regulator/bq257xx-regulator.c186
-rw-r--r--drivers/regulator/core.c530
-rw-r--r--drivers/regulator/cros-ec-regulator.c4
-rw-r--r--drivers/regulator/da9121-regulator.c2
-rw-r--r--drivers/regulator/devres.c22
-rw-r--r--drivers/regulator/dummy.c37
-rw-r--r--drivers/regulator/fan53555.c14
-rw-r--r--drivers/regulator/fixed.c1
-rw-r--r--drivers/regulator/fp9931.c551
-rw-r--r--drivers/regulator/gpio-regulator.c18
-rw-r--r--drivers/regulator/hi6421-regulator.c10
-rw-r--r--drivers/regulator/hi6421v530-regulator.c4
-rw-r--r--drivers/regulator/hi6421v600-regulator.c6
-rw-r--r--drivers/regulator/irq_helpers.c18
-rw-r--r--drivers/regulator/max14577-regulator.c5
-rw-r--r--drivers/regulator/max20086-regulator.c17
-rw-r--r--drivers/regulator/max77650-regulator.c6
-rw-r--r--drivers/regulator/max77838-regulator.c221
-rw-r--r--drivers/regulator/mp886x.c3
-rw-r--r--drivers/regulator/mt6315-regulator.c6
-rw-r--r--drivers/regulator/mt6316-regulator.c345
-rw-r--r--drivers/regulator/mt6358-regulator.c2
-rw-r--r--drivers/regulator/mt6363-regulator.c938
-rw-r--r--drivers/regulator/mt6370-regulator.c4
-rw-r--r--drivers/regulator/mtk-dvfsrc-regulator.c38
-rw-r--r--drivers/regulator/of_regulator.c46
-rw-r--r--drivers/regulator/pca9450-regulator.c544
-rw-r--r--drivers/regulator/pcf50633-regulator.c124
-rw-r--r--drivers/regulator/pf0900-regulator.c975
-rw-r--r--drivers/regulator/pf1550-regulator.c429
-rw-r--r--drivers/regulator/pf530x-regulator.c375
-rw-r--r--drivers/regulator/pf9453-regulator.c870
-rw-r--r--drivers/regulator/qcom-labibb-regulator.c4
-rw-r--r--drivers/regulator/qcom-pm8008-regulator.c2
-rw-r--r--drivers/regulator/qcom-refgen-regulator.c1
-rw-r--r--drivers/regulator/qcom-rpmh-regulator.c1331
-rw-r--r--drivers/regulator/qcom_spmi-regulator.c69
-rw-r--r--drivers/regulator/renesas-usb-vbus-regulator.c2
-rw-r--r--drivers/regulator/rk808-regulator.c4
-rw-r--r--drivers/regulator/rpi-panel-attiny-regulator.c81
-rw-r--r--drivers/regulator/rpi-panel-v2-regulator.c125
-rw-r--r--drivers/regulator/rt5133-regulator.c642
-rw-r--r--drivers/regulator/rt5739.c9
-rw-r--r--drivers/regulator/rt6160-regulator.c19
-rw-r--r--drivers/regulator/rtq2208-regulator.c216
-rw-r--r--drivers/regulator/rtq6752-regulator.c2
-rw-r--r--drivers/regulator/s2dos05-regulator.c165
-rw-r--r--drivers/regulator/s2mps11.c92
-rw-r--r--drivers/regulator/s5m8767.c146
-rw-r--r--drivers/regulator/scmi-regulator.c3
-rw-r--r--drivers/regulator/spacemit-p1.c157
-rw-r--r--drivers/regulator/stm32-vrefbuf.c6
-rw-r--r--drivers/regulator/sy7636a-regulator.c34
-rw-r--r--drivers/regulator/sy8824x.c5
-rw-r--r--drivers/regulator/sy8827n.c3
-rw-r--r--drivers/regulator/tps6286x-regulator.c9
-rw-r--r--drivers/regulator/tps6287x-regulator.c64
-rw-r--r--drivers/regulator/tps65219-regulator.c279
-rw-r--r--drivers/regulator/tps6524x-regulator.c1
-rw-r--r--drivers/regulator/tps6594-regulator.c273
72 files changed, 10886 insertions, 1786 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 39297f7d8177..d2335276cce5 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -122,6 +122,17 @@ config REGULATOR_AD5398
This driver supports AD5398 and AD5821 current regulator chips.
If building into module, its name is ad5398.ko.
+config REGULATOR_ADP5055
+ tristate "Analog Devices ADP5055 Triple Buck Regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver controls an Analog Devices ADP5055 with triple buck
+ regulators using an I2C interface.
+
+ Say M here if you want to include support for the regulator as a
+ module.
+
config REGULATOR_ANATOP
tristate "Freescale i.MX on-chip ANATOP LDO regulators"
depends on ARCH_MXC || COMPILE_TEST
@@ -286,6 +297,14 @@ config REGULATOR_BD96801
This driver can also be built as a module. If so, the module
will be called bd96801-regulator.
+config REGULATOR_BQ257XX
+ tristate "TI BQ257XX regulator family"
+ depends on MFD_BQ257XX
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say Y to enable support for the boost regulator function of
+ the BQ257XX family of charger circuits.
+
config REGULATOR_CPCAP
tristate "Motorola CPCAP regulator"
depends on MFD_CPCAP
@@ -481,6 +500,16 @@ config REGULATOR_ISL6271A
help
This driver supports ISL6271A voltage regulator chip.
+config REGULATOR_FP9931
+ tristate "FitiPower FP9931/JD9930 EPD regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports the FP9931/JD9930 voltage regulator chip
+ which is used to provide power to Electronic Paper Displays
+ so it is found in E-Book readers.
+ If HWWON is enabled, it also provides temperature measurement.
+
config REGULATOR_LM363X
tristate "TI LM363X voltage regulators"
depends on MFD_TI_LMU
@@ -766,6 +795,15 @@ config REGULATOR_MAX77826
It includes support for control of output voltage. This
regulator is found on the Samsung Galaxy S5 (klte) smartphone.
+config REGULATOR_MAX77838
+ tristate "Maxim 77838 regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver controls a Maxim 77838 regulator via I2C bus.
+ The regulator include 4 LDOs and a BUCK regulator. It's
+ present on the Samsung Galaxy S7 lineup of smartphones.
+
config REGULATOR_MC13XXX_CORE
tristate
@@ -853,6 +891,16 @@ config REGULATOR_MT6315
This driver supports the control of different power rails of device
through regulator interface.
+config REGULATOR_MT6316
+ tristate "MT6316 SPMI PMIC regulator driver"
+ depends on SPMI
+ select REGMAP_SPMI
+ help
+ Say Y here to enable support for 2+2, 3+1 and 4 phase regulators
+ found in the MediaTek MT6316 BP, CP, DP, HP, VP and TP SPMI PMICs.
+ This driver supports the control of different power rails of device
+ through regulator interface.
+
config REGULATOR_MT6323
tristate "MediaTek MT6323 PMIC"
depends on MFD_MT6397
@@ -916,6 +964,16 @@ config REGULATOR_MT6360
2-channel buck with Thermal Shutdown and Overload Protection
6-channel High PSRR and Low Dropout LDO.
+config REGULATOR_MT6363
+ tristate "MT6363 SPMI PMIC regulator driver"
+ depends on SPMI
+ select REGMAP_SPMI
+ help
+ Say Y here to enable support for regulators found in the MediaTek
+ MT6363 SPMI PMIC.
+ This driver supports the control of different power rails of device
+ through regulator interface.
+
config REGULATOR_MT6370
tristate "MT6370 SubPMIC Regulator"
depends on MFD_MT6370
@@ -981,6 +1039,13 @@ config REGULATOR_PCA9450
Say y here to support the NXP PCA9450A/PCA9450B/PCA9450C PMIC
regulator driver.
+config REGULATOR_PF9453
+ tristate "NXP PF9453 regulator driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support the NXP PF9453 PMIC regulator driver.
+
config REGULATOR_PCAP
tristate "Motorola PCAP2 regulator driver"
depends on EZX_PCAP
@@ -988,12 +1053,25 @@ config REGULATOR_PCAP
This driver provides support for the voltage regulators of the
PCAP2 PMIC.
-config REGULATOR_PCF50633
- tristate "NXP PCF50633 regulator driver"
- depends on MFD_PCF50633
+config REGULATOR_PF0900
+ tristate "NXP PF0900/PF0901/PF09XX regulator driver"
+ depends on I2C
+ select REGMAP_I2C
help
- Say Y here to support the voltage regulators and converters
- on PCF50633
+ Say y here to support the NXP PF0900/PF0901/PF09XX PMIC
+ regulator driver.
+
+config REGULATOR_PF530X
+ tristate "NXP PF5300/PF5301/PF5302 regulator driver"
+ depends on I2C && OF
+ select REGMAP_I2C
+ help
+ Say y here to support the regulators found on the NXP
+ PF5300/PF5301/PF5302 PMIC.
+
+ Say M here if you want to support for the regulators found
+ on the NXP PF5300/PF5301/PF5302 PMIC. The module will be named
+ "pf530x-regulator".
config REGULATOR_PF8X00
tristate "NXP PF8100/PF8121A/PF8200 regulator driver"
@@ -1038,6 +1116,15 @@ config REGULATOR_PV88090
Say y here to support the voltage regulators and convertors
on PV88090
+config REGULATOR_PF1550
+ tristate "NXP PF1550 regulator"
+ depends on MFD_PF1550
+ help
+ Say y here to select this option to enable the regulators on
+ the PF1550 PMICs.
+ This driver controls the PF1550 regulators via I2C bus.
+ The regulators include three bucks and three ldos.
+
config REGULATOR_PWM
tristate "PWM voltage regulator"
depends on PWM
@@ -1133,6 +1220,7 @@ config REGULATOR_RAA215300
config REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY
tristate "Raspberry Pi 7-inch touchscreen panel ATTINY regulator"
+ depends on ARM || ARM64 || COMPILE_TEST
depends on BACKLIGHT_CLASS_DEVICE
depends on I2C
depends on OF_GPIO
@@ -1142,6 +1230,18 @@ config REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY
touchscreen unit. The regulator is used to enable power to the
TC358762, display and to control backlight.
+config REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2
+ tristate "Raspberry Pi 7-inch touchscreen panel V2 regulator"
+ depends on ARM || ARM64 || COMPILE_TEST
+ depends on GPIOLIB
+ depends on I2C && OF
+ select GPIO_REGMAP
+ select REGMAP_I2C
+ help
+ This driver supports regulator on the V2 Raspberry Pi touchscreen
+ unit. The regulator is used to enable power to the display and to
+ control backlight PWM.
+
config REGULATOR_RC5T583
tristate "RICOH RC5T583 Power regulators"
depends on MFD_RC5T583
@@ -1181,7 +1281,7 @@ config REGULATOR_RT4801
The device supports two regulators (DSVP/DSVN).
config REGULATOR_RT4803
- tristate "Richtek RT4803 boost regualtor"
+ tristate "Richtek RT4803 boost regulator"
depends on I2C
select REGMAP_I2C
help
@@ -1218,6 +1318,18 @@ config REGULATOR_RT5120
600mV to 1395mV, per step 6.250mV. The others are all fixed voltage
by external hardware circuit.
+config REGULATOR_RT5133
+ tristate "Richtek RT5133 PMIC Regulators"
+ depends on I2C && GPIOLIB && OF
+ select REGMAP
+ select CRC8
+ select OF_GPIO
+ help
+ This driver adds support for RT5133 PMIC regulators.
+ RT5133 is an integrated chip. It includes 8 LDOs and 3 GPOs that
+ can be used to drive output high/low purpose. The dependency of the
+ GPO block is internally LDO1 Voltage.
+
config REGULATOR_RT5190A
tristate "Richtek RT5190A PMIC"
depends on I2C
@@ -1322,6 +1434,14 @@ config REGULATOR_RTQ2208
and two ldos. It features wide output voltage range from 0.4V to 2.05V
and the capability to configure the corresponding power stages.
+config REGULATOR_S2DOS05
+ tristate "Samsung S2DOS05 voltage regulator"
+ depends on MFD_SEC_CORE || COMPILE_TEST
+ help
+ This driver provides support for the voltage regulators of the S2DOS05.
+ The S2DOS05 is a companion power management IC for the smart phones.
+ The S2DOS05 has 4 LDOs and 1 BUCK outputs.
+
config REGULATOR_S2MPA01
tristate "Samsung S2MPA01 voltage regulator"
depends on MFD_SEC_CORE || COMPILE_TEST
@@ -1330,10 +1450,10 @@ config REGULATOR_S2MPA01
via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
config REGULATOR_S2MPS11
- tristate "Samsung S2MPS11/13/14/15/S2MPU02 voltage regulator"
+ tristate "Samsung S2MPS11/13/14/15/S2MPU02/05 voltage regulator"
depends on MFD_SEC_CORE || COMPILE_TEST
help
- This driver supports a Samsung S2MPS11/13/14/15/S2MPU02 voltage
+ This driver supports a Samsung S2MPS11/13/14/15/S2MPU02/05 voltage
output regulator via I2C bus. The chip is comprised of high efficient
Buck converters including Dual-Phase Buck converter, Buck-Boost
converter, various LDOs.
@@ -1373,6 +1493,19 @@ config REGULATOR_SLG51000
The SLG51000 is seven compact and customizable low dropout
regulators.
+config REGULATOR_SPACEMIT_P1
+ tristate "SpacemiT P1 regulators"
+ depends on ARCH_SPACEMIT || COMPILE_TEST
+ depends on I2C
+ select MFD_SPACEMIT_P1
+ default ARCH_SPACEMIT
+ help
+ Enable support for regulators implemented by the SpacemiT P1
+ power controller. The P1 implements 6 high-efficiency buck
+ converters and 12 programmable LDO regulators. To compile this
+ driver as a module, choose M here. The module will be called
+ "spacemit-pmic".
+
config REGULATOR_STM32_BOOSTER
tristate "STMicroelectronics STM32 BOOSTER"
depends on ARCH_STM32 || COMPILE_TEST
@@ -1579,10 +1712,16 @@ config REGULATOR_TPS65219
tristate "TI TPS65219 Power regulators"
depends on MFD_TPS65219 && OF
help
- This driver supports TPS65219 voltage regulator chips.
+ This driver supports TPS65219, TPS65215, and TPS65214 voltage
+ regulator chips.
TPS65219 series of PMICs have 3 single phase BUCKs & 4 LDOs
- voltage regulators. It supports software based voltage control
- for different voltage domains.
+ voltage regulators.
+ TPS65215 PMIC has 3 single phase BUCKs & 2 LDOs.
+ TPS65214 PMIC has 3 synchronous stepdown DC-DC converters & 2
+ LDOs. One LDO supports a maximum output current of 300 mA and the
+ other a maximum of 500 mA
+ All 3 PMICs support software based voltage control for different
+ voltage domains.
config REGULATOR_TPS6594
tristate "TI TPS6594 Power regulators"
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3d5a803dce8a..1beba1493241 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_REGULATOR_AB8500) += ab8500-ext.o ab8500.o
obj-$(CONFIG_REGULATOR_ACT8865) += act8865-regulator.o
obj-$(CONFIG_REGULATOR_ACT8945A) += act8945a-regulator.o
obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
+obj-$(CONFIG_REGULATOR_ADP5055) += adp5055-regulator.o
obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
obj-$(CONFIG_REGULATOR_ARIZONA_LDO1) += arizona-ldo1.o
obj-$(CONFIG_REGULATOR_ARIZONA_MICSUPP) += arizona-micsupp.o
@@ -37,6 +38,7 @@ obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o
obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
obj-$(CONFIG_REGULATOR_BD957XMUF) += bd9576-regulator.o
+obj-$(CONFIG_REGULATOR_BQ257XX) += bq257xx-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x-regulator.o
obj-$(CONFIG_REGULATOR_BD96801) += bd96801-regulator.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
@@ -57,6 +59,7 @@ obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o
obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
+obj-$(CONFIG_REGULATOR_FP9931) += fp9931.o
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
obj-$(CONFIG_REGULATOR_LOCHNAGAR) += lochnagar-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
@@ -91,6 +94,7 @@ obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o
obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
obj-$(CONFIG_REGULATOR_MAX77826) += max77826-regulator.o
+obj-$(CONFIG_REGULATOR_MAX77838) += max77838-regulator.o
obj-$(CONFIG_REGULATOR_MAX77857) += max77857-regulator.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
@@ -102,6 +106,7 @@ obj-$(CONFIG_REGULATOR_MP886X) += mp886x.o
obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o
+obj-$(CONFIG_REGULATOR_MT6315) += mt6316-regulator.o
obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6331) += mt6331-regulator.o
obj-$(CONFIG_REGULATOR_MT6332) += mt6332-regulator.o
@@ -109,6 +114,7 @@ obj-$(CONFIG_REGULATOR_MT6357) += mt6357-regulator.o
obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o
obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
+obj-$(CONFIG_REGULATOR_MT6363) += mt6363-regulator.o
obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
@@ -123,6 +129,10 @@ obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
+obj-$(CONFIG_REGULATOR_PF0900) += pf0900-regulator.o
+obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o
+obj-$(CONFIG_REGULATOR_PF1550) += pf1550-regulator.o
+obj-$(CONFIG_REGULATOR_PF530X) += pf530x-regulator.o
obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
@@ -132,9 +142,9 @@ obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
-obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RAA215300) += raa215300.o
obj-$(CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY) += rpi-panel-attiny-regulator.o
+obj-$(CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2) += rpi-panel-v2-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o
obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
@@ -144,6 +154,7 @@ obj-$(CONFIG_REGULATOR_RT4803) += rt4803.o
obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o
obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
obj-$(CONFIG_REGULATOR_RT5120) += rt5120-regulator.o
+obj-$(CONFIG_REGULATOR_RT5133) += rt5133-regulator.o
obj-$(CONFIG_REGULATOR_RT5190A) += rt5190a-regulator.o
obj-$(CONFIG_REGULATOR_RT5739) += rt5739.o
obj-$(CONFIG_REGULATOR_RT5759) += rt5759-regulator.o
@@ -154,12 +165,14 @@ obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o
obj-$(CONFIG_REGULATOR_RTQ2134) += rtq2134-regulator.o
obj-$(CONFIG_REGULATOR_RTQ6752) += rtq6752-regulator.o
obj-$(CONFIG_REGULATOR_RTQ2208) += rtq2208-regulator.o
+obj-$(CONFIG_REGULATOR_S2DOS05) += s2dos05-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o
+obj-$(CONFIG_REGULATOR_SPACEMIT_P1) += spacemit-p1.o
obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c
index 0457af23c55a..b2a6ddc6f56d 100644
--- a/drivers/regulator/act8865-regulator.c
+++ b/drivers/regulator/act8865-regulator.c
@@ -643,7 +643,7 @@ static int act8600_charger_probe(struct device *dev, struct regmap *regmap)
struct power_supply *charger;
struct power_supply_config cfg = {
.drv_data = regmap,
- .of_node = dev->of_node,
+ .fwnode = dev_fwnode(dev),
};
charger = devm_power_supply_register(dev, &act8600_charger_desc, &cfg);
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index 40f7dba42b5a..eb2a666a45cb 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -14,8 +14,9 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
-#define AD5398_CURRENT_EN_MASK 0x8000
+#define AD5398_SW_POWER_DOWN BIT(15)
struct ad5398_chip_info {
struct i2c_client *client;
@@ -113,7 +114,7 @@ static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int
/* prepare register data */
selector = (selector << chip->current_offset) & chip->current_mask;
- data = (unsigned short)selector | (data & AD5398_CURRENT_EN_MASK);
+ data = (unsigned short)selector | (data & AD5398_SW_POWER_DOWN);
/* write the new current value back as well as enable bit */
ret = ad5398_write_reg(client, data);
@@ -132,10 +133,10 @@ static int ad5398_is_enabled(struct regulator_dev *rdev)
if (ret < 0)
return ret;
- if (data & AD5398_CURRENT_EN_MASK)
- return 1;
- else
+ if (data & AD5398_SW_POWER_DOWN)
return 0;
+ else
+ return 1;
}
static int ad5398_enable(struct regulator_dev *rdev)
@@ -149,10 +150,10 @@ static int ad5398_enable(struct regulator_dev *rdev)
if (ret < 0)
return ret;
- if (data & AD5398_CURRENT_EN_MASK)
+ if (!(data & AD5398_SW_POWER_DOWN))
return 0;
- data |= AD5398_CURRENT_EN_MASK;
+ data &= ~AD5398_SW_POWER_DOWN;
ret = ad5398_write_reg(client, data);
@@ -170,10 +171,10 @@ static int ad5398_disable(struct regulator_dev *rdev)
if (ret < 0)
return ret;
- if (!(data & AD5398_CURRENT_EN_MASK))
+ if (data & AD5398_SW_POWER_DOWN)
return 0;
- data &= ~AD5398_CURRENT_EN_MASK;
+ data |= AD5398_SW_POWER_DOWN;
ret = ad5398_write_reg(client, data);
@@ -221,15 +222,20 @@ static int ad5398_probe(struct i2c_client *client)
const struct ad5398_current_data_format *df =
(struct ad5398_current_data_format *)id->driver_data;
- if (!init_data)
- return -EINVAL;
-
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
config.dev = &client->dev;
+ if (client->dev.of_node)
+ init_data = of_get_regulator_init_data(&client->dev,
+ client->dev.of_node,
+ &ad5398_reg);
+ if (!init_data)
+ return -EINVAL;
+
config.init_data = init_data;
+ config.of_node = client->dev.of_node;
config.driver_data = chip;
chip->client = client;
diff --git a/drivers/regulator/adp5055-regulator.c b/drivers/regulator/adp5055-regulator.c
new file mode 100644
index 000000000000..4b004a6b2f84
--- /dev/null
+++ b/drivers/regulator/adp5055-regulator.c
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Regulator driver for Analog Devices ADP5055
+//
+// Copyright (C) 2025 Analog Devices, Inc.
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+// ADP5055 Register Map.
+
+#define ADP5055_CTRL123 0xD1
+#define ADP5055_CTRL_MODE1 0xD3
+#define ADP5055_CTRL_MODE2 0xD4
+#define ADP5055_DLY0 0xD5
+#define ADP5055_DLY1 0xD6
+#define ADP5055_DLY2 0xD7
+#define ADP5055_VID0 0xD8
+#define ADP5055_VID1 0xD9
+#define ADP5055_VID2 0xDA
+#define ADP5055_DVS_LIM0 0xDC
+#define ADP5055_DVS_LIM1 0xDD
+#define ADP5055_DVS_LIM2 0xDE
+#define ADP5055_FT_CFG 0xDF
+#define ADP5055_PG_CFG 0xE0
+
+// ADP5055 Field Masks.
+
+#define ADP5055_MASK_EN_MODE BIT(0)
+#define ADP5055_MASK_OCP_BLANKING BIT(7)
+#define ADP5055_MASK_PSM BIT(4)
+#define ADP5055_MASK_DIS2 BIT(2)
+#define ADP5055_MASK_DIS1 BIT(1)
+#define ADP5055_MASK_DIS0 BIT(0)
+#define ADP5055_MASK_DIS_DLY GENMASK(6, 4)
+#define ADP5055_MASK_EN_DLY GENMASK(2, 0)
+#define ADP5055_MASK_DVS_LIM_UPPER GENMASK(7, 4)
+#define ADP5055_MASK_DVS_LIM_LOWER GENMASK(3, 0)
+#define ADP5055_MASK_FAST_TRANSIENT2 GENMASK(5, 4)
+#define ADP5055_MASK_FAST_TRANSIENT1 GENMASK(3, 2)
+#define ADP5055_MASK_FAST_TRANSIENT0 GENMASK(1, 0)
+#define ADP5055_MASK_DLY_PWRGD BIT(4)
+#define ADP5055_MASK_PWRGD2 BIT(2)
+#define ADP5055_MASK_PWRGD1 BIT(1)
+#define ADP5055_MASK_PWRGD0 BIT(0)
+
+#define ADP5055_MIN_VOUT 408000
+#define ADP5055_NUM_CH 3
+
+struct adp5055 {
+ struct device *dev;
+ struct regmap *regmap;
+ u32 tset;
+ struct gpio_desc *en_gpiod[ADP5055_NUM_CH];
+ bool en_mode_software;
+ int dvs_limit_upper[ADP5055_NUM_CH];
+ int dvs_limit_lower[ADP5055_NUM_CH];
+ u32 fast_transient[ADP5055_NUM_CH];
+ bool mask_power_good[ADP5055_NUM_CH];
+};
+
+static const unsigned int adp5055_tset_vals[] = {
+ 2600,
+ 20800,
+};
+
+static const unsigned int adp5055_enable_delay_vals_2_6[] = {
+ 0,
+ 2600,
+ 5200,
+ 7800,
+ 10400,
+ 13000,
+ 15600,
+ 18200,
+};
+
+static const unsigned int adp5055_enable_delay_vals_20_8[] = {
+ 0,
+ 20800,
+ 41600,
+ 62400,
+ 83200,
+ 104000,
+ 124800,
+ 145600,
+};
+
+static const char * const adp5055_fast_transient_vals[] = {
+ "none",
+ "3G_1.5%",
+ "5G_1.5%",
+ "5G_2.5%",
+};
+
+static int adp5055_get_prop_index(const u32 *table, size_t table_size,
+ u32 value)
+{
+ int i;
+
+ for (i = 0; i < table_size; i++)
+ if (table[i] == value)
+ return i;
+
+ return -EINVAL;
+}
+
+static const struct regmap_range adp5055_reg_ranges[] = {
+ regmap_reg_range(0xD1, 0xE0),
+};
+
+static const struct regmap_access_table adp5055_access_ranges_table = {
+ .yes_ranges = adp5055_reg_ranges,
+ .n_yes_ranges = ARRAY_SIZE(adp5055_reg_ranges),
+};
+
+static const struct regmap_config adp5055_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xE0,
+ .wr_table = &adp5055_access_ranges_table,
+ .rd_table = &adp5055_access_ranges_table,
+};
+
+static const struct linear_range adp5055_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(ADP5055_MIN_VOUT, 0, 255, 1500),
+};
+
+static int adp5055_parse_fw(struct device *dev, struct adp5055 *adp5055)
+{
+ int i, ret;
+ struct regmap *regmap = adp5055->regmap;
+ int val;
+ bool ocp_blanking;
+ bool delay_power_good;
+
+ ret = device_property_read_u32(dev, "adi,tset-us", &adp5055->tset);
+ if (!ret) {
+ ret = adp5055_get_prop_index(adp5055_tset_vals,
+ ARRAY_SIZE(adp5055_tset_vals), adp5055->tset);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to initialize tset.");
+ adp5055->tset = adp5055_tset_vals[ret];
+ }
+
+ ocp_blanking = device_property_read_bool(dev, "adi,ocp-blanking");
+
+ delay_power_good = device_property_read_bool(dev,
+ "adi,delay-power-good");
+
+ for (i = 0; i < ADP5055_NUM_CH; i++) {
+ val = FIELD_PREP(ADP5055_MASK_DVS_LIM_UPPER,
+ DIV_ROUND_CLOSEST_ULL(192000 - adp5055->dvs_limit_upper[i], 12000));
+ val |= FIELD_PREP(ADP5055_MASK_DVS_LIM_LOWER,
+ DIV_ROUND_CLOSEST_ULL(adp5055->dvs_limit_lower[i] + 190500, 12000));
+ ret = regmap_write(regmap, ADP5055_DVS_LIM0 + i, val);
+ if (ret)
+ return ret;
+ }
+
+ val = FIELD_PREP(ADP5055_MASK_EN_MODE, adp5055->en_mode_software);
+ ret = regmap_write(regmap, ADP5055_CTRL_MODE1, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(ADP5055_MASK_OCP_BLANKING, ocp_blanking);
+ ret = regmap_update_bits(regmap, ADP5055_CTRL_MODE2,
+ ADP5055_MASK_OCP_BLANKING, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(ADP5055_MASK_FAST_TRANSIENT2, adp5055->fast_transient[2]);
+ val |= FIELD_PREP(ADP5055_MASK_FAST_TRANSIENT1, adp5055->fast_transient[1]);
+ val |= FIELD_PREP(ADP5055_MASK_FAST_TRANSIENT0, adp5055->fast_transient[0]);
+ ret = regmap_write(regmap, ADP5055_FT_CFG, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(ADP5055_MASK_DLY_PWRGD, delay_power_good);
+ val |= FIELD_PREP(ADP5055_MASK_PWRGD2, adp5055->mask_power_good[2]);
+ val |= FIELD_PREP(ADP5055_MASK_PWRGD1, adp5055->mask_power_good[1]);
+ val |= FIELD_PREP(ADP5055_MASK_PWRGD0, adp5055->mask_power_good[0]);
+ ret = regmap_write(regmap, ADP5055_PG_CFG, val);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int adp5055_of_parse_cb(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct adp5055 *adp5055 = config->driver_data;
+ int id, ret, pval, i;
+
+ id = desc->id;
+
+ if (of_property_read_bool(np, "enable-gpios")) {
+ adp5055->en_gpiod[id] = devm_fwnode_gpiod_get(config->dev,
+ of_fwnode_handle(np), "enable",
+ GPIOD_OUT_LOW, "enable");
+ if (IS_ERR(adp5055->en_gpiod[id]))
+ return dev_err_probe(config->dev, PTR_ERR(adp5055->en_gpiod[id]),
+ "Failed to get enable GPIO\n");
+
+ config->ena_gpiod = adp5055->en_gpiod[id];
+ } else {
+ adp5055->en_mode_software = true;
+ }
+
+ ret = of_property_read_u32(np, "adi,dvs-limit-upper-microvolt", &pval);
+ if (ret)
+ adp5055->dvs_limit_upper[id] = 192000;
+ else
+ adp5055->dvs_limit_upper[id] = pval;
+
+ if (adp5055->dvs_limit_upper[id] > 192000 || adp5055->dvs_limit_upper[id] < 12000)
+ return dev_err_probe(config->dev, adp5055->dvs_limit_upper[id],
+ "Out of range - dvs-limit-upper-microvolt value.");
+
+ ret = of_property_read_u32(np, "adi,dvs-limit-lower-microvolt", &pval);
+ if (ret)
+ adp5055->dvs_limit_lower[id] = -190500;
+ else
+ adp5055->dvs_limit_lower[id] = pval;
+
+ if (adp5055->dvs_limit_lower[id] > -10500 || adp5055->dvs_limit_lower[id] < -190500)
+ return dev_err_probe(config->dev, adp5055->dvs_limit_lower[id],
+ "Out of range - dvs-limit-lower-microvolt value.");
+
+ for (i = 0; i < 4; i++) {
+ ret = of_property_match_string(np, "adi,fast-transient",
+ adp5055_fast_transient_vals[i]);
+ if (!ret)
+ break;
+ }
+
+ if (ret < 0)
+ adp5055->fast_transient[id] = 3;
+ else
+ adp5055->fast_transient[id] = i;
+
+ adp5055->mask_power_good[id] = of_property_read_bool(np, "adi,mask-power-good");
+
+ return 0;
+}
+
+static int adp5055_set_mode(struct regulator_dev *rdev, u32 mode)
+{
+ struct adp5055 *adp5055 = rdev_get_drvdata(rdev);
+ int id, ret;
+
+ id = rdev_get_id(rdev);
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ ret = regmap_update_bits(adp5055->regmap, ADP5055_CTRL_MODE2,
+ ADP5055_MASK_PSM << id, 0);
+ break;
+ case REGULATOR_MODE_IDLE:
+ ret = regmap_update_bits(adp5055->regmap, ADP5055_CTRL_MODE2,
+ ADP5055_MASK_PSM << id, ADP5055_MASK_PSM << id);
+ break;
+ default:
+ return dev_err_probe(&rdev->dev, -EINVAL,
+ "Unsupported mode: %d\n", mode);
+ }
+
+ return ret;
+}
+
+static unsigned int adp5055_get_mode(struct regulator_dev *rdev)
+{
+ struct adp5055 *adp5055 = rdev_get_drvdata(rdev);
+ int id, ret, regval;
+
+ id = rdev_get_id(rdev);
+
+ ret = regmap_read(adp5055->regmap, ADP5055_CTRL_MODE2, &regval);
+ if (ret)
+ return ret;
+
+ if (regval & (ADP5055_MASK_PSM << id))
+ return REGULATOR_MODE_IDLE;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static const struct regulator_ops adp5055_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = adp5055_set_mode,
+ .get_mode = adp5055_get_mode,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
+#define ADP5055_REG_(_name, _id, _ch, _ops) \
+ [_id] = { \
+ .name = _name, \
+ .of_match = of_match_ptr(_name), \
+ .of_parse_cb = adp5055_of_parse_cb, \
+ .id = _id, \
+ .ops = _ops, \
+ .linear_ranges = adp5055_voltage_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(adp5055_voltage_ranges), \
+ .vsel_reg = ADP5055_VID##_ch, \
+ .vsel_mask = GENMASK(7, 0), \
+ .enable_reg = ADP5055_CTRL123, \
+ .enable_mask = BIT(_ch), \
+ .active_discharge_on = ADP5055_MASK_DIS##_id, \
+ .active_discharge_off = 0, \
+ .active_discharge_mask = ADP5055_MASK_DIS##_id, \
+ .active_discharge_reg = ADP5055_CTRL_MODE2, \
+ .ramp_reg = ADP5055_DLY##_ch, \
+ .ramp_mask = ADP5055_MASK_EN_DLY, \
+ .n_ramp_values = ARRAY_SIZE(adp5055_enable_delay_vals_2_6), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }
+
+#define ADP5055_REG(_name, _id, _ch) \
+ ADP5055_REG_(_name, _id, _ch, &adp5055_ops)
+
+static struct regulator_desc adp5055_regulators[] = {
+ ADP5055_REG("buck0", 0, 0),
+ ADP5055_REG("buck1", 1, 1),
+ ADP5055_REG("buck2", 2, 2),
+};
+
+static int adp5055_probe(struct i2c_client *client)
+{
+ struct regulator_init_data *init_data;
+ struct device *dev = &client->dev;
+ struct adp5055 *adp5055;
+ int i, ret;
+
+ init_data = of_get_regulator_init_data(dev, client->dev.of_node,
+ &adp5055_regulators[0]);
+ if (!init_data)
+ return -EINVAL;
+
+ adp5055 = devm_kzalloc(dev, sizeof(struct adp5055), GFP_KERNEL);
+ if (!adp5055)
+ return -ENOMEM;
+
+ adp5055->tset = 2600;
+ adp5055->en_mode_software = false;
+
+ adp5055->regmap = devm_regmap_init_i2c(client, &adp5055_regmap_config);
+ if (IS_ERR(adp5055->regmap))
+ return dev_err_probe(dev, PTR_ERR(adp5055->regmap), "Failed to allocate reg map");
+
+ for (i = 0; i < ADP5055_NUM_CH; i++) {
+ const struct regulator_desc *desc;
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+
+ if (adp5055->tset == 2600)
+ adp5055_regulators[i].ramp_delay_table = adp5055_enable_delay_vals_2_6;
+ else
+ adp5055_regulators[i].ramp_delay_table = adp5055_enable_delay_vals_20_8;
+
+ desc = &adp5055_regulators[i];
+
+ config.dev = dev;
+ config.driver_data = adp5055;
+ config.regmap = adp5055->regmap;
+ config.init_data = init_data;
+
+ rdev = devm_regulator_register(dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "Failed to register %s\n", desc->name);
+ }
+ }
+
+ ret = adp5055_parse_fw(dev, adp5055);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct of_device_id adp5055_of_match[] = {
+ { .compatible = "adi,adp5055", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adp5055_of_match);
+
+static const struct i2c_device_id adp5055_ids[] = {
+ { .name = "adp5055"},
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, adp5055_ids);
+
+static struct i2c_driver adp5055_driver = {
+ .driver = {
+ .name = "adp5055",
+ .of_match_table = adp5055_of_match,
+ },
+ .probe = adp5055_probe,
+ .id_table = adp5055_ids,
+};
+module_i2c_driver(adp5055_driver);
+
+MODULE_DESCRIPTION("ADP5055 Voltage Regulator Driver");
+MODULE_AUTHOR("Alexis Czezar Torreno <alexisczezar.torreno@analog.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index e250e5f3fcbc..be7208bc7409 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -48,7 +48,6 @@ static void arizona_micsupp_check_cp(struct work_struct *work)
struct arizona_micsupp *micsupp =
container_of(work, struct arizona_micsupp, check_cp_work);
struct snd_soc_dapm_context *dapm = *micsupp->dapm;
- struct snd_soc_component *component;
const struct regulator_desc *desc = micsupp->desc;
unsigned int val;
int ret;
@@ -61,14 +60,11 @@ static void arizona_micsupp_check_cp(struct work_struct *work)
}
if (dapm) {
- component = snd_soc_dapm_to_component(dapm);
-
if ((val & (desc->enable_mask | desc->bypass_mask)) ==
desc->enable_mask)
- snd_soc_component_force_enable_pin(component,
- "MICSUPP");
+ snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
else
- snd_soc_component_disable_pin(component, "MICSUPP");
+ snd_soc_dapm_disable_pin(dapm, "MICSUPP");
snd_soc_dapm_sync(dapm);
}
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index e3cc59b82ea6..da891415efc0 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -372,7 +372,7 @@
}
#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask) \
+ _vmask, _ereg, _emask) \
[_family##_##_id] = { \
.name = (_match), \
.supply_name = (_supply), \
@@ -419,8 +419,8 @@
.ops = &axp20x_ops_fixed \
}
-#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \
- _vreg, _vmask, _ereg, _emask) \
+#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \
+ _vreg, _vmask, _ereg, _emask, _ramp_delay) \
[_family##_##_id] = { \
.name = (_match), \
.supply_name = (_supply), \
@@ -436,9 +436,15 @@
.enable_mask = (_emask), \
.linear_ranges = (_ranges), \
.n_linear_ranges = ARRAY_SIZE(_ranges), \
+ .ramp_delay = (_ramp_delay), \
.ops = &axp20x_ops_range, \
}
+#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \
+ _vreg, _vmask, _ereg, _emask) \
+ AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, 0)
+
static const int axp209_dcdc2_ldo3_slew_rates[] = {
1600,
800,
@@ -781,18 +787,18 @@ static const struct linear_range axp717_dcdc3_ranges[] = {
};
static const struct regulator_desc axp717_regulators[] = {
- AXP_DESC_RANGES(AXP717, DCDC1, "dcdc1", "vin1",
+ AXP_DESC_RANGES_DELAY(AXP717, DCDC1, "dcdc1", "vin1",
axp717_dcdc1_ranges, AXP717_DCDC1_NUM_VOLTAGES,
AXP717_DCDC1_CONTROL, AXP717_DCDC_V_OUT_MASK,
- AXP717_DCDC_OUTPUT_CONTROL, BIT(0)),
- AXP_DESC_RANGES(AXP717, DCDC2, "dcdc2", "vin2",
+ AXP717_DCDC_OUTPUT_CONTROL, BIT(0), 640),
+ AXP_DESC_RANGES_DELAY(AXP717, DCDC2, "dcdc2", "vin2",
axp717_dcdc2_ranges, AXP717_DCDC2_NUM_VOLTAGES,
AXP717_DCDC2_CONTROL, AXP717_DCDC_V_OUT_MASK,
- AXP717_DCDC_OUTPUT_CONTROL, BIT(1)),
- AXP_DESC_RANGES(AXP717, DCDC3, "dcdc3", "vin3",
+ AXP717_DCDC_OUTPUT_CONTROL, BIT(1), 640),
+ AXP_DESC_RANGES_DELAY(AXP717, DCDC3, "dcdc3", "vin3",
axp717_dcdc3_ranges, AXP717_DCDC3_NUM_VOLTAGES,
AXP717_DCDC3_CONTROL, AXP717_DCDC_V_OUT_MASK,
- AXP717_DCDC_OUTPUT_CONTROL, BIT(2)),
+ AXP717_DCDC_OUTPUT_CONTROL, BIT(2), 640),
AXP_DESC(AXP717, DCDC4, "dcdc4", "vin4", 1000, 3700, 100,
AXP717_DCDC4_CONTROL, AXP717_DCDC_V_OUT_MASK,
AXP717_DCDC_OUTPUT_CONTROL, BIT(3)),
diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c
index 9f0cda46b015..50414f4cb109 100644
--- a/drivers/regulator/bcm590xx-regulator.c
+++ b/drivers/regulator/bcm590xx-regulator.c
@@ -18,112 +18,236 @@
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
-/* I2C slave 0 registers */
-#define BCM590XX_RFLDOPMCTRL1 0x60
-#define BCM590XX_IOSR1PMCTRL1 0x7a
-#define BCM590XX_IOSR2PMCTRL1 0x7c
-#define BCM590XX_CSRPMCTRL1 0x7e
-#define BCM590XX_SDSR1PMCTRL1 0x82
-#define BCM590XX_SDSR2PMCTRL1 0x86
-#define BCM590XX_MSRPMCTRL1 0x8a
-#define BCM590XX_VSRPMCTRL1 0x8e
-#define BCM590XX_RFLDOCTRL 0x96
-#define BCM590XX_CSRVOUT1 0xc0
-
-/* I2C slave 1 registers */
-#define BCM590XX_GPLDO5PMCTRL1 0x16
-#define BCM590XX_GPLDO6PMCTRL1 0x18
-#define BCM590XX_GPLDO1CTRL 0x1a
-#define BCM590XX_GPLDO2CTRL 0x1b
-#define BCM590XX_GPLDO3CTRL 0x1c
-#define BCM590XX_GPLDO4CTRL 0x1d
-#define BCM590XX_GPLDO5CTRL 0x1e
-#define BCM590XX_GPLDO6CTRL 0x1f
-#define BCM590XX_OTG_CTRL 0x40
-#define BCM590XX_GPLDO1PMCTRL1 0x57
-#define BCM590XX_GPLDO2PMCTRL1 0x59
-#define BCM590XX_GPLDO3PMCTRL1 0x5b
-#define BCM590XX_GPLDO4PMCTRL1 0x5d
-
#define BCM590XX_REG_ENABLE BIT(7)
#define BCM590XX_VBUS_ENABLE BIT(2)
#define BCM590XX_LDO_VSEL_MASK GENMASK(5, 3)
#define BCM590XX_SR_VSEL_MASK GENMASK(5, 0)
+enum bcm590xx_reg_type {
+ BCM590XX_REG_TYPE_LDO,
+ BCM590XX_REG_TYPE_GPLDO,
+ BCM590XX_REG_TYPE_SR,
+ BCM590XX_REG_TYPE_VBUS
+};
+
+struct bcm590xx_reg_data {
+ enum bcm590xx_reg_type type;
+ enum bcm590xx_regmap_type regmap;
+ const struct regulator_desc desc;
+};
+
+struct bcm590xx_reg {
+ struct bcm590xx *mfd;
+ unsigned int n_regulators;
+ const struct bcm590xx_reg_data *regs;
+};
+
+static const struct regulator_ops bcm590xx_ops_ldo = {
+ .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,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+};
+
+/*
+ * LDO ops without voltage selection, used for MICLDO on BCM59054.
+ * (These are currently the same as VBUS ops, but will be different
+ * in the future once full PMMODE support is implemented.)
+ */
+static const struct regulator_ops bcm590xx_ops_ldo_novolt = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+};
+
+static const struct regulator_ops bcm590xx_ops_dcdc = {
+ .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,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+};
+
+static const struct regulator_ops bcm590xx_ops_vbus = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+};
+
+#define BCM590XX_REG_DESC(_model, _name, _name_lower) \
+ .id = _model##_REG_##_name, \
+ .name = #_name_lower, \
+ .of_match = of_match_ptr(#_name_lower), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE \
+
+#define BCM590XX_LDO_DESC(_model, _model_lower, _name, _name_lower, _table) \
+ BCM590XX_REG_DESC(_model, _name, _name_lower), \
+ .ops = &bcm590xx_ops_ldo, \
+ .n_voltages = ARRAY_SIZE(_model_lower##_##_table), \
+ .volt_table = _model_lower##_##_table, \
+ .vsel_reg = _model##_##_name##CTRL, \
+ .vsel_mask = BCM590XX_LDO_VSEL_MASK, \
+ .enable_reg = _model##_##_name##PMCTRL1, \
+ .enable_mask = BCM590XX_REG_ENABLE, \
+ .enable_is_inverted = true
+
+#define BCM590XX_SR_DESC(_model, _model_lower, _name, _name_lower, _ranges) \
+ BCM590XX_REG_DESC(_model, _name, _name_lower), \
+ .ops = &bcm590xx_ops_dcdc, \
+ .n_voltages = 64, \
+ .linear_ranges = _model_lower##_##_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(_model_lower##_##_ranges), \
+ .vsel_reg = _model##_##_name##VOUT1, \
+ .vsel_mask = BCM590XX_SR_VSEL_MASK, \
+ .enable_reg = _model##_##_name##PMCTRL1, \
+ .enable_mask = BCM590XX_REG_ENABLE, \
+ .enable_is_inverted = true
+
+#define BCM59056_REG_DESC(_name, _name_lower) \
+ BCM590XX_REG_DESC(BCM59056, _name, _name_lower)
+#define BCM59056_LDO_DESC(_name, _name_lower, _table) \
+ BCM590XX_LDO_DESC(BCM59056, bcm59056, _name, _name_lower, _table)
+#define BCM59056_SR_DESC(_name, _name_lower, _ranges) \
+ BCM590XX_SR_DESC(BCM59056, bcm59056, _name, _name_lower, _ranges)
+
+#define BCM59054_REG_DESC(_name, _name_lower) \
+ BCM590XX_REG_DESC(BCM59054, _name, _name_lower)
+#define BCM59054_LDO_DESC(_name, _name_lower, _table) \
+ BCM590XX_LDO_DESC(BCM59054, bcm59054, _name, _name_lower, _table)
+#define BCM59054_SR_DESC(_name, _name_lower, _ranges) \
+ BCM590XX_SR_DESC(BCM59054, bcm59054, _name, _name_lower, _ranges)
+
+/* BCM59056 data */
+
+/* I2C slave 0 registers */
+#define BCM59056_RFLDOPMCTRL1 0x60
+#define BCM59056_CAMLDO1PMCTRL1 0x62
+#define BCM59056_CAMLDO2PMCTRL1 0x64
+#define BCM59056_SIMLDO1PMCTRL1 0x66
+#define BCM59056_SIMLDO2PMCTRL1 0x68
+#define BCM59056_SDLDOPMCTRL1 0x6a
+#define BCM59056_SDXLDOPMCTRL1 0x6c
+#define BCM59056_MMCLDO1PMCTRL1 0x6e
+#define BCM59056_MMCLDO2PMCTRL1 0x70
+#define BCM59056_AUDLDOPMCTRL1 0x72
+#define BCM59056_MICLDOPMCTRL1 0x74
+#define BCM59056_USBLDOPMCTRL1 0x76
+#define BCM59056_VIBLDOPMCTRL1 0x78
+#define BCM59056_IOSR1PMCTRL1 0x7a
+#define BCM59056_IOSR2PMCTRL1 0x7c
+#define BCM59056_CSRPMCTRL1 0x7e
+#define BCM59056_SDSR1PMCTRL1 0x82
+#define BCM59056_SDSR2PMCTRL1 0x86
+#define BCM59056_MSRPMCTRL1 0x8a
+#define BCM59056_VSRPMCTRL1 0x8e
+#define BCM59056_RFLDOCTRL 0x96
+#define BCM59056_CAMLDO1CTRL 0x97
+#define BCM59056_CAMLDO2CTRL 0x98
+#define BCM59056_SIMLDO1CTRL 0x99
+#define BCM59056_SIMLDO2CTRL 0x9a
+#define BCM59056_SDLDOCTRL 0x9b
+#define BCM59056_SDXLDOCTRL 0x9c
+#define BCM59056_MMCLDO1CTRL 0x9d
+#define BCM59056_MMCLDO2CTRL 0x9e
+#define BCM59056_AUDLDOCTRL 0x9f
+#define BCM59056_MICLDOCTRL 0xa0
+#define BCM59056_USBLDOCTRL 0xa1
+#define BCM59056_VIBLDOCTRL 0xa2
+#define BCM59056_CSRVOUT1 0xc0
+#define BCM59056_IOSR1VOUT1 0xc3
+#define BCM59056_IOSR2VOUT1 0xc6
+#define BCM59056_MSRVOUT1 0xc9
+#define BCM59056_SDSR1VOUT1 0xcc
+#define BCM59056_SDSR2VOUT1 0xcf
+#define BCM59056_VSRVOUT1 0xd2
+
+/* I2C slave 1 registers */
+#define BCM59056_GPLDO5PMCTRL1 0x16
+#define BCM59056_GPLDO6PMCTRL1 0x18
+#define BCM59056_GPLDO1CTRL 0x1a
+#define BCM59056_GPLDO2CTRL 0x1b
+#define BCM59056_GPLDO3CTRL 0x1c
+#define BCM59056_GPLDO4CTRL 0x1d
+#define BCM59056_GPLDO5CTRL 0x1e
+#define BCM59056_GPLDO6CTRL 0x1f
+#define BCM59056_OTG_CTRL 0x40
+#define BCM59056_GPLDO1PMCTRL1 0x57
+#define BCM59056_GPLDO2PMCTRL1 0x59
+#define BCM59056_GPLDO3PMCTRL1 0x5b
+#define BCM59056_GPLDO4PMCTRL1 0x5d
+
/*
* RFLDO to VSR regulators are
* accessed via I2C slave 0
*/
/* LDO regulator IDs */
-#define BCM590XX_REG_RFLDO 0
-#define BCM590XX_REG_CAMLDO1 1
-#define BCM590XX_REG_CAMLDO2 2
-#define BCM590XX_REG_SIMLDO1 3
-#define BCM590XX_REG_SIMLDO2 4
-#define BCM590XX_REG_SDLDO 5
-#define BCM590XX_REG_SDXLDO 6
-#define BCM590XX_REG_MMCLDO1 7
-#define BCM590XX_REG_MMCLDO2 8
-#define BCM590XX_REG_AUDLDO 9
-#define BCM590XX_REG_MICLDO 10
-#define BCM590XX_REG_USBLDO 11
-#define BCM590XX_REG_VIBLDO 12
+#define BCM59056_REG_RFLDO 0
+#define BCM59056_REG_CAMLDO1 1
+#define BCM59056_REG_CAMLDO2 2
+#define BCM59056_REG_SIMLDO1 3
+#define BCM59056_REG_SIMLDO2 4
+#define BCM59056_REG_SDLDO 5
+#define BCM59056_REG_SDXLDO 6
+#define BCM59056_REG_MMCLDO1 7
+#define BCM59056_REG_MMCLDO2 8
+#define BCM59056_REG_AUDLDO 9
+#define BCM59056_REG_MICLDO 10
+#define BCM59056_REG_USBLDO 11
+#define BCM59056_REG_VIBLDO 12
/* DCDC regulator IDs */
-#define BCM590XX_REG_CSR 13
-#define BCM590XX_REG_IOSR1 14
-#define BCM590XX_REG_IOSR2 15
-#define BCM590XX_REG_MSR 16
-#define BCM590XX_REG_SDSR1 17
-#define BCM590XX_REG_SDSR2 18
-#define BCM590XX_REG_VSR 19
+#define BCM59056_REG_CSR 13
+#define BCM59056_REG_IOSR1 14
+#define BCM59056_REG_IOSR2 15
+#define BCM59056_REG_MSR 16
+#define BCM59056_REG_SDSR1 17
+#define BCM59056_REG_SDSR2 18
+#define BCM59056_REG_VSR 19
/*
* GPLDO1 to VBUS regulators are
* accessed via I2C slave 1
*/
-#define BCM590XX_REG_GPLDO1 20
-#define BCM590XX_REG_GPLDO2 21
-#define BCM590XX_REG_GPLDO3 22
-#define BCM590XX_REG_GPLDO4 23
-#define BCM590XX_REG_GPLDO5 24
-#define BCM590XX_REG_GPLDO6 25
-#define BCM590XX_REG_VBUS 26
+#define BCM59056_REG_GPLDO1 20
+#define BCM59056_REG_GPLDO2 21
+#define BCM59056_REG_GPLDO3 22
+#define BCM59056_REG_GPLDO4 23
+#define BCM59056_REG_GPLDO5 24
+#define BCM59056_REG_GPLDO6 25
+#define BCM59056_REG_VBUS 26
-#define BCM590XX_NUM_REGS 27
-
-#define BCM590XX_REG_IS_LDO(n) (n < BCM590XX_REG_CSR)
-#define BCM590XX_REG_IS_GPLDO(n) \
- ((n > BCM590XX_REG_VSR) && (n < BCM590XX_REG_VBUS))
-#define BCM590XX_REG_IS_VBUS(n) (n == BCM590XX_REG_VBUS)
+#define BCM59056_NUM_REGS 27
/* LDO group A: supported voltages in microvolts */
-static const unsigned int ldo_a_table[] = {
+static const unsigned int bcm59056_ldo_a_table[] = {
1200000, 1800000, 2500000, 2700000, 2800000,
2900000, 3000000, 3300000,
};
/* LDO group C: supported voltages in microvolts */
-static const unsigned int ldo_c_table[] = {
+static const unsigned int bcm59056_ldo_c_table[] = {
3100000, 1800000, 2500000, 2700000, 2800000,
2900000, 3000000, 3300000,
};
-static const unsigned int ldo_vbus[] = {
- 5000000,
-};
-
/* DCDC group CSR: supported voltages in microvolts */
-static const struct linear_range dcdc_csr_ranges[] = {
+static const struct linear_range bcm59056_dcdc_csr_ranges[] = {
REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000),
REGULATOR_LINEAR_RANGE(1360000, 51, 55, 20000),
REGULATOR_LINEAR_RANGE(900000, 56, 63, 0),
};
/* DCDC group IOSR1: supported voltages in microvolts */
-static const struct linear_range dcdc_iosr1_ranges[] = {
+static const struct linear_range bcm59056_dcdc_iosr1_ranges[] = {
REGULATOR_LINEAR_RANGE(860000, 2, 51, 10000),
REGULATOR_LINEAR_RANGE(1500000, 52, 52, 0),
REGULATOR_LINEAR_RANGE(1800000, 53, 53, 0),
@@ -131,155 +255,854 @@ static const struct linear_range dcdc_iosr1_ranges[] = {
};
/* DCDC group SDSR1: supported voltages in microvolts */
-static const struct linear_range dcdc_sdsr1_ranges[] = {
+static const struct linear_range bcm59056_dcdc_sdsr1_ranges[] = {
REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000),
REGULATOR_LINEAR_RANGE(1340000, 51, 51, 0),
REGULATOR_LINEAR_RANGE(900000, 52, 63, 0),
};
-struct bcm590xx_info {
- const char *name;
- const char *vin_name;
- u8 n_voltages;
- const unsigned int *volt_table;
- u8 n_linear_ranges;
- const struct linear_range *linear_ranges;
-};
+static const struct bcm590xx_reg_data bcm59056_regs[BCM59056_NUM_REGS] = {
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(RFLDO, rfldo, ldo_a_table),
+ },
+ },
-#define BCM590XX_REG_TABLE(_name, _table) \
- { \
- .name = #_name, \
- .n_voltages = ARRAY_SIZE(_table), \
- .volt_table = _table, \
- }
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(CAMLDO1, camldo1, ldo_c_table),
+ },
+ },
-#define BCM590XX_REG_RANGES(_name, _ranges) \
- { \
- .name = #_name, \
- .n_voltages = 64, \
- .n_linear_ranges = ARRAY_SIZE(_ranges), \
- .linear_ranges = _ranges, \
- }
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(CAMLDO2, camldo2, ldo_c_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(SIMLDO1, simldo1, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(SIMLDO2, simldo2, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(SDLDO, sdldo, ldo_c_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(SDXLDO, sdxldo, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(MMCLDO1, mmcldo1, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(MMCLDO2, mmcldo2, ldo_a_table),
+ },
+ },
-static struct bcm590xx_info bcm590xx_regs[] = {
- BCM590XX_REG_TABLE(rfldo, ldo_a_table),
- BCM590XX_REG_TABLE(camldo1, ldo_c_table),
- BCM590XX_REG_TABLE(camldo2, ldo_c_table),
- BCM590XX_REG_TABLE(simldo1, ldo_a_table),
- BCM590XX_REG_TABLE(simldo2, ldo_a_table),
- BCM590XX_REG_TABLE(sdldo, ldo_c_table),
- BCM590XX_REG_TABLE(sdxldo, ldo_a_table),
- BCM590XX_REG_TABLE(mmcldo1, ldo_a_table),
- BCM590XX_REG_TABLE(mmcldo2, ldo_a_table),
- BCM590XX_REG_TABLE(audldo, ldo_a_table),
- BCM590XX_REG_TABLE(micldo, ldo_a_table),
- BCM590XX_REG_TABLE(usbldo, ldo_a_table),
- BCM590XX_REG_TABLE(vibldo, ldo_c_table),
- BCM590XX_REG_RANGES(csr, dcdc_csr_ranges),
- BCM590XX_REG_RANGES(iosr1, dcdc_iosr1_ranges),
- BCM590XX_REG_RANGES(iosr2, dcdc_iosr1_ranges),
- BCM590XX_REG_RANGES(msr, dcdc_iosr1_ranges),
- BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges),
- BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges),
- BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges),
- BCM590XX_REG_TABLE(gpldo1, ldo_a_table),
- BCM590XX_REG_TABLE(gpldo2, ldo_a_table),
- BCM590XX_REG_TABLE(gpldo3, ldo_a_table),
- BCM590XX_REG_TABLE(gpldo4, ldo_a_table),
- BCM590XX_REG_TABLE(gpldo5, ldo_a_table),
- BCM590XX_REG_TABLE(gpldo6, ldo_a_table),
- BCM590XX_REG_TABLE(vbus, ldo_vbus),
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(AUDLDO, audldo, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(MICLDO, micldo, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(USBLDO, usbldo, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_LDO_DESC(VIBLDO, vibldo, ldo_c_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_SR_DESC(CSR, csr, dcdc_csr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_SR_DESC(IOSR1, iosr1, dcdc_iosr1_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_SR_DESC(IOSR2, iosr2, dcdc_iosr1_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_SR_DESC(MSR, msr, dcdc_iosr1_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_SR_DESC(SDSR1, sdsr1, dcdc_sdsr1_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_SR_DESC(SDSR2, sdsr2, dcdc_iosr1_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59056_SR_DESC(VSR, vsr, dcdc_iosr1_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59056_LDO_DESC(GPLDO1, gpldo1, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59056_LDO_DESC(GPLDO2, gpldo2, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59056_LDO_DESC(GPLDO3, gpldo3, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59056_LDO_DESC(GPLDO4, gpldo4, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59056_LDO_DESC(GPLDO5, gpldo5, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59056_LDO_DESC(GPLDO6, gpldo6, ldo_a_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_VBUS,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59056_REG_DESC(VBUS, vbus),
+ .ops = &bcm590xx_ops_vbus,
+ .n_voltages = 1,
+ .fixed_uV = 5000000,
+ .enable_reg = BCM59056_OTG_CTRL,
+ .enable_mask = BCM590XX_VBUS_ENABLE,
+ },
+ },
};
-struct bcm590xx_reg {
- struct regulator_desc *desc;
- struct bcm590xx *mfd;
+/* BCM59054 data */
+
+/* I2C slave 0 registers */
+#define BCM59054_RFLDOPMCTRL1 0x60
+#define BCM59054_CAMLDO1PMCTRL1 0x62
+#define BCM59054_CAMLDO2PMCTRL1 0x64
+#define BCM59054_SIMLDO1PMCTRL1 0x66
+#define BCM59054_SIMLDO2PMCTRL1 0x68
+#define BCM59054_SDLDOPMCTRL1 0x6a
+#define BCM59054_SDXLDOPMCTRL1 0x6c
+#define BCM59054_MMCLDO1PMCTRL1 0x6e
+#define BCM59054_MMCLDO2PMCTRL1 0x70
+#define BCM59054_AUDLDOPMCTRL1 0x72
+#define BCM59054_MICLDOPMCTRL1 0x74
+#define BCM59054_USBLDOPMCTRL1 0x76
+#define BCM59054_VIBLDOPMCTRL1 0x78
+#define BCM59054_IOSR1PMCTRL1 0x7a
+#define BCM59054_IOSR2PMCTRL1 0x7c
+#define BCM59054_CSRPMCTRL1 0x7e
+#define BCM59054_SDSR1PMCTRL1 0x82
+#define BCM59054_SDSR2PMCTRL1 0x86
+#define BCM59054_MMSRPMCTRL1 0x8a
+#define BCM59054_VSRPMCTRL1 0x8e
+#define BCM59054_RFLDOCTRL 0x96
+#define BCM59054_CAMLDO1CTRL 0x97
+#define BCM59054_CAMLDO2CTRL 0x98
+#define BCM59054_SIMLDO1CTRL 0x99
+#define BCM59054_SIMLDO2CTRL 0x9a
+#define BCM59054_SDLDOCTRL 0x9b
+#define BCM59054_SDXLDOCTRL 0x9c
+#define BCM59054_MMCLDO1CTRL 0x9d
+#define BCM59054_MMCLDO2CTRL 0x9e
+#define BCM59054_AUDLDOCTRL 0x9f
+#define BCM59054_MICLDOCTRL 0xa0
+#define BCM59054_USBLDOCTRL 0xa1
+#define BCM59054_VIBLDOCTRL 0xa2
+#define BCM59054_CSRVOUT1 0xc0
+#define BCM59054_IOSR1VOUT1 0xc3
+#define BCM59054_IOSR2VOUT1 0xc6
+#define BCM59054_MMSRVOUT1 0xc9
+#define BCM59054_SDSR1VOUT1 0xcc
+#define BCM59054_SDSR2VOUT1 0xcf
+#define BCM59054_VSRVOUT1 0xd2
+
+/* I2C slave 1 registers */
+#define BCM59054_LVLDO1PMCTRL1 0x16
+#define BCM59054_LVLDO2PMCTRL1 0x18
+#define BCM59054_GPLDO1CTRL 0x1a
+#define BCM59054_GPLDO2CTRL 0x1b
+#define BCM59054_GPLDO3CTRL 0x1c
+#define BCM59054_TCXLDOCTRL 0x1d
+#define BCM59054_LVLDO1CTRL 0x1e
+#define BCM59054_LVLDO2CTRL 0x1f
+#define BCM59054_OTG_CTRL 0x40
+#define BCM59054_GPLDO1PMCTRL1 0x57
+#define BCM59054_GPLDO2PMCTRL1 0x59
+#define BCM59054_GPLDO3PMCTRL1 0x5b
+#define BCM59054_TCXLDOPMCTRL1 0x5d
+
+/*
+ * RFLDO to VSR regulators are
+ * accessed via I2C slave 0
+ */
+
+/* LDO regulator IDs */
+#define BCM59054_REG_RFLDO 0
+#define BCM59054_REG_CAMLDO1 1
+#define BCM59054_REG_CAMLDO2 2
+#define BCM59054_REG_SIMLDO1 3
+#define BCM59054_REG_SIMLDO2 4
+#define BCM59054_REG_SDLDO 5
+#define BCM59054_REG_SDXLDO 6
+#define BCM59054_REG_MMCLDO1 7
+#define BCM59054_REG_MMCLDO2 8
+#define BCM59054_REG_AUDLDO 9
+#define BCM59054_REG_MICLDO 10
+#define BCM59054_REG_USBLDO 11
+#define BCM59054_REG_VIBLDO 12
+
+/* DCDC regulator IDs */
+#define BCM59054_REG_CSR 13
+#define BCM59054_REG_IOSR1 14
+#define BCM59054_REG_IOSR2 15
+#define BCM59054_REG_MMSR 16
+#define BCM59054_REG_SDSR1 17
+#define BCM59054_REG_SDSR2 18
+#define BCM59054_REG_VSR 19
+
+/*
+ * GPLDO1 to VBUS regulators are
+ * accessed via I2C slave 1
+ */
+
+#define BCM59054_REG_GPLDO1 20
+#define BCM59054_REG_GPLDO2 21
+#define BCM59054_REG_GPLDO3 22
+#define BCM59054_REG_TCXLDO 23
+#define BCM59054_REG_LVLDO1 24
+#define BCM59054_REG_LVLDO2 25
+#define BCM59054_REG_VBUS 26
+
+#define BCM59054_NUM_REGS 27
+
+/* LDO group 1: supported voltages in microvolts */
+static const unsigned int bcm59054_ldo_1_table[] = {
+ 1200000, 1800000, 2500000, 2700000, 2800000,
+ 2900000, 3000000, 3300000,
};
-static int bcm590xx_get_vsel_register(int id)
-{
- if (BCM590XX_REG_IS_LDO(id))
- return BCM590XX_RFLDOCTRL + id;
- else if (BCM590XX_REG_IS_GPLDO(id))
- return BCM590XX_GPLDO1CTRL + id;
- else
- return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3;
-}
+/* LDO group 2: supported voltages in microvolts */
+static const unsigned int bcm59054_ldo_2_table[] = {
+ 3100000, 1800000, 2500000, 2700000, 2800000,
+ 2900000, 3000000, 3300000,
+};
-static int bcm590xx_get_enable_register(int id)
-{
- int reg = 0;
-
- if (BCM590XX_REG_IS_LDO(id))
- reg = BCM590XX_RFLDOPMCTRL1 + id * 2;
- else if (BCM590XX_REG_IS_GPLDO(id))
- reg = BCM590XX_GPLDO1PMCTRL1 + id * 2;
- else
- switch (id) {
- case BCM590XX_REG_CSR:
- reg = BCM590XX_CSRPMCTRL1;
- break;
- case BCM590XX_REG_IOSR1:
- reg = BCM590XX_IOSR1PMCTRL1;
- break;
- case BCM590XX_REG_IOSR2:
- reg = BCM590XX_IOSR2PMCTRL1;
- break;
- case BCM590XX_REG_MSR:
- reg = BCM590XX_MSRPMCTRL1;
- break;
- case BCM590XX_REG_SDSR1:
- reg = BCM590XX_SDSR1PMCTRL1;
- break;
- case BCM590XX_REG_SDSR2:
- reg = BCM590XX_SDSR2PMCTRL1;
- break;
- case BCM590XX_REG_VSR:
- reg = BCM590XX_VSRPMCTRL1;
- break;
- case BCM590XX_REG_VBUS:
- reg = BCM590XX_OTG_CTRL;
- break;
- }
+/* LDO group 3: supported voltages in microvolts */
+static const unsigned int bcm59054_ldo_3_table[] = {
+ 1000000, 1107000, 1143000, 1214000, 1250000,
+ 1464000, 1500000, 1786000,
+};
+/* DCDC group SR: supported voltages in microvolts */
+static const struct linear_range bcm59054_dcdc_sr_ranges[] = {
+ REGULATOR_LINEAR_RANGE(0, 0, 1, 0),
+ REGULATOR_LINEAR_RANGE(860000, 2, 60, 10000),
+ REGULATOR_LINEAR_RANGE(1500000, 61, 61, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 62, 62, 0),
+ REGULATOR_LINEAR_RANGE(900000, 63, 63, 0),
+};
- return reg;
-}
+/* DCDC group VSR (BCM59054A1): supported voltages in microvolts */
+static const struct linear_range bcm59054_dcdc_vsr_a1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(0, 0, 1, 0),
+ REGULATOR_LINEAR_RANGE(860000, 2, 59, 10000),
+ REGULATOR_LINEAR_RANGE(1700000, 60, 60, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 61, 61, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 62, 62, 0),
+ REGULATOR_LINEAR_RANGE(1600000, 63, 63, 0),
+};
-static const struct regulator_ops bcm590xx_ops_ldo = {
- .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,
- .list_voltage = regulator_list_voltage_table,
- .map_voltage = regulator_map_voltage_iterate,
+/* DCDC group CSR: supported voltages in microvolts */
+static const struct linear_range bcm59054_dcdc_csr_ranges[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0, 1, 100000),
+ REGULATOR_LINEAR_RANGE(860000, 2, 60, 10000),
+ REGULATOR_LINEAR_RANGE(900000, 61, 63, 0),
};
-static const struct regulator_ops bcm590xx_ops_dcdc = {
- .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,
- .list_voltage = regulator_list_voltage_linear_range,
- .map_voltage = regulator_map_voltage_linear_range,
+static const struct bcm590xx_reg_data bcm59054_regs[BCM59054_NUM_REGS] = {
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(RFLDO, rfldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(CAMLDO1, camldo1, ldo_2_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(CAMLDO2, camldo2, ldo_2_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(SIMLDO1, simldo1, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(SIMLDO2, simldo2, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(SDLDO, sdldo, ldo_2_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(SDXLDO, sdxldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(MMCLDO1, mmcldo1, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(MMCLDO2, mmcldo2, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(AUDLDO, audldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_REG_DESC(MICLDO, micldo),
+ .ops = &bcm590xx_ops_ldo_novolt,
+ /* MICLDO is locked at 1.8V */
+ .n_voltages = 1,
+ .fixed_uV = 1800000,
+ .enable_reg = BCM59054_MICLDOPMCTRL1,
+ .enable_mask = BCM590XX_REG_ENABLE,
+ .enable_is_inverted = true,
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(USBLDO, usbldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(VIBLDO, vibldo, ldo_2_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(CSR, csr, dcdc_csr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(IOSR1, iosr1, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(IOSR2, iosr2, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(MMSR, mmsr, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(SDSR1, sdsr1, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(SDSR2, sdsr2, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(VSR, vsr, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(GPLDO1, gpldo1, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(GPLDO2, gpldo2, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(GPLDO3, gpldo3, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(TCXLDO, tcxldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(LVLDO1, lvldo1, ldo_3_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(LVLDO2, lvldo2, ldo_3_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_VBUS,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_REG_DESC(VBUS, vbus),
+ .ops = &bcm590xx_ops_vbus,
+ .n_voltages = 1,
+ .fixed_uV = 5000000,
+ .enable_reg = BCM59054_OTG_CTRL,
+ .enable_mask = BCM590XX_VBUS_ENABLE,
+ },
+ },
};
-static const struct regulator_ops bcm590xx_ops_vbus = {
- .is_enabled = regulator_is_enabled_regmap,
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
+/*
+ * BCM59054A1 regulators; same as previous revision, but with different
+ * VSR voltage table.
+ */
+static const struct bcm590xx_reg_data bcm59054_a1_regs[BCM59054_NUM_REGS] = {
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(RFLDO, rfldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(CAMLDO1, camldo1, ldo_2_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(CAMLDO2, camldo2, ldo_2_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(SIMLDO1, simldo1, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(SIMLDO2, simldo2, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(SDLDO, sdldo, ldo_2_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(SDXLDO, sdxldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(MMCLDO1, mmcldo1, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(MMCLDO2, mmcldo2, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(AUDLDO, audldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_REG_DESC(MICLDO, micldo),
+ .ops = &bcm590xx_ops_ldo_novolt,
+ /* MICLDO is locked at 1.8V */
+ .n_voltages = 1,
+ .fixed_uV = 1800000,
+ .enable_reg = BCM59054_MICLDOPMCTRL1,
+ .enable_mask = BCM590XX_REG_ENABLE,
+ .enable_is_inverted = true,
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(USBLDO, usbldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_LDO,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_LDO_DESC(VIBLDO, vibldo, ldo_2_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(CSR, csr, dcdc_csr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(IOSR1, iosr1, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(IOSR2, iosr2, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(MMSR, mmsr, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(SDSR1, sdsr1, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(SDSR2, sdsr2, dcdc_sr_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_SR,
+ .regmap = BCM590XX_REGMAP_PRI,
+ .desc = {
+ BCM59054_SR_DESC(VSR, vsr, dcdc_vsr_a1_ranges),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(GPLDO1, gpldo1, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(GPLDO2, gpldo2, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(GPLDO3, gpldo3, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(TCXLDO, tcxldo, ldo_1_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(LVLDO1, lvldo1, ldo_3_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_GPLDO,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_LDO_DESC(LVLDO2, lvldo2, ldo_3_table),
+ },
+ },
+
+ {
+ .type = BCM590XX_REG_TYPE_VBUS,
+ .regmap = BCM590XX_REGMAP_SEC,
+ .desc = {
+ BCM59054_REG_DESC(VBUS, vbus),
+ .ops = &bcm590xx_ops_vbus,
+ .n_voltages = 1,
+ .fixed_uV = 5000000,
+ .enable_reg = BCM59054_OTG_CTRL,
+ .enable_mask = BCM590XX_VBUS_ENABLE,
+ },
+ },
};
static int bcm590xx_probe(struct platform_device *pdev)
{
struct bcm590xx *bcm590xx = dev_get_drvdata(pdev->dev.parent);
struct bcm590xx_reg *pmu;
+ const struct bcm590xx_reg_data *info;
struct regulator_config config = { };
- struct bcm590xx_info *info;
struct regulator_dev *rdev;
- int i;
+ unsigned int i;
pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
if (!pmu)
@@ -287,65 +1110,53 @@ static int bcm590xx_probe(struct platform_device *pdev)
pmu->mfd = bcm590xx;
- platform_set_drvdata(pdev, pmu);
-
- pmu->desc = devm_kcalloc(&pdev->dev,
- BCM590XX_NUM_REGS,
- sizeof(struct regulator_desc),
- GFP_KERNEL);
- if (!pmu->desc)
- return -ENOMEM;
+ switch (pmu->mfd->pmu_id) {
+ case BCM590XX_PMUID_BCM59054:
+ pmu->n_regulators = BCM59054_NUM_REGS;
+ if (pmu->mfd->rev_analog == BCM59054_REV_ANALOG_A1)
+ pmu->regs = bcm59054_a1_regs;
+ else
+ pmu->regs = bcm59054_regs;
+ break;
+ case BCM590XX_PMUID_BCM59056:
+ pmu->n_regulators = BCM59056_NUM_REGS;
+ pmu->regs = bcm59056_regs;
+ break;
+ default:
+ dev_err(bcm590xx->dev,
+ "unknown device type, could not initialize\n");
+ return -EINVAL;
+ }
- info = bcm590xx_regs;
-
- for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) {
- /* Register the regulators */
- pmu->desc[i].name = info->name;
- pmu->desc[i].of_match = of_match_ptr(info->name);
- pmu->desc[i].regulators_node = of_match_ptr("regulators");
- pmu->desc[i].supply_name = info->vin_name;
- pmu->desc[i].id = i;
- pmu->desc[i].volt_table = info->volt_table;
- pmu->desc[i].n_voltages = info->n_voltages;
- pmu->desc[i].linear_ranges = info->linear_ranges;
- pmu->desc[i].n_linear_ranges = info->n_linear_ranges;
-
- if ((BCM590XX_REG_IS_LDO(i)) || (BCM590XX_REG_IS_GPLDO(i))) {
- pmu->desc[i].ops = &bcm590xx_ops_ldo;
- pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK;
- } else if (BCM590XX_REG_IS_VBUS(i))
- pmu->desc[i].ops = &bcm590xx_ops_vbus;
- else {
- pmu->desc[i].ops = &bcm590xx_ops_dcdc;
- pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK;
- }
+ platform_set_drvdata(pdev, pmu);
- if (BCM590XX_REG_IS_VBUS(i))
- pmu->desc[i].enable_mask = BCM590XX_VBUS_ENABLE;
- else {
- pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i);
- pmu->desc[i].enable_is_inverted = true;
- pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE;
- }
- pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i);
- pmu->desc[i].type = REGULATOR_VOLTAGE;
- pmu->desc[i].owner = THIS_MODULE;
+ /* Register the regulators */
+ for (i = 0; i < pmu->n_regulators; i++) {
+ info = &pmu->regs[i];
config.dev = bcm590xx->dev;
config.driver_data = pmu;
- if (BCM590XX_REG_IS_GPLDO(i) || BCM590XX_REG_IS_VBUS(i))
- config.regmap = bcm590xx->regmap_sec;
- else
- config.regmap = bcm590xx->regmap_pri;
- rdev = devm_regulator_register(&pdev->dev, &pmu->desc[i],
- &config);
- if (IS_ERR(rdev)) {
+ switch (info->regmap) {
+ case BCM590XX_REGMAP_PRI:
+ config.regmap = bcm590xx->regmap_pri;
+ break;
+ case BCM590XX_REGMAP_SEC:
+ config.regmap = bcm590xx->regmap_sec;
+ break;
+ default:
dev_err(bcm590xx->dev,
- "failed to register %s regulator\n",
+ "invalid regmap for %s regulator; this is a driver bug\n",
pdev->name);
- return PTR_ERR(rdev);
+ return -EINVAL;
}
+
+ rdev = devm_regulator_register(&pdev->dev, &info->desc,
+ &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(bcm590xx->dev, PTR_ERR(rdev),
+ "failed to register %s regulator\n",
+ pdev->name);
}
return 0;
diff --git a/drivers/regulator/bd71815-regulator.c b/drivers/regulator/bd71815-regulator.c
index 79fbb45297f6..8da57a7bb2f1 100644
--- a/drivers/regulator/bd71815-regulator.c
+++ b/drivers/regulator/bd71815-regulator.c
@@ -173,9 +173,9 @@ static int set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
- struct bd71815_regulator *data;
+ const struct bd71815_regulator *data;
- data = container_of(desc, struct bd71815_regulator, desc);
+ data = container_of_const(desc, struct bd71815_regulator, desc);
return rohm_regulator_set_dvs_levels(data->dvs, np, desc, cfg->regmap);
}
@@ -195,10 +195,10 @@ static int buck12_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
- struct bd71815_regulator *data;
+ const struct bd71815_regulator *data;
int ret = 0, val;
- data = container_of(desc, struct bd71815_regulator, desc);
+ data = container_of_const(desc, struct bd71815_regulator, desc);
if (of_property_present(np, "rohm,dvs-run-voltage") ||
of_property_present(np, "rohm,dvs-suspend-voltage") ||
diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c
index dd871ffe979c..87de87793fa1 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -95,9 +95,9 @@ 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;
+ const struct bd71828_regulator_data *data;
- data = container_of(desc, struct bd71828_regulator_data, desc);
+ data = container_of_const(desc, struct bd71828_regulator_data, desc);
return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap);
}
diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
index 1bb048de3ecd..1b5997c8482e 100644
--- a/drivers/regulator/bd718x7-regulator.c
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -134,9 +134,19 @@ static void voltage_change_done(struct regulator_dev *rdev, unsigned int sel,
if (*mask) {
/*
- * Let's allow scheduling as we use I2C anyways. We just need to
- * guarantee minimum of 1ms sleep - it shouldn't matter if we
- * exceed it due to the scheduling.
+ * We had fault detection disabled for the duration of the
+ * voltage change.
+ *
+ * According to HW colleagues the maximum time it takes is
+ * 1000us. I assume that on systems with light load this
+ * might be less - and we could probably use DT to give
+ * system specific delay value if performance matters.
+ *
+ * Well, knowing we use I2C here and can add scheduling delays
+ * I don't think it is worth the hassle and I just add fixed
+ * 1ms sleep here (and allow scheduling). If this turns out to
+ * be a problem we can change it to delay and make the delay
+ * time configurable.
*/
msleep(1);
@@ -173,16 +183,7 @@ static int voltage_change_prepare(struct regulator_dev *rdev, unsigned int sel,
/*
* If we increase LDO voltage when LDO is enabled we need to
* disable the power-good detection until voltage has reached
- * the new level. According to HW colleagues the maximum time
- * it takes is 1000us. I assume that on systems with light load
- * this might be less - and we could probably use DT to give
- * system specific delay value if performance matters.
- *
- * Well, knowing we use I2C here and can add scheduling delays
- * I don't think it is worth the hassle and I just add fixed
- * 1ms sleep here (and allow scheduling). If this turns out to
- * be a problem we can change it to delay and make the delay
- * time configurable.
+ * the new level.
*/
if (new > now) {
int tmp;
@@ -697,9 +698,9 @@ static int buck_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
- struct bd718xx_regulator_data *data;
+ const struct bd718xx_regulator_data *data;
- data = container_of(desc, struct bd718xx_regulator_data, desc);
+ data = container_of_const(desc, struct bd718xx_regulator_data, desc);
return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap);
}
@@ -1597,7 +1598,7 @@ static int setup_feedback_loop(struct device *dev, struct device_node *np,
if (desc->n_linear_ranges && desc->linear_ranges) {
struct linear_range *new;
- new = devm_kzalloc(dev, desc->n_linear_ranges *
+ new = devm_kcalloc(dev, desc->n_linear_ranges,
sizeof(struct linear_range),
GFP_KERNEL);
if (!new)
@@ -1612,6 +1613,8 @@ static int setup_feedback_loop(struct device *dev, struct device_node *np,
step /= r1;
new[j].min = min;
+ new[j].min_sel = desc->linear_ranges[j].min_sel;
+ new[j].max_sel = desc->linear_ranges[j].max_sel;
new[j].step = step;
dev_dbg(dev, "%s: old range min %d, step %d\n",
diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c
index 9876cc05867e..129b20c33bad 100644
--- a/drivers/regulator/bd96801-regulator.c
+++ b/drivers/regulator/bd96801-regulator.c
@@ -5,12 +5,7 @@
/*
* This version of the "BD86801 scalable PMIC"'s driver supports only very
* basic set of the PMIC features. Most notably, there is no support for
- * the ERRB interrupt and the configurations which should be done when the
- * PMIC is in STBY mode.
- *
- * Supporting the ERRB interrupt would require dropping the regmap-IRQ
- * usage or working around (or accepting a presense of) a naming conflict
- * in debugFS IRQs.
+ * the configurations which should be done when the PMIC is in STBY mode.
*
* Being able to reliably do the configurations like changing the
* regulator safety limits (like limits for the over/under -voltages, over
@@ -22,16 +17,14 @@
* be the need to configure these safety limits. Hence it's not simple to
* come up with a generic solution.
*
- * Users who require the ERRB handling and STBY state configurations can
- * have a look at the original RFC:
+ * Users who require the STBY state configurations can have a look at the
+ * original RFC:
* https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/
- * which implements a workaround to debugFS naming conflict and some of
- * the safety limit configurations - but leaves the state change handling
- * and synchronization to be implemented.
+ * which implements some of the safety limit configurations - but leaves the
+ * state change handling and synchronization to be implemented.
*
* It would be great to hear (and receive a patch!) if you implement the
- * STBY configuration support or a proper fix to the debugFS naming
- * conflict in your downstream driver ;)
+ * STBY configuration support in your downstream driver ;)
*/
#include <linux/cleanup.h>
@@ -90,6 +83,7 @@ enum {
#define BD96801_LDO6_VSEL_REG 0x26
#define BD96801_LDO7_VSEL_REG 0x27
#define BD96801_BUCK_VSEL_MASK 0x1F
+#define BD96805_BUCK_VSEL_MASK 0x3f
#define BD96801_LDO_VSEL_MASK 0xff
#define BD96801_MASK_RAMP_DELAY 0xc0
@@ -97,6 +91,7 @@ enum {
#define BD96801_BUCK_INT_VOUT_MASK 0xff
#define BD96801_BUCK_VOLTS 256
+#define BD96805_BUCK_VOLTS 64
#define BD96801_LDO_VOLTS 256
#define BD96801_OVP_MASK 0x03
@@ -167,6 +162,30 @@ static const struct linear_range bd96801_buck_init_volts[] = {
REGULATOR_LINEAR_RANGE(3300000 - 150000, 0xed, 0xff, 0),
};
+/* BD96802 uses same voltage ranges for bucks as BD96801 */
+#define bd96802_tune_volts bd96801_tune_volts
+#define bd96802_buck_init_volts bd96801_buck_init_volts
+
+/*
+ * On BD96805 we have similar "negative tuning range" as on BD96801, except
+ * that the max tuning is -310 ... +310 mV (instead of the 150mV). We use same
+ * approach as with the BD96801 ranges.
+ */
+static const struct linear_range bd96805_tune_volts[] = {
+ REGULATOR_LINEAR_RANGE(310000, 0x00, 0x1F, 10000),
+ REGULATOR_LINEAR_RANGE(0, 0x20, 0x3F, 10000),
+};
+
+static const struct linear_range bd96805_buck_init_volts[] = {
+ REGULATOR_LINEAR_RANGE(500000 - 310000, 0x00, 0xc8, 5000),
+ REGULATOR_LINEAR_RANGE(1550000 - 310000, 0xc9, 0xec, 50000),
+ REGULATOR_LINEAR_RANGE(3300000 - 310000, 0xed, 0xff, 0),
+};
+
+/* BD96806 uses same voltage ranges for bucks as BD96805 */
+#define bd96806_tune_volts bd96805_tune_volts
+#define bd96806_buck_init_volts bd96805_buck_init_volts
+
static const struct linear_range bd96801_ldo_int_volts[] = {
REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000),
REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0),
@@ -205,89 +224,89 @@ struct bd96801_irqinfo {
static const struct bd96801_irqinfo buck1_irqinfo[] = {
BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-h", 500,
- "bd96801-buck1-overcurr-h"),
+ "buck1-overcurr-h"),
BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-l", 500,
- "bd96801-buck1-overcurr-l"),
+ "buck1-overcurr-l"),
BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-n", 500,
- "bd96801-buck1-overcurr-n"),
+ "buck1-overcurr-n"),
BD96801_IRQINFO(BD96801_PROT_OVP, "buck1-over-voltage", 500,
- "bd96801-buck1-overvolt"),
+ "buck1-overvolt"),
BD96801_IRQINFO(BD96801_PROT_UVP, "buck1-under-voltage", 500,
- "bd96801-buck1-undervolt"),
+ "buck1-undervolt"),
BD96801_IRQINFO(BD96801_PROT_TEMP, "buck1-over-temp", 500,
- "bd96801-buck1-thermal")
+ "buck1-thermal")
};
static const struct bd96801_irqinfo buck2_irqinfo[] = {
BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-h", 500,
- "bd96801-buck2-overcurr-h"),
+ "buck2-overcurr-h"),
BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-l", 500,
- "bd96801-buck2-overcurr-l"),
+ "buck2-overcurr-l"),
BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-n", 500,
- "bd96801-buck2-overcurr-n"),
+ "buck2-overcurr-n"),
BD96801_IRQINFO(BD96801_PROT_OVP, "buck2-over-voltage", 500,
- "bd96801-buck2-overvolt"),
+ "buck2-overvolt"),
BD96801_IRQINFO(BD96801_PROT_UVP, "buck2-under-voltage", 500,
- "bd96801-buck2-undervolt"),
+ "buck2-undervolt"),
BD96801_IRQINFO(BD96801_PROT_TEMP, "buck2-over-temp", 500,
- "bd96801-buck2-thermal")
+ "buck2-thermal")
};
static const struct bd96801_irqinfo buck3_irqinfo[] = {
BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-h", 500,
- "bd96801-buck3-overcurr-h"),
+ "buck3-overcurr-h"),
BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-l", 500,
- "bd96801-buck3-overcurr-l"),
+ "buck3-overcurr-l"),
BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-n", 500,
- "bd96801-buck3-overcurr-n"),
+ "buck3-overcurr-n"),
BD96801_IRQINFO(BD96801_PROT_OVP, "buck3-over-voltage", 500,
- "bd96801-buck3-overvolt"),
+ "buck3-overvolt"),
BD96801_IRQINFO(BD96801_PROT_UVP, "buck3-under-voltage", 500,
- "bd96801-buck3-undervolt"),
+ "buck3-undervolt"),
BD96801_IRQINFO(BD96801_PROT_TEMP, "buck3-over-temp", 500,
- "bd96801-buck3-thermal")
+ "buck3-thermal")
};
static const struct bd96801_irqinfo buck4_irqinfo[] = {
BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-h", 500,
- "bd96801-buck4-overcurr-h"),
+ "buck4-overcurr-h"),
BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-l", 500,
- "bd96801-buck4-overcurr-l"),
+ "buck4-overcurr-l"),
BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-n", 500,
- "bd96801-buck4-overcurr-n"),
+ "buck4-overcurr-n"),
BD96801_IRQINFO(BD96801_PROT_OVP, "buck4-over-voltage", 500,
- "bd96801-buck4-overvolt"),
+ "buck4-overvolt"),
BD96801_IRQINFO(BD96801_PROT_UVP, "buck4-under-voltage", 500,
- "bd96801-buck4-undervolt"),
+ "buck4-undervolt"),
BD96801_IRQINFO(BD96801_PROT_TEMP, "buck4-over-temp", 500,
- "bd96801-buck4-thermal")
+ "buck4-thermal")
};
static const struct bd96801_irqinfo ldo5_irqinfo[] = {
BD96801_IRQINFO(BD96801_PROT_OCP, "ldo5-overcurr", 500,
- "bd96801-ldo5-overcurr"),
+ "ldo5-overcurr"),
BD96801_IRQINFO(BD96801_PROT_OVP, "ldo5-over-voltage", 500,
- "bd96801-ldo5-overvolt"),
+ "ldo5-overvolt"),
BD96801_IRQINFO(BD96801_PROT_UVP, "ldo5-under-voltage", 500,
- "bd96801-ldo5-undervolt"),
+ "ldo5-undervolt"),
};
static const struct bd96801_irqinfo ldo6_irqinfo[] = {
BD96801_IRQINFO(BD96801_PROT_OCP, "ldo6-overcurr", 500,
- "bd96801-ldo6-overcurr"),
+ "ldo6-overcurr"),
BD96801_IRQINFO(BD96801_PROT_OVP, "ldo6-over-voltage", 500,
- "bd96801-ldo6-overvolt"),
+ "ldo6-overvolt"),
BD96801_IRQINFO(BD96801_PROT_UVP, "ldo6-under-voltage", 500,
- "bd96801-ldo6-undervolt"),
+ "ldo6-undervolt"),
};
static const struct bd96801_irqinfo ldo7_irqinfo[] = {
BD96801_IRQINFO(BD96801_PROT_OCP, "ldo7-overcurr", 500,
- "bd96801-ldo7-overcurr"),
+ "ldo7-overcurr"),
BD96801_IRQINFO(BD96801_PROT_OVP, "ldo7-over-voltage", 500,
- "bd96801-ldo7-overvolt"),
+ "ldo7-overvolt"),
BD96801_IRQINFO(BD96801_PROT_UVP, "ldo7-under-voltage", 500,
- "bd96801-ldo7-undervolt"),
+ "ldo7-undervolt"),
};
struct bd96801_irq_desc {
@@ -309,6 +328,7 @@ struct bd96801_pmic_data {
struct bd96801_regulator_data regulator_data[BD96801_NUM_REGULATORS];
struct regmap *regmap;
int fatal_ind;
+ int num_regulators;
};
static int ldo_map_notif(int irq, struct regulator_irq_data *rid,
@@ -317,12 +337,12 @@ static int ldo_map_notif(int irq, struct regulator_irq_data *rid,
int i;
for (i = 0; i < rid->num_states; i++) {
- struct bd96801_regulator_data *rdata;
+ const struct bd96801_regulator_data *rdata;
struct regulator_dev *rdev;
rdev = rid->states[i].rdev;
- rdata = container_of(rdev->desc, struct bd96801_regulator_data,
- desc);
+ rdata = container_of_const(rdev->desc, struct bd96801_regulator_data,
+ desc);
rid->states[i].notifs = regulator_err2notif(rdata->ldo_errs);
rid->states[i].errors = rdata->ldo_errs;
*dev_mask |= BIT(i);
@@ -334,9 +354,9 @@ static int bd96801_list_voltage_lr(struct regulator_dev *rdev,
unsigned int selector)
{
int voltage;
- struct bd96801_regulator_data *data;
+ const struct bd96801_regulator_data *data;
- data = container_of(rdev->desc, struct bd96801_regulator_data, desc);
+ data = container_of_const(rdev->desc, struct bd96801_regulator_data, desc);
/*
* The BD096801 has voltage setting in two registers. One giving the
@@ -510,6 +530,70 @@ static int bd96801_walk_regulator_dt(struct device *dev, struct regmap *regmap,
* case later. What we can easly do for preparing is to not use static global
* data for regulators though.
*/
+static const struct bd96801_pmic_data bd96802_data = {
+ .regulator_data = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("buck1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_BUCK1,
+ .ops = &bd96801_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96802_tune_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96802_tune_volts),
+ .n_voltages = BD96801_BUCK_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_BUCK1_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_BUCK1_VSEL_REG,
+ .vsel_mask = BD96801_BUCK_VSEL_MASK,
+ .ramp_reg = BD96801_BUCK1_VSEL_REG,
+ .ramp_mask = BD96801_MASK_RAMP_DELAY,
+ .ramp_delay_table = &buck_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .init_ranges = bd96802_buck_init_volts,
+ .num_ranges = ARRAY_SIZE(bd96802_buck_init_volts),
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(buck1_irqinfo),
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("buck2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_BUCK2,
+ .ops = &bd96801_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96802_tune_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96802_tune_volts),
+ .n_voltages = BD96801_BUCK_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_BUCK2_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_BUCK2_VSEL_REG,
+ .vsel_mask = BD96801_BUCK_VSEL_MASK,
+ .ramp_reg = BD96801_BUCK2_VSEL_REG,
+ .ramp_mask = BD96801_MASK_RAMP_DELAY,
+ .ramp_delay_table = &buck_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(buck2_irqinfo),
+ },
+ .init_ranges = bd96802_buck_init_volts,
+ .num_ranges = ARRAY_SIZE(bd96802_buck_init_volts),
+ },
+ },
+ .num_regulators = 2,
+};
+
static const struct bd96801_pmic_data bd96801_data = {
.regulator_data = {
{
@@ -695,11 +779,265 @@ static const struct bd96801_pmic_data bd96801_data = {
.ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG,
},
},
+ .num_regulators = 7,
+};
+
+static const struct bd96801_pmic_data bd96805_data = {
+ .regulator_data = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("buck1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_BUCK1,
+ .ops = &bd96801_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96805_tune_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96805_tune_volts),
+ .n_voltages = BD96805_BUCK_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_BUCK1_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_BUCK1_VSEL_REG,
+ .vsel_mask = BD96805_BUCK_VSEL_MASK,
+ .ramp_reg = BD96801_BUCK1_VSEL_REG,
+ .ramp_mask = BD96801_MASK_RAMP_DELAY,
+ .ramp_delay_table = &buck_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .init_ranges = bd96805_buck_init_volts,
+ .num_ranges = ARRAY_SIZE(bd96805_buck_init_volts),
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(buck1_irqinfo),
+ },
+ }, {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("buck2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_BUCK2,
+ .ops = &bd96801_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96805_tune_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96805_tune_volts),
+ .n_voltages = BD96805_BUCK_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_BUCK2_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_BUCK2_VSEL_REG,
+ .vsel_mask = BD96805_BUCK_VSEL_MASK,
+ .ramp_reg = BD96801_BUCK2_VSEL_REG,
+ .ramp_mask = BD96801_MASK_RAMP_DELAY,
+ .ramp_delay_table = &buck_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(buck2_irqinfo),
+ },
+ .init_ranges = bd96805_buck_init_volts,
+ .num_ranges = ARRAY_SIZE(bd96805_buck_init_volts),
+ }, {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("buck3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_BUCK3,
+ .ops = &bd96801_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96805_tune_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96805_tune_volts),
+ .n_voltages = BD96805_BUCK_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_BUCK3_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_BUCK3_VSEL_REG,
+ .vsel_mask = BD96805_BUCK_VSEL_MASK,
+ .ramp_reg = BD96801_BUCK3_VSEL_REG,
+ .ramp_mask = BD96801_MASK_RAMP_DELAY,
+ .ramp_delay_table = &buck_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&buck3_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(buck3_irqinfo),
+ },
+ .init_ranges = bd96805_buck_init_volts,
+ .num_ranges = ARRAY_SIZE(bd96805_buck_init_volts),
+ }, {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("buck4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_BUCK4,
+ .ops = &bd96801_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96805_tune_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96805_tune_volts),
+ .n_voltages = BD96805_BUCK_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_BUCK4_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_BUCK4_VSEL_REG,
+ .vsel_mask = BD96805_BUCK_VSEL_MASK,
+ .ramp_reg = BD96801_BUCK4_VSEL_REG,
+ .ramp_mask = BD96801_MASK_RAMP_DELAY,
+ .ramp_delay_table = &buck_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&buck4_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(buck4_irqinfo),
+ },
+ .init_ranges = bd96805_buck_init_volts,
+ .num_ranges = ARRAY_SIZE(bd96805_buck_init_volts),
+ }, {
+ .desc = {
+ .name = "ldo5",
+ .of_match = of_match_ptr("ldo5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_LDO5,
+ .ops = &bd96801_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96801_ldo_int_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts),
+ .n_voltages = BD96801_LDO_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_LDO5_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_LDO5_VSEL_REG,
+ .vsel_mask = BD96801_LDO_VSEL_MASK,
+ .owner = THIS_MODULE,
+ },
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&ldo5_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(ldo5_irqinfo),
+ },
+ .ldo_vol_lvl = BD96801_LDO5_VOL_LVL_REG,
+ }, {
+ .desc = {
+ .name = "ldo6",
+ .of_match = of_match_ptr("ldo6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_LDO6,
+ .ops = &bd96801_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96801_ldo_int_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts),
+ .n_voltages = BD96801_LDO_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_LDO6_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_LDO6_VSEL_REG,
+ .vsel_mask = BD96801_LDO_VSEL_MASK,
+ .owner = THIS_MODULE,
+ },
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&ldo6_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(ldo6_irqinfo),
+ },
+ .ldo_vol_lvl = BD96801_LDO6_VOL_LVL_REG,
+ }, {
+ .desc = {
+ .name = "ldo7",
+ .of_match = of_match_ptr("ldo7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_LDO7,
+ .ops = &bd96801_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96801_ldo_int_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts),
+ .n_voltages = BD96801_LDO_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_LDO7_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_LDO7_VSEL_REG,
+ .vsel_mask = BD96801_LDO_VSEL_MASK,
+ .owner = THIS_MODULE,
+ },
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&ldo7_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(ldo7_irqinfo),
+ },
+ .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG,
+ },
+ },
+ .num_regulators = 7,
};
-static int initialize_pmic_data(struct device *dev,
+static const struct bd96801_pmic_data bd96806_data = {
+ .regulator_data = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("buck1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_BUCK1,
+ .ops = &bd96801_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96806_tune_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96806_tune_volts),
+ .n_voltages = BD96805_BUCK_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_BUCK1_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_BUCK1_VSEL_REG,
+ .vsel_mask = BD96805_BUCK_VSEL_MASK,
+ .ramp_reg = BD96801_BUCK1_VSEL_REG,
+ .ramp_mask = BD96801_MASK_RAMP_DELAY,
+ .ramp_delay_table = &buck_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .init_ranges = bd96806_buck_init_volts,
+ .num_ranges = ARRAY_SIZE(bd96806_buck_init_volts),
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(buck1_irqinfo),
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("buck2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD96801_BUCK2,
+ .ops = &bd96801_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .linear_ranges = bd96806_tune_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd96806_tune_volts),
+ .n_voltages = BD96805_BUCK_VOLTS,
+ .enable_reg = BD96801_REG_ENABLE,
+ .enable_mask = BD96801_BUCK2_EN_MASK,
+ .enable_is_inverted = true,
+ .vsel_reg = BD96801_BUCK2_VSEL_REG,
+ .vsel_mask = BD96805_BUCK_VSEL_MASK,
+ .ramp_reg = BD96801_BUCK2_VSEL_REG,
+ .ramp_mask = BD96801_MASK_RAMP_DELAY,
+ .ramp_delay_table = &buck_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .irq_desc = {
+ .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0],
+ .num_irqs = ARRAY_SIZE(buck2_irqinfo),
+ },
+ .init_ranges = bd96806_buck_init_volts,
+ .num_ranges = ARRAY_SIZE(bd96806_buck_init_volts),
+ },
+ },
+ .num_regulators = 2,
+};
+
+static int initialize_pmic_data(struct platform_device *pdev,
struct bd96801_pmic_data *pdata)
{
+ struct device *dev = &pdev->dev;
int r, i;
/*
@@ -707,7 +1045,7 @@ static int initialize_pmic_data(struct device *dev,
* wish to modify IRQ information independently for each driver
* instance.
*/
- for (r = 0; r < BD96801_NUM_REGULATORS; r++) {
+ for (r = 0; r < pdata->num_regulators; r++) {
const struct bd96801_irqinfo *template;
struct bd96801_irqinfo *new;
int num_infos;
@@ -728,6 +1066,92 @@ static int initialize_pmic_data(struct device *dev,
return 0;
}
+static int bd96801_map_event_all(int irq, struct regulator_irq_data *rid,
+ unsigned long *dev_mask)
+{
+ int i;
+
+ for (i = 0; i < rid->num_states; i++) {
+ rid->states[i].notifs = REGULATOR_EVENT_FAIL;
+ rid->states[i].errors = REGULATOR_ERROR_FAIL;
+ *dev_mask |= BIT(i);
+ }
+
+ return 0;
+}
+
+static int bd96801_rdev_errb_irqs(struct platform_device *pdev,
+ struct regulator_dev *rdev)
+{
+ int i;
+ void *retp;
+ static const char * const single_out_errb_irqs[] = {
+ "%s-pvin-err", "%s-ovp-err", "%s-uvp-err", "%s-shdn-err",
+ };
+
+ for (i = 0; i < ARRAY_SIZE(single_out_errb_irqs); i++) {
+ struct regulator_irq_desc id = {
+ .map_event = bd96801_map_event_all,
+ .irq_off_ms = 1000,
+ };
+ struct regulator_dev *rdev_arr[1];
+ char tmp[255];
+ int irq;
+
+ snprintf(tmp, 255, single_out_errb_irqs[i], rdev->desc->name);
+ tmp[254] = 0;
+ id.name = tmp;
+
+ irq = platform_get_irq_byname(pdev, tmp);
+ if (irq < 0)
+ continue;
+
+ rdev_arr[0] = rdev;
+ retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0,
+ REGULATOR_ERROR_FAIL, NULL,
+ rdev_arr, 1);
+ if (IS_ERR(retp))
+ return PTR_ERR(retp);
+
+ }
+ return 0;
+}
+
+static int bd96801_global_errb_irqs(struct platform_device *pdev,
+ struct regulator_dev **rdev, int num_rdev)
+{
+ int i, num_irqs;
+ void *retp;
+ static const char * const global_errb_irqs[] = {
+ "otp-err", "dbist-err", "eep-err", "abist-err", "prstb-err",
+ "drmoserr1", "drmoserr2", "slave-err", "vref-err", "tsd",
+ "uvlo-err", "ovlo-err", "osc-err", "pon-err", "poff-err",
+ "cmd-shdn-err", "int-shdn-err"
+ };
+
+ num_irqs = ARRAY_SIZE(global_errb_irqs);
+ for (i = 0; i < num_irqs; i++) {
+ int irq;
+ struct regulator_irq_desc id = {
+ .name = global_errb_irqs[i],
+ .map_event = bd96801_map_event_all,
+ .irq_off_ms = 1000,
+ };
+
+ irq = platform_get_irq_byname(pdev, global_errb_irqs[i]);
+ if (irq < 0)
+ continue;
+
+ retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0,
+ REGULATOR_ERROR_FAIL, NULL,
+ rdev, num_rdev);
+ if (IS_ERR(retp))
+ return PTR_ERR(retp);
+ }
+
+ return 0;
+}
+
static int bd96801_rdev_intb_irqs(struct platform_device *pdev,
struct bd96801_pmic_data *pdata,
struct bd96801_irqinfo *iinfo,
@@ -783,11 +1207,11 @@ static int bd96801_rdev_intb_irqs(struct platform_device *pdev,
return 0;
}
-
-
static int bd96801_probe(struct platform_device *pdev)
{
struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS];
+ struct regulator_dev *all_rdevs[BD96801_NUM_REGULATORS];
+ struct bd96801_pmic_data *pdata_template;
struct bd96801_regulator_data *rdesc;
struct regulator_config config = {};
int ldo_errs_arr[BD96801_NUM_LDOS];
@@ -795,16 +1219,21 @@ static int bd96801_probe(struct platform_device *pdev)
int temp_notif_ldos = 0;
struct device *parent;
int i, ret;
+ bool use_errb;
void *retp;
parent = pdev->dev.parent;
- pdata = devm_kmemdup(&pdev->dev, &bd96801_data, sizeof(bd96801_data),
+ pdata_template = (struct bd96801_pmic_data *)platform_get_device_id(pdev)->driver_data;
+ if (!pdata_template)
+ return -ENODEV;
+
+ pdata = devm_kmemdup(&pdev->dev, pdata_template, sizeof(bd96801_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- if (initialize_pmic_data(&pdev->dev, pdata))
+ if (initialize_pmic_data(pdev, pdata))
return -ENOMEM;
pdata->regmap = dev_get_regmap(parent, NULL);
@@ -819,12 +1248,19 @@ static int bd96801_probe(struct platform_device *pdev)
config.regmap = pdata->regmap;
config.dev = parent;
+ ret = of_property_match_string(pdev->dev.parent->of_node,
+ "interrupt-names", "errb");
+ if (ret < 0)
+ use_errb = false;
+ else
+ use_errb = true;
+
ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc,
- BD96801_NUM_REGULATORS);
+ pdata->num_regulators);
if (ret)
return ret;
- for (i = 0; i < ARRAY_SIZE(pdata->regulator_data); i++) {
+ for (i = 0; i < pdata->num_regulators; i++) {
struct regulator_dev *rdev;
struct bd96801_irq_desc *idesc = &rdesc[i].irq_desc;
int j;
@@ -837,6 +1273,8 @@ static int bd96801_probe(struct platform_device *pdev)
rdesc[i].desc.name);
return PTR_ERR(rdev);
}
+
+ all_rdevs[i] = rdev;
/*
* LDOs don't have own temperature monitoring. If temperature
* notification was requested for this LDO from DT then we will
@@ -856,16 +1294,22 @@ static int bd96801_probe(struct platform_device *pdev)
if (ret)
return ret;
}
+ /* Register per regulator ERRB notifiers */
+ if (use_errb) {
+ ret = bd96801_rdev_errb_irqs(pdev, rdev);
+ if (ret)
+ return ret;
+ }
}
if (temp_notif_ldos) {
int irq;
struct regulator_irq_desc tw_desc = {
- .name = "bd96801-core-thermal",
+ .name = "core-thermal",
.irq_off_ms = 500,
.map_event = ldo_map_notif,
};
- irq = platform_get_irq_byname(pdev, "bd96801-core-thermal");
+ irq = platform_get_irq_byname(pdev, "core-thermal");
if (irq < 0)
return irq;
@@ -877,12 +1321,19 @@ static int bd96801_probe(struct platform_device *pdev)
return PTR_ERR(retp);
}
+ if (use_errb)
+ return bd96801_global_errb_irqs(pdev, all_rdevs,
+ pdata->num_regulators);
+
return 0;
}
static const struct platform_device_id bd96801_pmic_id[] = {
- { "bd96801-regulator", },
- { }
+ { "bd96801-regulator", (kernel_ulong_t)&bd96801_data },
+ { "bd96802-regulator", (kernel_ulong_t)&bd96802_data },
+ { "bd96805-regulator", (kernel_ulong_t)&bd96805_data },
+ { "bd96806-regulator", (kernel_ulong_t)&bd96806_data },
+ { },
};
MODULE_DEVICE_TABLE(platform, bd96801_pmic_id);
diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
new file mode 100644
index 000000000000..fc1ccede4468
--- /dev/null
+++ b/drivers/regulator/bq257xx-regulator.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * BQ257XX Battery Charger Driver
+ * Copyright (C) 2025 Chris Morgan <macromorgan@hotmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mfd/bq257xx.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+struct bq257xx_reg_data {
+ struct bq257xx_device *bq;
+ struct regulator_dev *bq257xx_reg;
+ struct gpio_desc *otg_en_gpio;
+ struct regulator_desc desc;
+};
+
+static int bq25703_vbus_get_cur_limit(struct regulator_dev *rdev)
+{
+ struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev);
+ int ret;
+ unsigned int reg;
+
+ ret = regmap_read(pdata->bq->regmap, BQ25703_OTG_CURRENT, &reg);
+ if (ret)
+ return ret;
+ return FIELD_GET(BQ25703_OTG_CUR_MASK, reg) * BQ25703_OTG_CUR_STEP_UA;
+}
+
+/*
+ * Check if the minimum current and maximum current requested are
+ * sane values, then set the register accordingly.
+ */
+static int bq25703_vbus_set_cur_limit(struct regulator_dev *rdev,
+ int min_uA, int max_uA)
+{
+ struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev);
+ unsigned int reg;
+
+ if ((min_uA > BQ25703_OTG_CUR_MAX_UA) || (max_uA < 0))
+ return -EINVAL;
+
+ reg = (max_uA / BQ25703_OTG_CUR_STEP_UA);
+
+ /* Catch rounding errors since our step is 50000uA. */
+ if ((reg * BQ25703_OTG_CUR_STEP_UA) < min_uA)
+ return -EINVAL;
+
+ return regmap_write(pdata->bq->regmap, BQ25703_OTG_CURRENT,
+ FIELD_PREP(BQ25703_OTG_CUR_MASK, reg));
+}
+
+static int bq25703_vbus_enable(struct regulator_dev *rdev)
+{
+ struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev);
+
+ if (pdata->otg_en_gpio)
+ gpiod_set_value_cansleep(pdata->otg_en_gpio, 1);
+ return regulator_enable_regmap(rdev);
+}
+
+static int bq25703_vbus_disable(struct regulator_dev *rdev)
+{
+ struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev);
+
+ if (pdata->otg_en_gpio)
+ gpiod_set_value_cansleep(pdata->otg_en_gpio, 0);
+ return regulator_disable_regmap(rdev);
+}
+
+static const struct regulator_ops bq25703_vbus_ops = {
+ .enable = bq25703_vbus_enable,
+ .disable = bq25703_vbus_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_current_limit = bq25703_vbus_get_cur_limit,
+ .set_current_limit = bq25703_vbus_set_cur_limit,
+};
+
+static const struct regulator_desc bq25703_vbus_desc = {
+ .name = "vbus",
+ .of_match = of_match_ptr("vbus"),
+ .regulators_node = of_match_ptr("regulators"),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .ops = &bq25703_vbus_ops,
+ .min_uV = BQ25703_OTG_VOLT_MIN_UV,
+ .uV_step = BQ25703_OTG_VOLT_STEP_UV,
+ .n_voltages = BQ25703_OTG_VOLT_NUM_VOLT,
+ .enable_mask = BQ25703_EN_OTG_MASK,
+ .enable_reg = BQ25703_CHARGE_OPTION_3,
+ .enable_val = BQ25703_EN_OTG_MASK,
+ .disable_val = 0,
+ .vsel_reg = BQ25703_OTG_VOLT,
+ .vsel_mask = BQ25703_OTG_VOLT_MASK,
+};
+
+/* Get optional GPIO for OTG regulator enable. */
+static void bq257xx_reg_dt_parse_gpio(struct platform_device *pdev)
+{
+ struct device_node *child, *subchild;
+ struct bq257xx_reg_data *pdata = platform_get_drvdata(pdev);
+
+ child = of_get_child_by_name(pdev->dev.of_node,
+ pdata->desc.regulators_node);
+ if (!child)
+ return;
+
+ subchild = of_get_child_by_name(child, pdata->desc.of_match);
+ if (!subchild)
+ return;
+
+ of_node_put(child);
+
+ pdata->otg_en_gpio = devm_fwnode_gpiod_get_index(&pdev->dev,
+ of_fwnode_handle(subchild),
+ "enable", 0,
+ GPIOD_OUT_LOW,
+ pdata->desc.of_match);
+
+ of_node_put(subchild);
+
+ if (IS_ERR(pdata->otg_en_gpio)) {
+ dev_err(&pdev->dev, "Error getting enable gpio: %ld\n",
+ PTR_ERR(pdata->otg_en_gpio));
+ return;
+ }
+}
+
+static int bq257xx_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct bq257xx_device *bq = dev_get_drvdata(pdev->dev.parent);
+ struct bq257xx_reg_data *pdata;
+ struct device_node *np = dev->of_node;
+ struct regulator_config cfg = {};
+
+ pdev->dev.of_node = pdev->dev.parent->of_node;
+ pdev->dev.of_node_reused = true;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(struct bq257xx_reg_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->bq = bq;
+ pdata->desc = bq25703_vbus_desc;
+
+ platform_set_drvdata(pdev, pdata);
+ bq257xx_reg_dt_parse_gpio(pdev);
+
+ cfg.dev = &pdev->dev;
+ cfg.driver_data = pdata;
+ cfg.of_node = np;
+ cfg.regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!cfg.regmap)
+ return -ENODEV;
+
+ pdata->bq257xx_reg = devm_regulator_register(dev, &pdata->desc, &cfg);
+ if (IS_ERR(pdata->bq257xx_reg)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(pdata->bq257xx_reg),
+ "error registering bq257xx regulator");
+ }
+
+ return 0;
+}
+
+static struct platform_driver bq257xx_reg_driver = {
+ .driver = {
+ .name = "bq257xx-regulator",
+ },
+ .probe = bq257xx_regulator_probe,
+};
+
+module_platform_driver(bq257xx_reg_driver);
+
+MODULE_DESCRIPTION("bq257xx regulator driver");
+MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 84d48e310aa8..f4987f54e01b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -83,6 +83,19 @@ struct regulator_supply_alias {
const char *alias_supply;
};
+/*
+ * Work item used to forward regulator events.
+ *
+ * @work: workqueue entry
+ * @rdev: regulator device to notify (consumer receiving the forwarded event)
+ * @event: event code to be forwarded
+ */
+struct regulator_event_work {
+ struct work_struct work;
+ struct regulator_dev *rdev;
+ unsigned long event;
+};
+
static int _regulator_is_enabled(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator *regulator);
static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags);
@@ -497,7 +510,8 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
return -EPERM;
}
- if (*max_uA > rdev->constraints->max_uA)
+ if (*max_uA > rdev->constraints->max_uA &&
+ rdev->constraints->max_uA)
*max_uA = rdev->constraints->max_uA;
if (*min_uA < rdev->constraints->min_uA)
*min_uA = rdev->constraints->min_uA;
@@ -916,6 +930,26 @@ static ssize_t bypass_show(struct device *dev,
}
static DEVICE_ATTR_RO(bypass);
+static ssize_t power_budget_milliwatt_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", rdev->constraints->pw_budget_mW);
+}
+static DEVICE_ATTR_RO(power_budget_milliwatt);
+
+static ssize_t power_requested_milliwatt_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", rdev->pw_requested_mW);
+}
+static DEVICE_ATTR_RO(power_requested_milliwatt);
+
#define REGULATOR_ERROR_ATTR(name, bit) \
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
@@ -1148,6 +1182,10 @@ static void print_constraints_debug(struct regulator_dev *rdev)
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
count += scnprintf(buf + count, len - count, "standby ");
+ if (constraints->pw_budget_mW)
+ count += scnprintf(buf + count, len - count, "%d mW budget",
+ constraints->pw_budget_mW);
+
if (!count)
count = scnprintf(buf, len, "no parameters");
else
@@ -1561,8 +1599,8 @@ static int set_machine_constraints(struct regulator_dev *rdev)
}
if (rdev->constraints->active_discharge && ops->set_active_discharge) {
- bool ad_state = (rdev->constraints->active_discharge ==
- REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
+ bool ad_state = rdev->constraints->active_discharge ==
+ REGULATOR_ACTIVE_DISCHARGE_ENABLE;
ret = ops->set_active_discharge(rdev, ad_state);
if (ret < 0) {
@@ -1593,6 +1631,8 @@ static int set_machine_constraints(struct regulator_dev *rdev)
* and we have control then make sure it is enabled.
*/
if (rdev->constraints->always_on || rdev->constraints->boot_on) {
+ bool supply_enabled = false;
+
/* If we want to enable this regulator, make sure that we know
* the supplying regulator.
*/
@@ -1612,11 +1652,14 @@ static int set_machine_constraints(struct regulator_dev *rdev)
rdev->supply = NULL;
return ret;
}
+ supply_enabled = true;
}
ret = _regulator_do_enable(rdev);
if (ret < 0 && ret != -EINVAL) {
rdev_err(rdev, "failed to enable: %pe\n", ERR_PTR(ret));
+ if (supply_enabled)
+ regulator_disable(rdev->supply);
return ret;
}
@@ -1626,11 +1669,112 @@ static int set_machine_constraints(struct regulator_dev *rdev)
rdev->last_off = ktime_get();
}
+ if (!rdev->constraints->pw_budget_mW)
+ rdev->constraints->pw_budget_mW = INT_MAX;
+
print_constraints(rdev);
return 0;
}
/**
+ * regulator_event_work_fn - process a deferred regulator event
+ * @work: work_struct queued by the notifier
+ *
+ * Calls the regulator's notifier chain in process context while holding
+ * the rdev lock, then releases the device reference.
+ */
+static void regulator_event_work_fn(struct work_struct *work)
+{
+ struct regulator_event_work *rew =
+ container_of(work, struct regulator_event_work, work);
+ struct regulator_dev *rdev = rew->rdev;
+ int ret;
+
+ regulator_lock(rdev);
+ ret = regulator_notifier_call_chain(rdev, rew->event, NULL);
+ regulator_unlock(rdev);
+ if (ret == NOTIFY_BAD)
+ dev_err(rdev_get_dev(rdev), "failed to forward regulator event\n");
+
+ put_device(rdev_get_dev(rdev));
+ kfree(rew);
+}
+
+/**
+ * regulator_event_forward_notifier - notifier callback for supply events
+ * @nb: notifier block embedded in the regulator
+ * @event: regulator event code
+ * @data: unused
+ *
+ * Packages the event into a work item and schedules it in process context.
+ * Takes a reference on @rdev->dev to pin the regulator until the work
+ * completes (see put_device() in the worker).
+ *
+ * Return: NOTIFY_OK on success, NOTIFY_DONE for events that are not forwarded.
+ */
+static int regulator_event_forward_notifier(struct notifier_block *nb,
+ unsigned long event,
+ void __always_unused *data)
+{
+ struct regulator_dev *rdev = container_of(nb, struct regulator_dev,
+ supply_fwd_nb);
+ struct regulator_event_work *rew;
+
+ switch (event) {
+ case REGULATOR_EVENT_UNDER_VOLTAGE:
+ break;
+ default:
+ /* Only forward allowed events downstream. */
+ return NOTIFY_DONE;
+ }
+
+ rew = kmalloc(sizeof(*rew), GFP_ATOMIC);
+ if (!rew)
+ return NOTIFY_DONE;
+
+ get_device(rdev_get_dev(rdev));
+ rew->rdev = rdev;
+ rew->event = event;
+ INIT_WORK(&rew->work, regulator_event_work_fn);
+
+ queue_work(system_highpri_wq, &rew->work);
+
+ return NOTIFY_OK;
+}
+
+/**
+ * register_regulator_event_forwarding - enable supply event forwarding
+ * @rdev: regulator device
+ *
+ * Registers a notifier on the regulator's supply so that supply events
+ * are forwarded to the consumer regulator via the deferred work handler.
+ *
+ * Return: 0 on success, -EALREADY if already enabled, or a negative error code.
+ */
+static int register_regulator_event_forwarding(struct regulator_dev *rdev)
+{
+ int ret;
+
+ if (!rdev->supply)
+ return 0; /* top-level regulator: nothing to forward */
+
+ if (rdev->supply_fwd_nb.notifier_call)
+ return -EALREADY;
+
+ rdev->supply_fwd_nb.notifier_call = regulator_event_forward_notifier;
+
+ ret = regulator_register_notifier(rdev->supply, &rdev->supply_fwd_nb);
+ if (ret) {
+ dev_err(&rdev->dev, "failed to register supply notifier: %pe\n",
+ ERR_PTR(ret));
+ rdev->supply_fwd_nb.notifier_call = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
* set_supply - set regulator supply regulator
* @rdev: regulator (locked)
* @supply_rdev: supply regulator (locked))
@@ -1802,12 +1946,49 @@ static const struct file_operations constraint_flags_fops = {
#define REG_STR_SIZE 64
+static void link_and_create_debugfs(struct regulator *regulator, struct regulator_dev *rdev,
+ struct device *dev)
+{
+ int err = 0;
+
+ if (dev) {
+ regulator->dev = dev;
+
+ /* Add a link to the device sysfs entry */
+ err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj,
+ regulator->supply_name);
+ if (err) {
+ rdev_dbg(rdev, "could not add device link %s: %pe\n",
+ dev->kobj.name, ERR_PTR(err));
+ /* non-fatal */
+ }
+ }
+
+ if (err != -EEXIST) {
+ regulator->debugfs = debugfs_create_dir(regulator->supply_name, rdev->debugfs);
+ if (IS_ERR(regulator->debugfs)) {
+ rdev_dbg(rdev, "Failed to create debugfs directory\n");
+ regulator->debugfs = NULL;
+ }
+ }
+
+ if (regulator->debugfs) {
+ debugfs_create_u32("uA_load", 0444, regulator->debugfs,
+ &regulator->uA_load);
+ debugfs_create_u32("min_uV", 0444, regulator->debugfs,
+ &regulator->voltage[PM_SUSPEND_ON].min_uV);
+ debugfs_create_u32("max_uV", 0444, regulator->debugfs,
+ &regulator->voltage[PM_SUSPEND_ON].max_uV);
+ debugfs_create_file("constraint_flags", 0444, regulator->debugfs,
+ regulator, &constraint_flags_fops);
+ }
+}
+
static struct regulator *create_regulator(struct regulator_dev *rdev,
struct device *dev,
const char *supply_name)
{
struct regulator *regulator;
- int err = 0;
lockdep_assert_held_once(&rdev->mutex.base);
@@ -1840,38 +2021,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
list_add(&regulator->list, &rdev->consumer_list);
- if (dev) {
- regulator->dev = dev;
-
- /* Add a link to the device sysfs entry */
- err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj,
- supply_name);
- if (err) {
- rdev_dbg(rdev, "could not add device link %s: %pe\n",
- dev->kobj.name, ERR_PTR(err));
- /* non-fatal */
- }
- }
-
- if (err != -EEXIST) {
- regulator->debugfs = debugfs_create_dir(supply_name, rdev->debugfs);
- if (IS_ERR(regulator->debugfs)) {
- rdev_dbg(rdev, "Failed to create debugfs directory\n");
- regulator->debugfs = NULL;
- }
- }
-
- if (regulator->debugfs) {
- debugfs_create_u32("uA_load", 0444, regulator->debugfs,
- &regulator->uA_load);
- debugfs_create_u32("min_uV", 0444, regulator->debugfs,
- &regulator->voltage[PM_SUSPEND_ON].min_uV);
- debugfs_create_u32("max_uV", 0444, regulator->debugfs,
- &regulator->voltage[PM_SUSPEND_ON].max_uV);
- debugfs_create_file("constraint_flags", 0444, regulator->debugfs,
- regulator, &constraint_flags_fops);
- }
-
/*
* Check now if the regulator is an always on regulator - if
* it is then we don't need to do nearly so much work for
@@ -1909,6 +2058,7 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
{
struct regulator_supply_alias *map;
+ mutex_lock(&regulator_list_mutex);
map = regulator_find_supply_alias(*dev, *supply);
if (map) {
dev_dbg(*dev, "Mapping supply %s to %s,%s\n",
@@ -1917,6 +2067,7 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
*dev = map->alias_dev;
*supply = map->alias_supply;
}
+ mutex_unlock(&regulator_list_mutex);
}
static int regulator_match(struct device *dev, const void *data)
@@ -1935,6 +2086,20 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
return dev ? dev_to_rdev(dev) : NULL;
}
+static struct regulator_dev *regulator_dt_lookup(struct device *dev,
+ const char *supply)
+{
+ struct regulator_dev *r = NULL;
+
+ if (dev_of_node(dev)) {
+ r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply);
+ if (PTR_ERR(r) == -ENODEV)
+ r = NULL;
+ }
+
+ return r;
+}
+
/**
* regulator_dev_lookup - lookup a regulator device.
* @dev: device for regulator "consumer".
@@ -1959,16 +2124,9 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
regulator_supply_alias(&dev, &supply);
/* first do a dt based lookup */
- if (dev_of_node(dev)) {
- r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply);
- if (!IS_ERR(r))
- return r;
- if (PTR_ERR(r) == -EPROBE_DEFER)
- return r;
-
- if (PTR_ERR(r) == -ENODEV)
- r = NULL;
- }
+ r = regulator_dt_lookup(dev, supply);
+ if (r)
+ return r;
/* if not found, try doing it non-dt way */
if (dev)
@@ -2014,7 +2172,17 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (rdev->supply)
return 0;
- r = regulator_dev_lookup(dev, rdev->supply_name);
+ /* first do a dt based lookup on the node described in the virtual
+ * device.
+ */
+ r = regulator_dt_lookup(&rdev->dev, rdev->supply_name);
+
+ /* If regulator not found use usual search path in the parent
+ * device.
+ */
+ if (!r)
+ r = regulator_dev_lookup(dev, rdev->supply_name);
+
if (IS_ERR(r)) {
ret = PTR_ERR(r);
@@ -2024,6 +2192,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (have_full_constraints()) {
r = dummy_regulator_rdev;
+ if (!r) {
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
get_device(&r->dev);
} else {
dev_err(dev, "Failed to resolve %s-supply for %s\n",
@@ -2041,6 +2213,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
goto out;
}
r = dummy_regulator_rdev;
+ if (!r) {
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
get_device(&r->dev);
}
@@ -2086,8 +2262,21 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
goto out;
}
+ /*
+ * Automatically register for event forwarding from the new supply.
+ * This creates the downstream propagation link for events like
+ * under-voltage.
+ */
+ ret = register_regulator_event_forwarding(rdev);
+ if (ret < 0)
+ rdev_warn(rdev, "Failed to register event forwarding: %pe\n",
+ ERR_PTR(ret));
+
regulator_unlock_two(rdev, r, &ww_ctx);
+ /* rdev->supply was created in set_supply() */
+ link_and_create_debugfs(rdev->supply, r, &rdev->dev);
+
/*
* In set_machine_constraints() we may have turned this regulator on
* but we couldn't propagate to the supply if it hadn't been resolved
@@ -2166,8 +2355,10 @@ struct regulator *_regulator_get_common(struct regulator_dev *rdev, struct devic
* enabled, even if it isn't hooked up, and just
* provide a dummy.
*/
- dev_warn(dev, "supply %s not found, using dummy regulator\n", id);
rdev = dummy_regulator_rdev;
+ if (!rdev)
+ return ERR_PTR(-EPROBE_DEFER);
+ dev_warn(dev, "supply %s not found, using dummy regulator\n", id);
get_device(&rdev->dev);
break;
@@ -2226,6 +2417,8 @@ struct regulator *_regulator_get_common(struct regulator_dev *rdev, struct devic
return regulator;
}
+ link_and_create_debugfs(regulator, rdev, dev);
+
rdev->open_count++;
if (get_type == EXCLUSIVE_GET) {
rdev->exclusive = 1;
@@ -2427,22 +2620,26 @@ int regulator_register_supply_alias(struct device *dev, const char *id,
const char *alias_id)
{
struct regulator_supply_alias *map;
+ struct regulator_supply_alias *new_map;
- map = regulator_find_supply_alias(dev, id);
- if (map)
- return -EEXIST;
-
- map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
- if (!map)
+ new_map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
+ if (!new_map)
return -ENOMEM;
- map->src_dev = dev;
- map->src_supply = id;
- map->alias_dev = alias_dev;
- map->alias_supply = alias_id;
-
- list_add(&map->list, &regulator_supply_alias_list);
+ mutex_lock(&regulator_list_mutex);
+ map = regulator_find_supply_alias(dev, id);
+ if (map) {
+ mutex_unlock(&regulator_list_mutex);
+ kfree(new_map);
+ return -EEXIST;
+ }
+ new_map->src_dev = dev;
+ new_map->src_supply = id;
+ new_map->alias_dev = alias_dev;
+ new_map->alias_supply = alias_id;
+ list_add(&new_map->list, &regulator_supply_alias_list);
+ mutex_unlock(&regulator_list_mutex);
pr_info("Adding alias for supply %s,%s -> %s,%s\n",
id, dev_name(dev), alias_id, dev_name(alias_dev));
@@ -2462,11 +2659,13 @@ void regulator_unregister_supply_alias(struct device *dev, const char *id)
{
struct regulator_supply_alias *map;
+ mutex_lock(&regulator_list_mutex);
map = regulator_find_supply_alias(dev, id);
if (map) {
list_del(&map->list);
kfree(map);
}
+ mutex_unlock(&regulator_list_mutex);
}
EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);
@@ -2551,8 +2750,15 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev,
mutex_lock(&regulator_list_mutex);
+ if (gpiod_is_shared(gpiod))
+ /*
+ * The sharing of this GPIO pin is managed internally by
+ * GPIOLIB. We don't need to keep track of its enable count.
+ */
+ goto skip_compare;
+
list_for_each_entry(pin, &regulator_ena_gpio_list, list) {
- if (pin->gpiod == gpiod) {
+ if (gpiod_is_equal(pin->gpiod, gpiod)) {
rdev_dbg(rdev, "GPIO is already used\n");
goto update_ena_gpio_to_rdev;
}
@@ -2563,6 +2769,7 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev,
return -ENOMEM;
}
+skip_compare:
pin = new_pin;
new_pin = NULL;
@@ -3732,6 +3939,16 @@ static int _regulator_do_set_suspend_voltage(struct regulator_dev *rdev,
return 0;
}
+static int regulator_get_voltage_delta(struct regulator_dev *rdev, int uV)
+{
+ int current_uV = regulator_get_voltage_rdev(rdev);
+
+ if (current_uV < 0)
+ return current_uV;
+
+ return abs(current_uV - uV);
+}
+
static int regulator_set_voltage_unlocked(struct regulator *regulator,
int min_uV, int max_uV,
suspend_state_t state)
@@ -3739,8 +3956,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
struct regulator_dev *rdev = regulator->rdev;
struct regulator_voltage *voltage = &regulator->voltage[state];
int ret = 0;
+ int current_uV, delta, new_delta;
int old_min_uV, old_max_uV;
- int current_uV;
/* If we're setting the same range as last time the change
* should be a noop (some cpufreq implementations use the same
@@ -3787,6 +4004,37 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
voltage->max_uV = old_max_uV;
}
+ if (rdev->constraints->max_uV_step > 0) {
+ /* For regulators with a maximum voltage step, reaching the desired
+ * voltage might take a few retries.
+ */
+ ret = regulator_get_voltage_delta(rdev, min_uV);
+ if (ret < 0)
+ goto out;
+
+ delta = ret;
+
+ while (delta > 0) {
+ ret = regulator_balance_voltage(rdev, state);
+ if (ret < 0)
+ goto out;
+
+ ret = regulator_get_voltage_delta(rdev, min_uV);
+ if (ret < 0)
+ goto out;
+
+ new_delta = ret;
+
+ /* check that voltage is converging quickly enough */
+ if (delta - new_delta < rdev->constraints->max_uV_step) {
+ ret = -EWOULDBLOCK;
+ goto out;
+ }
+
+ delta = new_delta;
+ }
+ }
+
out:
return ret;
}
@@ -4584,6 +4832,87 @@ int regulator_get_current_limit(struct regulator *regulator)
EXPORT_SYMBOL_GPL(regulator_get_current_limit);
/**
+ * regulator_get_unclaimed_power_budget - get regulator unclaimed power budget
+ * @regulator: regulator source
+ *
+ * Return: Unclaimed power budget of the regulator in mW.
+ */
+int regulator_get_unclaimed_power_budget(struct regulator *regulator)
+{
+ return regulator->rdev->constraints->pw_budget_mW -
+ regulator->rdev->pw_requested_mW;
+}
+EXPORT_SYMBOL_GPL(regulator_get_unclaimed_power_budget);
+
+/**
+ * regulator_request_power_budget - request power budget on a regulator
+ * @regulator: regulator source
+ * @pw_req: Power requested
+ *
+ * Return: 0 on success or a negative error number on failure.
+ */
+int regulator_request_power_budget(struct regulator *regulator,
+ unsigned int pw_req)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+ int ret = 0, pw_tot_req;
+
+ regulator_lock(rdev);
+ if (rdev->supply) {
+ ret = regulator_request_power_budget(rdev->supply, pw_req);
+ if (ret < 0)
+ goto out;
+ }
+
+ pw_tot_req = rdev->pw_requested_mW + pw_req;
+ if (pw_tot_req > rdev->constraints->pw_budget_mW) {
+ rdev_warn(rdev, "power requested %d mW out of budget %d mW",
+ pw_req,
+ rdev->constraints->pw_budget_mW - rdev->pw_requested_mW);
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_OVER_CURRENT_WARN,
+ NULL);
+ ret = -ERANGE;
+ goto out;
+ }
+
+ rdev->pw_requested_mW = pw_tot_req;
+out:
+ regulator_unlock(rdev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_request_power_budget);
+
+/**
+ * regulator_free_power_budget - free power budget on a regulator
+ * @regulator: regulator source
+ * @pw: Power to be released.
+ *
+ * Return: Power budget of the regulator in mW.
+ */
+void regulator_free_power_budget(struct regulator *regulator,
+ unsigned int pw)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+ int pw_tot_req;
+
+ regulator_lock(rdev);
+ if (rdev->supply)
+ regulator_free_power_budget(rdev->supply, pw);
+
+ pw_tot_req = rdev->pw_requested_mW - pw;
+ if (pw_tot_req >= 0)
+ rdev->pw_requested_mW = pw_tot_req;
+ else
+ rdev_warn(rdev,
+ "too much power freed %d mW (already requested %d mW)",
+ pw, rdev->pw_requested_mW);
+
+ regulator_unlock(rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_free_power_budget);
+
+/**
* regulator_set_mode - set regulator operating mode
* @regulator: regulator source
* @mode: operating mode - one of the REGULATOR_MODE constants
@@ -4907,7 +5236,7 @@ int _regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].supply, get_type);
if (IS_ERR(consumers[i].consumer)) {
ret = dev_err_probe(dev, PTR_ERR(consumers[i].consumer),
- "Failed to get supply '%s'",
+ "Failed to get supply '%s'\n",
consumers[i].supply);
consumers[i].consumer = NULL;
goto err;
@@ -5136,8 +5465,8 @@ static void regulator_handle_critical(struct regulator_dev *rdev,
if (!reason)
return;
- hw_protection_shutdown(reason,
- rdev->constraints->uv_less_critical_window_ms);
+ hw_protection_trigger(reason,
+ rdev->constraints->uv_less_critical_window_ms);
}
/**
@@ -5221,6 +5550,8 @@ static struct attribute *regulator_dev_attrs[] = {
&dev_attr_suspend_standby_mode.attr,
&dev_attr_suspend_mem_mode.attr,
&dev_attr_suspend_disk_mode.attr,
+ &dev_attr_power_budget_milliwatt.attr,
+ &dev_attr_power_requested_milliwatt.attr,
NULL
};
@@ -5302,6 +5633,10 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
attr == &dev_attr_suspend_disk_mode.attr)
return ops->set_suspend_mode ? mode : 0;
+ if (attr == &dev_attr_power_budget_milliwatt.attr ||
+ attr == &dev_attr_power_requested_milliwatt.attr)
+ return rdev->constraints->pw_budget_mW != INT_MAX ? mode : 0;
+
return mode;
}
@@ -5487,6 +5822,7 @@ static void regulator_remove_coupling(struct regulator_dev *rdev)
ERR_PTR(err));
}
+ rdev->coupling_desc.n_coupled = 0;
kfree(rdev->coupling_desc.coupled_rdevs);
rdev->coupling_desc.coupled_rdevs = NULL;
}
@@ -5642,43 +5978,36 @@ regulator_register(struct device *dev,
goto clean;
}
- if (config->init_data) {
- /*
- * Providing of_match means the framework is expected to parse
- * DT to get the init_data. This would conflict with provided
- * init_data, if set. Warn if it happens.
- */
- if (regulator_desc->of_match)
- dev_warn(dev, "Using provided init data - OF match ignored\n");
+ /*
+ * DT may override the config->init_data provided if the platform
+ * needs to do so. If so, config->init_data is completely ignored.
+ */
+ init_data = regulator_of_get_init_data(dev, regulator_desc, config,
+ &rdev->dev.of_node);
+
+ /*
+ * Sometimes not all resources are probed already so we need to take
+ * that into account. This happens most the time if the ena_gpiod comes
+ * from a gpio extender or something else.
+ */
+ if (PTR_ERR(init_data) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto clean;
+ }
+ /*
+ * We need to keep track of any GPIO descriptor coming from the
+ * device tree until we have handled it over to the core. If the
+ * config that was passed in to this function DOES NOT contain
+ * a descriptor, and the config after this call DOES contain
+ * a descriptor, we definitely got one from parsing the device
+ * tree.
+ */
+ if (!cfg->ena_gpiod && config->ena_gpiod)
+ dangling_of_gpiod = true;
+ if (!init_data) {
init_data = config->init_data;
rdev->dev.of_node = of_node_get(config->of_node);
-
- } else {
- init_data = regulator_of_get_init_data(dev, regulator_desc,
- config,
- &rdev->dev.of_node);
-
- /*
- * Sometimes not all resources are probed already so we need to
- * take that into account. This happens most the time if the
- * ena_gpiod comes from a gpio extender or something else.
- */
- if (PTR_ERR(init_data) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
- goto clean;
- }
-
- /*
- * We need to keep track of any GPIO descriptor coming from the
- * device tree until we have handled it over to the core. If the
- * config that was passed in to this function DOES NOT contain a
- * descriptor, and the config after this call DOES contain a
- * descriptor, we definitely got one from parsing the device
- * tree.
- */
- if (!cfg->ena_gpiod && config->ena_gpiod)
- dangling_of_gpiod = true;
}
ww_mutex_init(&rdev->mutex, &regulator_ww_class);
@@ -5844,6 +6173,9 @@ void regulator_unregister(struct regulator_dev *rdev)
return;
if (rdev->supply) {
+ regulator_unregister_notifier(rdev->supply,
+ &rdev->supply_fwd_nb);
+
while (rdev->use_count--)
regulator_disable(rdev->supply);
regulator_put(rdev->supply);
diff --git a/drivers/regulator/cros-ec-regulator.c b/drivers/regulator/cros-ec-regulator.c
index fb9643ed7a49..fb0767b33a36 100644
--- a/drivers/regulator/cros-ec-regulator.c
+++ b/drivers/regulator/cros-ec-regulator.c
@@ -138,8 +138,8 @@ static int cros_ec_regulator_init_info(struct device *dev,
data->num_voltages =
min_t(u16, ARRAY_SIZE(resp.voltages_mv), resp.num_voltages);
data->voltages_mV =
- devm_kmemdup(dev, resp.voltages_mv,
- sizeof(u16) * data->num_voltages, GFP_KERNEL);
+ devm_kmemdup_array(dev, resp.voltages_mv, data->num_voltages,
+ sizeof(resp.voltages_mv[0]), GFP_KERNEL);
if (!data->voltages_mV)
return -ENOMEM;
diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c
index 17527a3f53b4..ef161eb0ca27 100644
--- a/drivers/regulator/da9121-regulator.c
+++ b/drivers/regulator/da9121-regulator.c
@@ -1129,7 +1129,7 @@ static int da9121_i2c_probe(struct i2c_client *i2c)
}
chip->pdata = i2c->dev.platform_data;
- chip->subvariant_id = (enum da9121_subvariant)i2c_get_match_data(i2c);
+ chip->subvariant_id = (kernel_ulong_t)i2c_get_match_data(i2c);
ret = da9121_assign_chip_model(i2c, chip);
if (ret < 0)
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 36164aec30e8..2cf03042fddf 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -332,9 +332,8 @@ int devm_regulator_bulk_get_const(struct device *dev, int num_consumers,
const struct regulator_bulk_data *in_consumers,
struct regulator_bulk_data **out_consumers)
{
- *out_consumers = devm_kmemdup(dev, in_consumers,
- num_consumers * sizeof(*in_consumers),
- GFP_KERNEL);
+ *out_consumers = devm_kmemdup_array(dev, in_consumers, num_consumers,
+ sizeof(*in_consumers), GFP_KERNEL);
if (*out_consumers == NULL)
return -ENOMEM;
@@ -772,6 +771,23 @@ static struct regulator *_devm_of_regulator_get(struct device *dev, struct devic
}
/**
+ * devm_of_regulator_get - Resource managed of_regulator_get()
+ * @dev: device used for dev_printk() messages and resource lifetime management
+ * @node: device node for regulator "consumer"
+ * @id: supply name or regulator ID.
+ *
+ * Managed of_regulator_get(). Regulators returned from this
+ * function are automatically regulator_put() on driver detach. See
+ * of_regulator_get() for more information.
+ */
+struct regulator *devm_of_regulator_get(struct device *dev, struct device_node *node,
+ const char *id)
+{
+ return _devm_of_regulator_get(dev, node, id, NORMAL_GET);
+}
+EXPORT_SYMBOL_GPL(devm_of_regulator_get);
+
+/**
* devm_of_regulator_get_optional - Resource managed of_regulator_get_optional()
* @dev: device used for dev_printk() messages and resource lifetime management
* @node: device node for regulator "consumer"
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index 5b9b9e4e762d..e5197ec7234d 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -13,7 +13,7 @@
#include <linux/err.h>
#include <linux/export.h>
-#include <linux/platform_device.h>
+#include <linux/device/faux.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -37,15 +37,15 @@ static const struct regulator_desc dummy_desc = {
.ops = &dummy_ops,
};
-static int dummy_regulator_probe(struct platform_device *pdev)
+static int dummy_regulator_probe(struct faux_device *fdev)
{
struct regulator_config config = { };
int ret;
- config.dev = &pdev->dev;
+ config.dev = &fdev->dev;
config.init_data = &dummy_initdata;
- dummy_regulator_rdev = devm_regulator_register(&pdev->dev, &dummy_desc,
+ dummy_regulator_rdev = devm_regulator_register(&fdev->dev, &dummy_desc,
&config);
if (IS_ERR(dummy_regulator_rdev)) {
ret = PTR_ERR(dummy_regulator_rdev);
@@ -56,36 +56,17 @@ static int dummy_regulator_probe(struct platform_device *pdev)
return 0;
}
-static struct platform_driver dummy_regulator_driver = {
- .probe = dummy_regulator_probe,
- .driver = {
- .name = "reg-dummy",
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
- },
+struct faux_device_ops dummy_regulator_driver = {
+ .probe = dummy_regulator_probe,
};
-static struct platform_device *dummy_pdev;
+static struct faux_device *dummy_fdev;
void __init regulator_dummy_init(void)
{
- int ret;
-
- dummy_pdev = platform_device_alloc("reg-dummy", -1);
- if (!dummy_pdev) {
+ dummy_fdev = faux_device_create("reg-dummy", NULL, &dummy_regulator_driver);
+ if (!dummy_fdev) {
pr_err("Failed to allocate dummy regulator device\n");
return;
}
-
- ret = platform_device_add(dummy_pdev);
- if (ret != 0) {
- pr_err("Failed to register dummy regulator device: %d\n", ret);
- platform_device_put(dummy_pdev);
- return;
- }
-
- ret = platform_driver_register(&dummy_regulator_driver);
- if (ret != 0) {
- pr_err("Failed to register dummy regulator driver: %d\n", ret);
- platform_device_unregister(dummy_pdev);
- }
}
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index bd9447dac596..c282236959b1 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -147,6 +147,7 @@ struct fan53555_device_info {
unsigned int slew_mask;
const unsigned int *ramp_delay_table;
unsigned int n_ramp_values;
+ unsigned int enable_time;
unsigned int slew_rate;
};
@@ -282,6 +283,7 @@ static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di)
di->slew_mask = CTL_SLEW_MASK;
di->ramp_delay_table = slew_rates;
di->n_ramp_values = ARRAY_SIZE(slew_rates);
+ di->enable_time = 250;
di->vsel_count = FAN53526_NVOLTAGES;
return 0;
@@ -296,10 +298,12 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
case FAN53555_CHIP_REV_00:
di->vsel_min = 600000;
di->vsel_step = 10000;
+ di->enable_time = 400;
break;
case FAN53555_CHIP_REV_13:
di->vsel_min = 800000;
di->vsel_step = 10000;
+ di->enable_time = 400;
break;
default:
dev_err(di->dev,
@@ -311,13 +315,19 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
case FAN53555_CHIP_ID_01:
case FAN53555_CHIP_ID_03:
case FAN53555_CHIP_ID_05:
+ di->vsel_min = 600000;
+ di->vsel_step = 10000;
+ di->enable_time = 400;
+ break;
case FAN53555_CHIP_ID_08:
di->vsel_min = 600000;
di->vsel_step = 10000;
+ di->enable_time = 175;
break;
case FAN53555_CHIP_ID_04:
di->vsel_min = 603000;
di->vsel_step = 12826;
+ di->enable_time = 400;
break;
default:
dev_err(di->dev,
@@ -350,6 +360,7 @@ static int fan53555_voltages_setup_rockchip(struct fan53555_device_info *di)
di->slew_mask = CTL_SLEW_MASK;
di->ramp_delay_table = slew_rates;
di->n_ramp_values = ARRAY_SIZE(slew_rates);
+ di->enable_time = 360;
di->vsel_count = FAN53555_NVOLTAGES;
return 0;
@@ -372,6 +383,7 @@ static int rk8602_voltages_setup_rockchip(struct fan53555_device_info *di)
di->slew_mask = CTL_SLEW_MASK;
di->ramp_delay_table = slew_rates;
di->n_ramp_values = ARRAY_SIZE(slew_rates);
+ di->enable_time = 360;
di->vsel_count = RK8602_NVOLTAGES;
return 0;
@@ -395,6 +407,7 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
di->slew_mask = CTL_SLEW_MASK;
di->ramp_delay_table = slew_rates;
di->n_ramp_values = ARRAY_SIZE(slew_rates);
+ di->enable_time = 400;
di->vsel_count = FAN53555_NVOLTAGES;
return 0;
@@ -594,6 +607,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,
rdesc->ramp_mask = di->slew_mask;
rdesc->ramp_delay_table = di->ramp_delay_table;
rdesc->n_ramp_values = di->n_ramp_values;
+ rdesc->enable_time = di->enable_time;
rdesc->owner = THIS_MODULE;
rdev = devm_regulator_register(di->dev, &di->desc, config);
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 1cb647ed70c6..a2d16e9abfb5 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -334,6 +334,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
ret = dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev),
"Failed to register regulator: %ld\n",
PTR_ERR(drvdata->dev));
+ gpiod_put(cfg.ena_gpiod);
return ret;
}
diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c
new file mode 100644
index 000000000000..fef0bb07fd5d
--- /dev/null
+++ b/drivers/regulator/fp9931.c
@@ -0,0 +1,551 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2025 Andreas Kemnade
+
+/* Datasheet: https://www.fitipower.com/dl/file/flXa6hIchVeu0W3K */
+
+#include <linux/cleanup.h>
+#include <linux/completion.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regmap.h>
+
+#define FP9931_REG_TMST_VALUE 0
+#define FP9931_REG_VCOM_SETTING 1
+#define FP9931_REG_VPOSNEG_SETTING 2
+#define FP9931_REG_PWRON_DELAY 3
+#define FP9931_REG_CONTROL_REG1 11
+
+#define PGOOD_TIMEOUT_MSECS 200
+
+struct fp9931_data {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regulator *vin_reg;
+ struct gpio_desc *pgood_gpio;
+ struct gpio_desc *en_gpio;
+ struct gpio_desc *en_ts_gpio;
+ struct completion pgood_completion;
+ int pgood_irq;
+};
+
+static const unsigned int VPOSNEG_table[] = {
+ 7040000,
+ 7040000,
+ 7040000,
+ 7040000,
+ 7040000,
+ 7040000,
+ 7260000,
+ 7490000,
+ 7710000,
+ 7930000,
+ 8150000,
+ 8380000,
+ 8600000,
+ 8820000,
+ 9040000,
+ 9270000,
+ 9490000,
+ 9710000,
+ 9940000,
+ 10160000,
+ 10380000,
+ 10600000,
+ 10830000,
+ 11050000,
+ 11270000,
+ 11490000,
+ 11720000,
+ 11940000,
+ 12160000,
+ 12380000,
+ 12610000,
+ 12830000,
+ 13050000,
+ 13280000,
+ 13500000,
+ 13720000,
+ 13940000,
+ 14170000,
+ 14390000,
+ 14610000,
+ 14830000,
+ 15060000,
+};
+
+static const struct hwmon_channel_info *fp9931_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ NULL
+};
+
+static int setup_timings(struct fp9931_data *data)
+{
+ u32 tdly[4];
+ u8 tdlys = 0;
+ int i;
+ int ret;
+
+ ret = device_property_count_u32(data->dev, "fitipower,tdly-ms");
+ if (ret == -EINVAL) /* property is optional */
+ return 0;
+
+ if (ret < 0)
+ return ret;
+
+ if (ret != ARRAY_SIZE(tdly)) {
+ dev_err(data->dev, "invalid delay specification");
+ return -EINVAL;
+ }
+
+ ret = device_property_read_u32_array(data->dev, "fitipower,tdly-ms",
+ tdly, ARRAY_SIZE(tdly));
+ if (ret)
+ return ret;
+
+ for (i = ARRAY_SIZE(tdly) - 1; i >= 0; i--) {
+ if (tdly[i] > 4 || tdly[i] == 3)
+ return -EINVAL;
+
+ if (tdly[i] == 4) /* convert from ms */
+ tdly[i] = 3;
+
+ tdlys <<= 2;
+ tdlys |= tdly[i];
+ }
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(data->regmap, FP9931_REG_PWRON_DELAY, tdlys);
+ pm_runtime_put_autosuspend(data->dev);
+
+ return ret;
+}
+
+static int fp9931_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *temp)
+{
+ struct fp9931_data *data = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, FP9931_REG_TMST_VALUE, &val);
+ if (ret)
+ return ret;
+
+ pm_runtime_put_autosuspend(data->dev);
+ *temp = (s8)val * 1000;
+
+ return 0;
+}
+
+static umode_t fp9931_hwmon_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ return 0444;
+}
+
+static const struct hwmon_ops fp9931_hwmon_ops = {
+ .is_visible = fp9931_hwmon_is_visible,
+ .read = fp9931_hwmon_read,
+};
+
+static const struct hwmon_chip_info fp9931_chip_info = {
+ .ops = &fp9931_hwmon_ops,
+ .info = fp9931_info,
+};
+
+static int fp9931_runtime_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct fp9931_data *data = dev_get_drvdata(dev);
+
+ if (data->en_ts_gpio)
+ gpiod_set_value_cansleep(data->en_ts_gpio, 0);
+
+ if (data->vin_reg) {
+ ret = regulator_disable(data->vin_reg);
+ regcache_mark_dirty(data->regmap);
+ }
+
+ return ret;
+}
+
+static int fp9931_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct fp9931_data *data = dev_get_drvdata(dev);
+
+ if (data->vin_reg)
+ ret = regulator_enable(data->vin_reg);
+
+ if (ret)
+ return ret;
+
+ if (data->en_ts_gpio) {
+ gpiod_set_value_cansleep(data->en_ts_gpio, 1);
+ /* wait for one ADC conversion to have sane temperature */
+ usleep_range(10000, 15000);
+ }
+
+ ret = regcache_sync(data->regmap);
+
+ return ret;
+}
+
+static bool fp9931_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg == FP9931_REG_TMST_VALUE;
+}
+
+static const struct reg_default fp9931_reg_default = {
+ .reg = FP9931_REG_VCOM_SETTING,
+ .def = 0x80,
+};
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 12,
+ .cache_type = REGCACHE_FLAT,
+ .volatile_reg = fp9931_volatile_reg,
+ .reg_defaults = &fp9931_reg_default,
+ .num_reg_defaults = 1,
+};
+
+static void disable_nopm(void *d)
+{
+ struct fp9931_data *data = d;
+
+ fp9931_runtime_suspend(data->dev);
+}
+
+static int fp9931_v3p3_enable(struct regulator_dev *rdev)
+{
+ struct fp9931_data *data = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_enable_regmap(rdev);
+ if (ret < 0)
+ pm_runtime_put_autosuspend(data->dev);
+
+ return ret;
+}
+
+static int fp9931_v3p3_disable(struct regulator_dev *rdev)
+{
+ struct fp9931_data *data = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = regulator_disable_regmap(rdev);
+ pm_runtime_put_autosuspend(data->dev);
+
+ return ret;
+}
+
+static int fp9931_v3p3_is_enabled(struct regulator_dev *rdev)
+{
+ struct fp9931_data *data = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (pm_runtime_status_suspended(data->dev))
+ return 0;
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return 0;
+
+ ret = regulator_is_enabled_regmap(rdev);
+
+ pm_runtime_put_autosuspend(data->dev);
+ return ret;
+}
+
+static const struct regulator_ops fp9931_v3p3ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = fp9931_v3p3_enable,
+ .disable = fp9931_v3p3_disable,
+ .is_enabled = fp9931_v3p3_is_enabled,
+};
+
+static int fp9931_check_powergood(struct regulator_dev *rdev)
+{
+ struct fp9931_data *data = rdev_get_drvdata(rdev);
+
+ if (pm_runtime_status_suspended(data->dev))
+ return 0;
+
+ return gpiod_get_value_cansleep(data->pgood_gpio);
+}
+
+static int fp9931_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct fp9931_data *data = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_get_voltage_sel_regmap(rdev);
+ pm_runtime_put_autosuspend(data->dev);
+
+ return ret;
+}
+
+static int fp9931_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
+{
+ struct fp9931_data *data = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_set_voltage_sel_regmap(rdev, selector);
+ pm_runtime_put_autosuspend(data->dev);
+
+ return ret;
+}
+
+static irqreturn_t pgood_handler(int irq, void *dev_id)
+{
+ struct fp9931_data *data = dev_id;
+
+ complete(&data->pgood_completion);
+
+ return IRQ_HANDLED;
+}
+
+static int fp9931_set_enable(struct regulator_dev *rdev)
+{
+ struct fp9931_data *data = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
+ reinit_completion(&data->pgood_completion);
+ gpiod_set_value_cansleep(data->en_gpio, 1);
+ dev_dbg(data->dev, "turning on...");
+ wait_for_completion_timeout(&data->pgood_completion,
+ msecs_to_jiffies(PGOOD_TIMEOUT_MSECS));
+ dev_dbg(data->dev, "turned on");
+ if (gpiod_get_value_cansleep(data->pgood_gpio) != 1) {
+ pm_runtime_put_autosuspend(data->dev);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int fp9931_clear_enable(struct regulator_dev *rdev)
+{
+ struct fp9931_data *data = rdev_get_drvdata(rdev);
+
+ gpiod_set_value_cansleep(data->en_gpio, 0);
+ pm_runtime_put_autosuspend(data->dev);
+ return 0;
+}
+
+static const struct regulator_ops fp9931_vcom_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .enable = fp9931_set_enable,
+ .disable = fp9931_clear_enable,
+ .is_enabled = fp9931_check_powergood,
+ .set_voltage_sel = fp9931_set_voltage_sel,
+ .get_voltage_sel = fp9931_get_voltage_sel,
+};
+
+static const struct regulator_ops fp9931_vposneg_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ /* gets enabled by enabling vcom, too */
+ .is_enabled = fp9931_check_powergood,
+ .set_voltage_sel = fp9931_set_voltage_sel,
+ .get_voltage_sel = fp9931_get_voltage_sel,
+};
+
+static const struct regulator_desc regulators[] = {
+ {
+ .name = "v3p3",
+ .of_match = of_match_ptr("v3p3"),
+ .id = 0,
+ .ops = &fp9931_v3p3ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = FP9931_REG_CONTROL_REG1,
+ .enable_mask = BIT(1),
+ .n_voltages = 1,
+ .min_uV = 3300000
+ },
+ {
+ .name = "vposneg",
+ .of_match = of_match_ptr("vposneg"),
+ .id = 1,
+ .ops = &fp9931_vposneg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(VPOSNEG_table),
+ .vsel_reg = FP9931_REG_VPOSNEG_SETTING,
+ .vsel_mask = 0x3F,
+ .volt_table = VPOSNEG_table,
+ },
+ {
+ .name = "vcom",
+ .of_match = of_match_ptr("vcom"),
+ .id = 2,
+ .ops = &fp9931_vcom_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = 255,
+ .min_uV = 0,
+ .uV_step = 5000000 / 255,
+ .vsel_reg = FP9931_REG_VCOM_SETTING,
+ .vsel_mask = 0xFF
+ },
+};
+
+static int fp9931_probe(struct i2c_client *client)
+{
+ struct fp9931_data *data;
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+ int ret = 0;
+ int i;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ data->regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
+ "failed to allocate regmap!\n");
+
+ data->vin_reg = devm_regulator_get_optional(&client->dev, "vin");
+ if (IS_ERR(data->vin_reg))
+ return dev_err_probe(&client->dev, PTR_ERR(data->vin_reg),
+ "failed to get vin regulator\n");
+
+ data->pgood_gpio = devm_gpiod_get(&client->dev, "pg", GPIOD_IN);
+ if (IS_ERR(data->pgood_gpio))
+ return dev_err_probe(&client->dev,
+ PTR_ERR(data->pgood_gpio),
+ "failed to get power good gpio\n");
+
+ data->pgood_irq = gpiod_to_irq(data->pgood_gpio);
+ if (data->pgood_irq < 0)
+ return data->pgood_irq;
+
+ data->en_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(data->en_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(data->en_gpio),
+ "failed to get en gpio\n");
+
+ data->en_ts_gpio = devm_gpiod_get_optional(&client->dev, "en-ts", GPIOD_OUT_LOW);
+ if (IS_ERR(data->en_ts_gpio))
+ return dev_err_probe(&client->dev,
+ PTR_ERR(data->en_ts_gpio),
+ "failed to get en gpio\n");
+
+ data->dev = &client->dev;
+ i2c_set_clientdata(client, data);
+
+ init_completion(&data->pgood_completion);
+
+ ret = devm_request_threaded_irq(&client->dev, data->pgood_irq, NULL,
+ pgood_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "PGOOD", data);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "failed to request irq\n");
+
+ if (IS_ENABLED(CONFIG_PM)) {
+ devm_pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev, 4000);
+ pm_runtime_use_autosuspend(&client->dev);
+ } else {
+ ret = fp9931_runtime_resume(&client->dev);
+ if (ret < 0)
+ return ret;
+
+ devm_add_action_or_reset(&client->dev, disable_nopm, data);
+ }
+
+ ret = setup_timings(data);
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "failed to setup timings\n");
+
+ config.driver_data = data;
+ config.dev = &client->dev;
+ config.regmap = data->regmap;
+
+ for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+ rdev = devm_regulator_register(&client->dev, &regulators[i],
+ &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(&client->dev, PTR_ERR(rdev),
+ "failed to register %s regulator\n",
+ regulators[i].name);
+ }
+
+ if (IS_REACHABLE(CONFIG_HWMON)) {
+ struct device *hwmon_dev;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, "fp9931", data,
+ &fp9931_chip_info, NULL);
+ if (IS_ERR(hwmon_dev))
+ dev_notice(&client->dev, "failed to register hwmon\n");
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops fp9931_pm_ops = {
+ SET_RUNTIME_PM_OPS(fp9931_runtime_suspend, fp9931_runtime_resume, NULL)
+};
+
+static const struct of_device_id fp9931_dt_ids[] = {
+ {
+ .compatible = "fitipower,fp9931",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, fp9931_dt_ids);
+
+static struct i2c_driver fp9931_i2c_driver = {
+ .driver = {
+ .name = "fp9931",
+ .of_match_table = fp9931_dt_ids,
+ .pm = &fp9931_pm_ops,
+ },
+ .probe = fp9931_probe,
+};
+
+module_i2c_driver(fp9931_i2c_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("FP9931 regulator driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index 65927fa2ef16..6351ceefdb3e 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -240,7 +240,7 @@ static int gpio_regulator_probe(struct platform_device *pdev)
struct regulator_config cfg = { };
struct regulator_dev *rdev;
enum gpiod_flags gflags;
- int ptr, ret, state, i;
+ int ptr, state, i;
drvdata = devm_kzalloc(dev, sizeof(struct gpio_regulator_data),
GFP_KERNEL);
@@ -260,8 +260,10 @@ static int gpio_regulator_probe(struct platform_device *pdev)
return -ENOMEM;
}
- drvdata->gpiods = devm_kzalloc(dev, sizeof(struct gpio_desc *),
- GFP_KERNEL);
+ drvdata->gpiods = devm_kcalloc(dev, config->ngpios,
+ sizeof(struct gpio_desc *), GFP_KERNEL);
+ if (!drvdata->gpiods)
+ return -ENOMEM;
if (config->input_supply) {
drvdata->desc.supply_name = devm_kstrdup(&pdev->dev,
@@ -274,8 +276,6 @@ static int gpio_regulator_probe(struct platform_device *pdev)
}
}
- if (!drvdata->gpiods)
- return -ENOMEM;
for (i = 0; i < config->ngpios; i++) {
drvdata->gpiods[i] = devm_gpiod_get_index(dev,
NULL,
@@ -345,11 +345,9 @@ static int gpio_regulator_probe(struct platform_device *pdev)
return PTR_ERR(cfg.ena_gpiod);
rdev = devm_regulator_register(dev, &drvdata->desc, &cfg);
- if (IS_ERR(rdev)) {
- ret = PTR_ERR(rdev);
- dev_err(dev, "Failed to register regulator: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "Failed to register regulator\n");
platform_set_drvdata(pdev, drvdata);
diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c
index 69d24728d6a4..cd06030c3587 100644
--- a/drivers/regulator/hi6421-regulator.c
+++ b/drivers/regulator/hi6421-regulator.c
@@ -387,7 +387,7 @@ static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev)
const struct hi6421_regulator_info *info;
unsigned int reg_val;
- info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
+ info = container_of_const(rdev->desc, struct hi6421_regulator_info, desc);
regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
if (reg_val & info->mode_mask)
return REGULATOR_MODE_IDLE;
@@ -400,7 +400,7 @@ static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev)
const struct hi6421_regulator_info *info;
unsigned int reg_val;
- info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
+ info = container_of_const(rdev->desc, struct hi6421_regulator_info, desc);
regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
if (reg_val & info->mode_mask)
return REGULATOR_MODE_STANDBY;
@@ -414,7 +414,7 @@ static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev,
const struct hi6421_regulator_info *info;
unsigned int new_mode;
- info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
+ info = container_of_const(rdev->desc, struct hi6421_regulator_info, desc);
switch (mode) {
case REGULATOR_MODE_NORMAL:
new_mode = 0;
@@ -439,7 +439,7 @@ static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev,
const struct hi6421_regulator_info *info;
unsigned int new_mode;
- info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
+ info = container_of_const(rdev->desc, struct hi6421_regulator_info, desc);
switch (mode) {
case REGULATOR_MODE_NORMAL:
new_mode = 0;
@@ -464,7 +464,7 @@ hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev,
{
const struct hi6421_regulator_info *info;
- info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
+ info = container_of_const(rdev->desc, struct hi6421_regulator_info, desc);
if (load_uA > info->eco_microamp)
return REGULATOR_MODE_NORMAL;
diff --git a/drivers/regulator/hi6421v530-regulator.c b/drivers/regulator/hi6421v530-regulator.c
index b3ebd1624814..1822f5daf6ce 100644
--- a/drivers/regulator/hi6421v530-regulator.c
+++ b/drivers/regulator/hi6421v530-regulator.c
@@ -110,7 +110,7 @@ static unsigned int hi6421v530_regulator_ldo_get_mode(
const struct hi6421v530_regulator_info *info;
unsigned int reg_val;
- info = container_of(rdev->desc, struct hi6421v530_regulator_info, rdesc);
+ info = container_of_const(rdev->desc, struct hi6421v530_regulator_info, rdesc);
regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
if (reg_val & (info->mode_mask))
@@ -125,7 +125,7 @@ static int hi6421v530_regulator_ldo_set_mode(struct regulator_dev *rdev,
const struct hi6421v530_regulator_info *info;
unsigned int new_mode;
- info = container_of(rdev->desc, struct hi6421v530_regulator_info, rdesc);
+ info = container_of_const(rdev->desc, struct hi6421v530_regulator_info, rdesc);
switch (mode) {
case REGULATOR_MODE_NORMAL:
new_mode = 0;
diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index e5f6fbfc9016..e7c8bc10cf24 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -121,7 +121,7 @@ static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
const struct hi6421_spmi_reg_info *sreg;
unsigned int reg_val;
- sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc);
+ sreg = container_of_const(rdev->desc, struct hi6421_spmi_reg_info, desc);
regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
if (reg_val & sreg->eco_mode_mask)
@@ -136,7 +136,7 @@ static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
const struct hi6421_spmi_reg_info *sreg;
unsigned int val;
- sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc);
+ sreg = container_of_const(rdev->desc, struct hi6421_spmi_reg_info, desc);
switch (mode) {
case REGULATOR_MODE_NORMAL:
val = 0;
@@ -162,7 +162,7 @@ hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev,
{
const struct hi6421_spmi_reg_info *sreg;
- sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc);
+ sreg = container_of_const(rdev->desc, struct hi6421_spmi_reg_info, desc);
if (!sreg->eco_uA || ((unsigned int)load_uA > sreg->eco_uA))
return REGULATOR_MODE_NORMAL;
diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c
index 0aa188b2bbb2..5b3cfac28667 100644
--- a/drivers/regulator/irq_helpers.c
+++ b/drivers/regulator/irq_helpers.c
@@ -64,16 +64,16 @@ static void regulator_notifier_isr_work(struct work_struct *work)
reread:
if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
if (!d->die)
- return hw_protection_shutdown("Regulator HW failure? - no IC recovery",
- REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+ return hw_protection_trigger("Regulator HW failure? - no IC recovery",
+ REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
ret = d->die(rid);
/*
* If the 'last resort' IC recovery failed we will have
* nothing else left to do...
*/
if (ret)
- return hw_protection_shutdown("Regulator HW failure. IC recovery failed",
- REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+ return hw_protection_trigger("Regulator HW failure. IC recovery failed",
+ REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
/*
* If h->die() was implemented we assume recovery has been
@@ -146,7 +146,7 @@ enable_out:
reschedule:
if (!d->high_prio)
- mod_delayed_work(system_wq, &h->isr_work,
+ mod_delayed_work(system_dfl_wq, &h->isr_work,
msecs_to_jiffies(tmo));
else
mod_delayed_work(system_highpri_wq, &h->isr_work,
@@ -263,14 +263,14 @@ fail_out:
if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
/* If we have no recovery, just try shut down straight away */
if (!d->die) {
- hw_protection_shutdown("Regulator failure. Retry count exceeded",
- REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+ hw_protection_trigger("Regulator failure. Retry count exceeded",
+ REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
} else {
ret = d->die(rid);
/* If die() failed shut down as a last attempt to save the HW */
if (ret)
- hw_protection_shutdown("Regulator failure. Recovery failed",
- REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+ hw_protection_trigger("Regulator failure. Recovery failed",
+ REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
}
}
diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c
index 5e7171b9065a..41fd15adfd1f 100644
--- a/drivers/regulator/max14577-regulator.c
+++ b/drivers/regulator/max14577-regulator.c
@@ -40,11 +40,14 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
struct max14577 *max14577 = rdev_get_drvdata(rdev);
const struct maxim_charger_current *limits =
&maxim_charger_currents[max14577->dev_type];
+ int ret;
if (rdev_get_id(rdev) != MAX14577_CHARGER)
return -EINVAL;
- max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, &reg_data);
+ ret = max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, &reg_data);
+ if (ret < 0)
+ return ret;
if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0)
return limits->min;
diff --git a/drivers/regulator/max20086-regulator.c b/drivers/regulator/max20086-regulator.c
index 59eb23d467ec..fcdd2d0317a5 100644
--- a/drivers/regulator/max20086-regulator.c
+++ b/drivers/regulator/max20086-regulator.c
@@ -5,6 +5,7 @@
// Copyright (C) 2022 Laurent Pinchart <laurent.pinchart@idesonboard.com>
// Copyright (C) 2018 Avnet, Inc.
+#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
@@ -28,7 +29,7 @@
#define MAX20086_REG_ADC4 0x09
/* DEVICE IDs */
-#define MAX20086_DEVICE_ID_MAX20086 0x40
+#define MAX20086_DEVICE_ID_MAX20086 0x30
#define MAX20086_DEVICE_ID_MAX20087 0x20
#define MAX20086_DEVICE_ID_MAX20088 0x10
#define MAX20086_DEVICE_ID_MAX20089 0x00
@@ -132,23 +133,27 @@ static int max20086_regulators_register(struct max20086 *chip)
static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on)
{
- struct of_regulator_match matches[MAX20086_MAX_REGULATORS] = { };
- struct device_node *node;
+ struct of_regulator_match *matches;
unsigned int i;
int ret;
- node = of_get_child_by_name(chip->dev->of_node, "regulators");
+ struct device_node *node __free(device_node) =
+ of_get_child_by_name(chip->dev->of_node, "regulators");
if (!node) {
dev_err(chip->dev, "regulators node not found\n");
return -ENODEV;
}
+ matches = devm_kcalloc(chip->dev, chip->info->num_outputs,
+ sizeof(*matches), GFP_KERNEL);
+ if (!matches)
+ return -ENOMEM;
+
for (i = 0; i < chip->info->num_outputs; ++i)
matches[i].name = max20086_output_names[i];
ret = of_regulator_match(chip->dev, node, matches,
chip->info->num_outputs);
- of_node_put(node);
if (ret < 0) {
dev_err(chip->dev, "Failed to match regulators\n");
return -EINVAL;
@@ -259,7 +264,7 @@ static int max20086_i2c_probe(struct i2c_client *i2c)
* shutdown.
*/
flags = boot_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
- chip->ena_gpiod = devm_gpiod_get(chip->dev, "enable", flags);
+ chip->ena_gpiod = devm_gpiod_get_optional(chip->dev, "enable", flags);
if (IS_ERR(chip->ena_gpiod)) {
ret = PTR_ERR(chip->ena_gpiod);
dev_err(chip->dev, "Failed to get enable GPIO: %d\n", ret);
diff --git a/drivers/regulator/max77650-regulator.c b/drivers/regulator/max77650-regulator.c
index 7368f54f046d..a809264c77fc 100644
--- a/drivers/regulator/max77650-regulator.c
+++ b/drivers/regulator/max77650-regulator.c
@@ -68,7 +68,7 @@ static int max77650_regulator_is_enabled(struct regulator_dev *rdev)
struct regmap *map;
int val, rv, en;
- rdesc = container_of(rdev->desc, struct max77650_regulator_desc, desc);
+ rdesc = container_of_const(rdev->desc, struct max77650_regulator_desc, desc);
map = rdev_get_regmap(rdev);
rv = regmap_read(map, rdesc->regB, &val);
@@ -85,7 +85,7 @@ static int max77650_regulator_enable(struct regulator_dev *rdev)
const struct max77650_regulator_desc *rdesc;
struct regmap *map;
- rdesc = container_of(rdev->desc, struct max77650_regulator_desc, desc);
+ rdesc = container_of_const(rdev->desc, struct max77650_regulator_desc, desc);
map = rdev_get_regmap(rdev);
return regmap_update_bits(map, rdesc->regB,
@@ -98,7 +98,7 @@ static int max77650_regulator_disable(struct regulator_dev *rdev)
const struct max77650_regulator_desc *rdesc;
struct regmap *map;
- rdesc = container_of(rdev->desc, struct max77650_regulator_desc, desc);
+ rdesc = container_of_const(rdev->desc, struct max77650_regulator_desc, desc);
map = rdev_get_regmap(rdev);
return regmap_update_bits(map, rdesc->regB,
diff --git a/drivers/regulator/max77838-regulator.c b/drivers/regulator/max77838-regulator.c
new file mode 100644
index 000000000000..9faddbfd25fd
--- /dev/null
+++ b/drivers/regulator/max77838-regulator.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// regulator driver for Maxim MAX77838
+//
+// based on max77826-regulator.c
+//
+// Copyright (c) 2025, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+enum max77838_registers {
+ MAX77838_REG_DEVICE_ID = 0x00,
+ MAX77838_REG_TOPSYS_STAT,
+ MAX77838_REG_STAT,
+ MAX77838_REG_EN,
+ MAX77838_REG_GPIO_PD_CTRL,
+ MAX77838_REG_UVLO_CFG1,
+ /* 0x06 - 0x0B: reserved */
+ MAX77838_REG_I2C_CFG = 0x0C,
+ /* 0x0D - 0x0F: reserved */
+ MAX77838_REG_LDO1_CFG = 0x10,
+ MAX77838_REG_LDO2_CFG,
+ MAX77838_REG_LDO3_CFG,
+ MAX77838_REG_LDO4_CFG,
+ /* 0x14 - 0x1F: reserved */
+ MAX77838_REG_BUCK_CFG1 = 0x20,
+ MAX77838_REG_BUCK_VOUT,
+};
+
+enum max77838_regulators {
+ MAX77838_LDO1 = 0,
+ MAX77838_LDO2,
+ MAX77838_LDO3,
+ MAX77838_LDO4,
+ MAX77838_BUCK,
+ MAX77838_MAX_REGULATORS,
+};
+
+#define MAX77838_MASK_LDO 0x7f
+#define MAX77838_MASK_BUCK 0xff
+
+#define MAX77838_LDO1_EN BIT(0)
+#define MAX77838_LDO2_EN BIT(1)
+#define MAX77838_LDO3_EN BIT(2)
+#define MAX77838_LDO4_EN BIT(3)
+#define MAX77838_BUCK_EN BIT(4)
+
+#define MAX77838_BUCK_AD BIT(3)
+#define MAX77838_LDO_AD BIT(7)
+
+#define MAX77838_LDO_VOLT_MIN 600000
+#define MAX77838_LDO_VOLT_MAX 3775000
+#define MAX77838_LDO_VOLT_STEP 25000
+
+#define MAX77838_BUCK_VOLT_MIN 500000
+#define MAX77838_BUCK_VOLT_MAX 2093750
+#define MAX77838_BUCK_VOLT_STEP 6250
+
+#define MAX77838_VOLT_RANGE(_type) \
+ ((MAX77838_ ## _type ## _VOLT_MAX - \
+ MAX77838_ ## _type ## _VOLT_MIN) / \
+ MAX77838_ ## _type ## _VOLT_STEP + 1)
+
+#define MAX77838_LDO(_id) \
+ [MAX77838_LDO ## _id] = { \
+ .id = MAX77838_LDO ## _id, \
+ .name = "ldo"#_id, \
+ .of_match = of_match_ptr("ldo"#_id), \
+ .regulators_node = "regulators", \
+ .ops = &max77838_regulator_ops, \
+ .min_uV = MAX77838_LDO_VOLT_MIN, \
+ .uV_step = MAX77838_LDO_VOLT_STEP, \
+ .n_voltages = MAX77838_VOLT_RANGE(LDO), \
+ .enable_reg = MAX77838_REG_EN, \
+ .enable_mask = MAX77838_LDO ## _id ## _EN, \
+ .vsel_reg = MAX77838_REG_LDO ## _id ## _CFG, \
+ .vsel_mask = MAX77838_MASK_LDO, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = MAX77838_LDO_AD, \
+ .active_discharge_mask = MAX77838_LDO_AD, \
+ .active_discharge_reg = MAX77838_REG_LDO ## _id ## _CFG, \
+ .owner = THIS_MODULE, \
+ }
+
+#define MAX77838_BUCK_DESC \
+ [MAX77838_BUCK] = { \
+ .id = MAX77838_BUCK, \
+ .name = "buck", \
+ .of_match = of_match_ptr("buck"), \
+ .regulators_node = "regulators", \
+ .ops = &max77838_regulator_ops, \
+ .min_uV = MAX77838_BUCK_VOLT_MIN, \
+ .uV_step = MAX77838_BUCK_VOLT_STEP, \
+ .n_voltages = MAX77838_VOLT_RANGE(BUCK), \
+ .enable_reg = MAX77838_REG_EN, \
+ .enable_mask = MAX77838_BUCK_EN, \
+ .vsel_reg = MAX77838_REG_BUCK_VOUT, \
+ .vsel_mask = MAX77838_MASK_BUCK, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = MAX77838_BUCK_AD, \
+ .active_discharge_mask = MAX77838_BUCK_AD, \
+ .active_discharge_reg = MAX77838_REG_BUCK_CFG1, \
+ .owner = THIS_MODULE, \
+ }
+
+struct max77838_regulator_info {
+ struct regmap *regmap;
+};
+
+static const struct regmap_config max77838_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX77838_REG_BUCK_VOUT,
+};
+
+static const struct regulator_ops max77838_regulator_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_desc max77838_regulators_desc[] = {
+ MAX77838_LDO(1),
+ MAX77838_LDO(2),
+ MAX77838_LDO(3),
+ MAX77838_LDO(4),
+ MAX77838_BUCK_DESC,
+};
+
+static int max77838_read_device_id(struct regmap *regmap, struct device *dev)
+{
+ unsigned int device_id;
+ int ret;
+
+ ret = regmap_read(regmap, MAX77838_REG_DEVICE_ID, &device_id);
+ if (!ret)
+ dev_dbg(dev, "DEVICE_ID: 0x%x\n", device_id);
+
+ return ret;
+}
+
+static int max77838_i2c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct max77838_regulator_info *info;
+ struct regulator_config config = {};
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ int i;
+
+ info = devm_kzalloc(dev, sizeof(struct max77838_regulator_info),
+ GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &max77838_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "Failed to allocate regmap!\n");
+ return PTR_ERR(regmap);
+ }
+
+ info->regmap = regmap;
+ i2c_set_clientdata(client, info);
+
+ config.dev = dev;
+ config.regmap = regmap;
+ config.driver_data = info;
+
+ for (i = 0; i < MAX77838_MAX_REGULATORS; i++) {
+ rdev = devm_regulator_register(dev,
+ &max77838_regulators_desc[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(dev, "Failed to register regulator!\n");
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return max77838_read_device_id(regmap, dev);
+}
+
+static const struct of_device_id __maybe_unused max77838_of_match[] = {
+ { .compatible = "maxim,max77838" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, max77838_of_match);
+
+static const struct i2c_device_id max77838_id[] = {
+ { "max77838-regulator" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, max77838_id);
+
+static struct i2c_driver max77838_regulator_driver = {
+ .driver = {
+ .name = "max77838",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = of_match_ptr(max77838_of_match),
+ },
+ .probe = max77838_i2c_probe,
+ .id_table = max77838_id,
+};
+module_i2c_driver(max77838_regulator_driver);
+
+MODULE_AUTHOR("Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>");
+MODULE_DESCRIPTION("MAX77838 PMIC regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c
index 48dcee5287f3..9ad16b04c913 100644
--- a/drivers/regulator/mp886x.c
+++ b/drivers/regulator/mp886x.c
@@ -348,7 +348,8 @@ static const struct of_device_id mp886x_dt_ids[] = {
MODULE_DEVICE_TABLE(of, mp886x_dt_ids);
static const struct i2c_device_id mp886x_id[] = {
- { "mp886x", (kernel_ulong_t)&mp8869_ci },
+ { "mp8867", (kernel_ulong_t)&mp8867_ci },
+ { "mp8869", (kernel_ulong_t)&mp8869_ci },
{ },
};
MODULE_DEVICE_TABLE(i2c, mp886x_id);
diff --git a/drivers/regulator/mt6315-regulator.c b/drivers/regulator/mt6315-regulator.c
index 2608a6652d77..d3f93aae0fc5 100644
--- a/drivers/regulator/mt6315-regulator.c
+++ b/drivers/regulator/mt6315-regulator.c
@@ -80,7 +80,7 @@ static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev)
int ret, regval;
u32 modeset_mask;
- info = container_of(rdev->desc, struct mt6315_regulator_info, desc);
+ info = container_of_const(rdev->desc, struct mt6315_regulator_info, desc);
modeset_mask = init->modeset_mask[rdev_get_id(rdev)];
ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_4PHASE_ANA_CON42, &regval);
if (ret != 0) {
@@ -111,7 +111,7 @@ static int mt6315_regulator_set_mode(struct regulator_dev *rdev,
int ret, val, curr_mode;
u32 modeset_mask;
- info = container_of(rdev->desc, struct mt6315_regulator_info, desc);
+ info = container_of_const(rdev->desc, struct mt6315_regulator_info, desc);
modeset_mask = init->modeset_mask[rdev_get_id(rdev)];
curr_mode = mt6315_regulator_get_mode(rdev);
switch (mode) {
@@ -165,7 +165,7 @@ static int mt6315_get_status(struct regulator_dev *rdev)
int ret;
u32 regval;
- info = container_of(rdev->desc, struct mt6315_regulator_info, desc);
+ info = container_of_const(rdev->desc, struct mt6315_regulator_info, desc);
ret = regmap_read(rdev->regmap, info->status_reg, &regval);
if (ret < 0) {
dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
diff --git a/drivers/regulator/mt6316-regulator.c b/drivers/regulator/mt6316-regulator.c
new file mode 100644
index 000000000000..952852bbe923
--- /dev/null
+++ b/drivers/regulator/mt6316-regulator.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+// Copyright (c) 2025 Collabora Ltd
+// AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6316_BUCK_MODE_AUTO 0
+#define MT6316_BUCK_MODE_FORCE_PWM 1
+#define MT6316_BUCK_MODE_LP 2
+
+#define MT6316_CHIP_ID 0x20b
+#define MT6316_BUCK_TOP_CON0 0x1440
+#define EN_SET_OFFSET 0x1
+#define EN_CLR_OFFSET 0x2
+
+#define MT6316_BUCK_TOP_CON1 0x1443
+
+#define MT6316_BUCK_TOP_ELR0 0x1448
+#define MT6316_BUCK_TOP_ELR2 0x144a
+#define MT6316_BUCK_TOP_ELR4 0x144c
+#define MT6316_BUCK_TOP_ELR6 0x144e
+#define MT6316_VSEL_MASK GENMASK(8, 0)
+
+#define MT6316_VBUCK1_DBG 0x14a8
+#define MT6316_VBUCK2_DBG 0x1528
+#define MT6316_VBUCK3_DBG 0x15a8
+#define MT6316_VBUCK4_DBG 0x1628
+#define MT6316_BUCK_QI BIT(0)
+
+#define MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0 0x1688
+#define MT6316_BUCK_TOP_4PHASE_TOP_ELR_0 0x1690
+
+enum mt6316_type {
+ MT6316_TYPE_2PHASE,
+ MT6316_TYPE_3PHASE,
+ MT6316_TYPE_4PHASE
+};
+
+/**
+ * struct mt6316_regulator_info - MT6316 regulators information
+ * @desc: Regulator description structure
+ * @debug_reg: Debug register for regulator status
+ * @lp_mode_reg: Low Power mode register (normal/idle)
+ * @lp_mode_mask: Low Power mode regulator mask
+ * @modeset_reg: AUTO/PWM mode register
+ * @modeset_mask: AUTO/PWM regulator mask
+ */
+struct mt6316_regulator_info {
+ struct regulator_desc desc;
+ u16 debug_reg;
+ u16 lp_mode_reg;
+ u16 lp_mode_mask;
+ u16 modeset_reg;
+ u16 modeset_mask;
+};
+
+#define MT6316_BUCK(match, vreg_id, min, max, step, vs_reg) \
+{ \
+ .desc = { \
+ .name = match, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6316_vreg_setclr_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .n_voltages = (max - min) / step + 1, \
+ .min_uV = min, \
+ .uV_step = step, \
+ .enable_reg = MT6316_BUCK_TOP_CON0, \
+ .enable_mask = BIT(vreg_id - 1), \
+ .vsel_reg = vs_reg, \
+ .vsel_mask = MT6316_VSEL_MASK, \
+ .of_map_mode = mt6316_map_mode, \
+ }, \
+ .lp_mode_reg = MT6316_BUCK_TOP_CON1, \
+ .lp_mode_mask = BIT(vreg_id - 1), \
+ .modeset_reg = MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0, \
+ .modeset_mask = BIT(vreg_id - 1), \
+ .debug_reg = MT6316_VBUCK##vreg_id##_DBG, \
+}
+
+/* Values in some MT6316 registers are big endian, 9 bits long... */
+static inline u16 mt6316_be9_to_cpu(u16 val)
+{
+ return ((val >> 8) & BIT(0)) | ((val & GENMASK(7, 0)) << 1);
+}
+
+static inline u16 mt6316_cpu_to_be9(u16 val)
+{
+ return ((val & BIT(0)) << 8) | (val >> 1);
+}
+
+static unsigned int mt6316_map_mode(u32 mode)
+{
+ switch (mode) {
+ case MT6316_BUCK_MODE_AUTO:
+ return REGULATOR_MODE_NORMAL;
+ case MT6316_BUCK_MODE_FORCE_PWM:
+ return REGULATOR_MODE_FAST;
+ case MT6316_BUCK_MODE_LP:
+ return REGULATOR_MODE_IDLE;
+ default:
+ return REGULATOR_MODE_INVALID;
+ }
+}
+
+static int mt6316_vreg_enable_setclr(struct regulator_dev *rdev)
+{
+ return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_SET_OFFSET,
+ rdev->desc->enable_mask);
+}
+
+static int mt6316_vreg_disable_setclr(struct regulator_dev *rdev)
+{
+ return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_CLR_OFFSET,
+ rdev->desc->enable_mask);
+}
+
+static int mt6316_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
+{
+ u16 val = mt6316_cpu_to_be9(selector);
+
+ return regmap_bulk_write(rdev->regmap, rdev->desc->vsel_reg, &val, sizeof(val));
+}
+
+static int mt6316_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+ u16 val;
+ int ret;
+
+ ret = regmap_bulk_read(rdev->regmap, rdev->desc->vsel_reg, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ return mt6316_be9_to_cpu(val & rdev->desc->vsel_mask);
+}
+
+static int mt6316_regulator_get_status(struct regulator_dev *rdev)
+{
+ struct mt6316_regulator_info *info = rdev_get_drvdata(rdev);
+ u32 val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, info->debug_reg, &val);
+ if (ret)
+ return ret;
+
+ return val & MT6316_BUCK_QI ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static unsigned int mt6316_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct mt6316_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to get mode: %d\n", ret);
+ return ret;
+ }
+
+ if ((val & info->modeset_mask) == info->modeset_mask)
+ return REGULATOR_MODE_FAST;
+
+ ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val);
+ val &= info->lp_mode_mask;
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
+ return ret;
+ }
+
+ return val ? REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL;
+}
+
+static int mt6316_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct mt6316_regulator_info *info = rdev_get_drvdata(rdev);
+ struct regmap *regmap = rdev->regmap;
+ int cur_mode, ret;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ ret = regmap_set_bits(regmap, info->modeset_reg, info->modeset_mask);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ cur_mode = mt6316_regulator_get_mode(rdev);
+ if (cur_mode < 0) {
+ ret = cur_mode;
+ break;
+ }
+
+ if (cur_mode == REGULATOR_MODE_FAST) {
+ ret = regmap_clear_bits(regmap, info->modeset_reg, info->modeset_mask);
+ break;
+ } else if (cur_mode == REGULATOR_MODE_IDLE) {
+ ret = regmap_clear_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+ if (ret == 0)
+ usleep_range(100, 200);
+ } else {
+ ret = 0;
+ }
+ break;
+ case REGULATOR_MODE_IDLE:
+ ret = regmap_set_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to set mode %u: %d\n", mode, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct regulator_ops mt6316_vreg_setclr_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_sel = mt6316_regulator_set_voltage_sel,
+ .get_voltage_sel = mt6316_regulator_get_voltage_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = mt6316_vreg_enable_setclr,
+ .disable = mt6316_vreg_disable_setclr,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6316_regulator_get_status,
+ .set_mode = mt6316_regulator_set_mode,
+ .get_mode = mt6316_regulator_get_mode,
+};
+
+/* MT6316BP/VP - 2+2 phase buck */
+static struct mt6316_regulator_info mt6316bv_regulators[] = {
+ MT6316_BUCK("vbuck12", 1, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR0),
+ MT6316_BUCK("vbuck34", 3, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR4),
+};
+
+/* MT6316CP/HP/KP - 3+1 phase buck */
+static struct mt6316_regulator_info mt6316chk_regulators[] = {
+ MT6316_BUCK("vbuck124", 1, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR0),
+ MT6316_BUCK("vbuck3", 3, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR4),
+};
+
+/* MT6316DP/TP - 4 phase buck */
+static struct mt6316_regulator_info mt6316dt_regulators[] = {
+ MT6316_BUCK("vbuck1234", 1, 0, 1277500, 2500, MT6316_BUCK_TOP_ELR0),
+};
+
+static const struct regmap_config mt6316_spmi_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0x1700,
+ .fast_io = true,
+};
+
+static int mt6316_regulator_probe(struct spmi_device *sdev)
+{
+ struct regulator_config config = {};
+ struct mt6316_regulator_info *info;
+ struct regulator_dev *rdev;
+ enum mt6316_type type;
+ int num_vregs, ret;
+ unsigned int i;
+ u32 chip_id;
+
+ config.regmap = devm_regmap_init_spmi_ext(sdev, &mt6316_spmi_regmap_config);
+ if (IS_ERR(config.regmap))
+ return PTR_ERR(config.regmap);
+
+ /*
+ * The first read is expected to fail: this PMIC needs to be woken up
+ * and that can be done with any activity over the SPMI bus.
+ */
+ regmap_read(config.regmap, MT6316_CHIP_ID, &chip_id);
+
+ /* The second read, instead, shall not fail! */
+ ret = regmap_read(config.regmap, MT6316_CHIP_ID, &chip_id);
+ if (ret) {
+ dev_err(&sdev->dev, "Cannot read Chip ID!\n");
+ return ret;
+ }
+ dev_dbg(&sdev->dev, "Chip ID: 0x%x\n", chip_id);
+
+ config.dev = &sdev->dev;
+
+ type = (uintptr_t)device_get_match_data(&sdev->dev);
+ switch (type) {
+ case MT6316_TYPE_2PHASE:
+ info = mt6316bv_regulators;
+ num_vregs = ARRAY_SIZE(mt6316bv_regulators);
+ break;
+ case MT6316_TYPE_3PHASE:
+ info = mt6316chk_regulators;
+ num_vregs = ARRAY_SIZE(mt6316chk_regulators);
+ break;
+ case MT6316_TYPE_4PHASE:
+ info = mt6316dt_regulators;
+ num_vregs = ARRAY_SIZE(mt6316dt_regulators);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_vregs; i++) {
+ config.driver_data = &info[i];
+
+ rdev = devm_regulator_register(&sdev->dev, &info[i].desc, &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(&sdev->dev, PTR_ERR(rdev),
+ "failed to register %s\n", info[i].desc.name);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id mt6316_regulator_match[] = {
+ { .compatible = "mediatek,mt6316b-regulator", .data = (void *)MT6316_TYPE_2PHASE },
+ { .compatible = "mediatek,mt6316c-regulator", .data = (void *)MT6316_TYPE_3PHASE },
+ { .compatible = "mediatek,mt6316d-regulator", .data = (void *)MT6316_TYPE_4PHASE },
+ { /* sentinel */ }
+};
+
+static struct spmi_driver mt6316_regulator_driver = {
+ .driver = {
+ .name = "mt6316-regulator",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = mt6316_regulator_match,
+ },
+ .probe = mt6316_regulator_probe,
+};
+module_spmi_driver(mt6316_regulator_driver);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6316 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c
index e4745f616cea..2604f674be49 100644
--- a/drivers/regulator/mt6358-regulator.c
+++ b/drivers/regulator/mt6358-regulator.c
@@ -31,7 +31,7 @@ struct mt6358_regulator_info {
u32 modeset_mask;
};
-#define to_regulator_info(x) container_of((x), struct mt6358_regulator_info, desc)
+#define to_regulator_info(x) container_of_const((x), struct mt6358_regulator_info, desc)
#define MT6358_BUCK(match, vreg, supply, min, max, step, \
vosel_mask, _da_vsel_reg, _da_vsel_mask, \
diff --git a/drivers/regulator/mt6363-regulator.c b/drivers/regulator/mt6363-regulator.c
new file mode 100644
index 000000000000..e0fbf92e7685
--- /dev/null
+++ b/drivers/regulator/mt6363-regulator.c
@@ -0,0 +1,938 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+// Copyright (c) 2025 Collabora Ltd
+// AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6363-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6363_REGULATOR_MODE_NORMAL 0
+#define MT6363_REGULATOR_MODE_FCCM 1
+#define MT6363_REGULATOR_MODE_LP 2
+#define MT6363_REGULATOR_MODE_ULP 3
+
+#define EN_SET_OFFSET 0x1
+#define EN_CLR_OFFSET 0x2
+#define OP_CFG_OFFSET 0x5
+
+#define NORMAL_OP_CFG 0x10
+#define NORMAL_OP_EN 0x800000
+
+#define OC_IRQ_ENABLE_DELAY_MS 10
+
+/* Unlock keys for TMA and BUCK_TOP */
+#define MT6363_TMA_UNLOCK_VALUE 0x9c9c
+#define MT6363_BUCK_TOP_UNLOCK_VALUE 0x5543
+
+enum {
+ MT6363_ID_VBUCK1,
+ MT6363_ID_VBUCK2,
+ MT6363_ID_VBUCK3,
+ MT6363_ID_VBUCK4,
+ MT6363_ID_VBUCK5,
+ MT6363_ID_VBUCK6,
+ MT6363_ID_VBUCK7,
+ MT6363_ID_VS1,
+ MT6363_ID_VS2,
+ MT6363_ID_VS3,
+ MT6363_ID_VA12_1,
+ MT6363_ID_VA12_2,
+ MT6363_ID_VA15,
+ MT6363_ID_VAUX18,
+ MT6363_ID_VCN13,
+ MT6363_ID_VCN15,
+ MT6363_ID_VEMC,
+ MT6363_ID_VIO075,
+ MT6363_ID_VIO18,
+ MT6363_ID_VM18,
+ MT6363_ID_VSRAM_APU,
+ MT6363_ID_VSRAM_CPUB,
+ MT6363_ID_VSRAM_CPUM,
+ MT6363_ID_VSRAM_CPUL,
+ MT6363_ID_VSRAM_DIGRF,
+ MT6363_ID_VSRAM_MDFE,
+ MT6363_ID_VSRAM_MODEM,
+ MT6363_ID_VRF09,
+ MT6363_ID_VRF12,
+ MT6363_ID_VRF13,
+ MT6363_ID_VRF18,
+ MT6363_ID_VRFIO18,
+ MT6363_ID_VTREF18,
+ MT6363_ID_VUFS12,
+ MT6363_ID_VUFS18,
+};
+
+/**
+ * struct mt6363_regulator_info - MT6363 regulators information
+ * @desc: Regulator description structure
+ * @lp_mode_reg: Low Power mode register (normal/idle)
+ * @lp_mode_mask: Low Power mode regulator mask
+ * @hw_lp_mode_reg: Hardware voted Low Power mode register (normal/idle)
+ * @hw_lp_mode_mask: Hardware voted Low Power mode regulator mask
+ * @modeset_reg: AUTO/PWM mode register
+ * @modeset_mask: AUTO/PWM regulator mask
+ * @lp_imax_uA: Maximum load current (microamps), for Low Power mode only
+ * @op_en_reg: Operation mode enablement register
+ * @orig_op_en: Backup of a regulator's operation mode enablement register
+ * @orig_op_cfg: Backup of a regulator's operation mode configuration register
+ * @oc_work: Delayed work for enabling overcurrent IRQ
+ * @hwirq: PMIC-Internal HW Interrupt for overcurrent event
+ * @virq: Mapped Interrupt for overcurrent event
+ */
+struct mt6363_regulator_info {
+ struct regulator_desc desc;
+ u16 lp_mode_reg;
+ u16 lp_mode_mask;
+ u16 hw_lp_mode_reg;
+ u16 hw_lp_mode_mask;
+ u16 modeset_reg;
+ u16 modeset_mask;
+ int lp_imax_uA;
+ u16 op_en_reg;
+ u32 orig_op_en;
+ u8 orig_op_cfg;
+ struct delayed_work oc_work;
+ u8 hwirq;
+ int virq;
+};
+
+#define MT6363_BUCK(match, vreg, min, max, step, en_reg, lp_reg, \
+ mset_reg, ocp_intn) \
+[MT6363_ID_##vreg] = { \
+ .desc = { \
+ .name = match, \
+ .supply_name = "vsys-"match, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6363_vreg_setclr_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6363_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = (max - min) / step + 1, \
+ .min_uV = min, \
+ .uV_step = step, \
+ .enable_reg = en_reg, \
+ .enable_mask = BIT(MT6363_RG_BUCK_##vreg##_EN_BIT), \
+ .vsel_reg = MT6363_RG_BUCK_##vreg##_VOSEL_ADDR, \
+ .vsel_mask = MT6363_RG_BUCK_##vreg##_VOSEL_MASK, \
+ .of_map_mode = mt6363_map_mode, \
+ }, \
+ .lp_mode_reg = lp_reg, \
+ .lp_mode_mask = BIT(MT6363_RG_BUCK_##vreg##_LP_BIT), \
+ .hw_lp_mode_reg = MT6363_BUCK_##vreg##_HW_LP_MODE, \
+ .hw_lp_mode_mask = 0xc, \
+ .modeset_reg = mset_reg, \
+ .modeset_mask = BIT(MT6363_RG_##vreg##_FCCM_BIT), \
+ .lp_imax_uA = 100000, \
+ .op_en_reg = MT6363_BUCK_##vreg##_OP_EN_0, \
+ .hwirq = ocp_intn, \
+}
+
+#define MT6363_LDO_LINEAR_OPS(match, vreg, in_sup, vops, min, max, \
+ step, buck_reg, ocp_intn) \
+[MT6363_ID_##vreg] = { \
+ .desc = { \
+ .name = match, \
+ .supply_name = in_sup, \
+ .of_match = of_match_ptr(match), \
+ .ops = &vops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6363_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = (max - min) / step + 1, \
+ .min_uV = min, \
+ .uV_step = step, \
+ .enable_reg = MT6363_RG_##buck_reg##_EN_ADDR, \
+ .enable_mask = BIT(MT6363_RG_LDO_##vreg##_EN_BIT), \
+ .vsel_reg = MT6363_RG_LDO_##vreg##_VOSEL_ADDR, \
+ .vsel_mask = MT6363_RG_LDO_##vreg##_VOSEL_MASK, \
+ .of_map_mode = mt6363_map_mode, \
+ }, \
+ .lp_mode_reg = MT6363_RG_##buck_reg##_LP_ADDR, \
+ .lp_mode_mask = BIT(MT6363_RG_LDO_##vreg##_LP_BIT), \
+ .hw_lp_mode_reg = MT6363_LDO_##vreg##_HW_LP_MODE, \
+ .hw_lp_mode_mask = 0x4, \
+ .hwirq = ocp_intn, \
+}
+
+#define MT6363_LDO_L_SC(match, vreg, inp, min, max, step, buck_reg, \
+ ocp_intn) \
+ MT6363_LDO_LINEAR_OPS(match, vreg, inp, mt6363_vreg_setclr_ops, \
+ min, max, step, buck_reg, ocp_intn)
+
+#define MT6363_LDO_L(match, vreg, inp, min, max, step, buck_reg, \
+ ocp_intn) \
+ MT6363_LDO_LINEAR_OPS(match, vreg, inp, mt6363_ldo_linear_ops, \
+ min, max, step, buck_reg, ocp_intn)
+
+#define MT6363_LDO_LINEAR_CAL_OPS(match, vreg, in_sup, vops, vrnum, \
+ ocp_intn) \
+[MT6363_ID_##vreg] = { \
+ .desc = { \
+ .name = match, \
+ .supply_name = in_sup, \
+ .of_match = of_match_ptr(match), \
+ .ops = &vops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6363_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(ldo_volt_ranges##vrnum) * 11, \
+ .linear_ranges = ldo_volt_ranges##vrnum, \
+ .n_linear_ranges = ARRAY_SIZE(ldo_volt_ranges##vrnum), \
+ .linear_range_selectors_bitfield = ldos_cal_selectors, \
+ .enable_reg = MT6363_RG_LDO_##vreg##_ADDR, \
+ .enable_mask = BIT(MT6363_RG_LDO_##vreg##_EN_BIT), \
+ .vsel_reg = MT6363_RG_##vreg##_VOCAL_ADDR, \
+ .vsel_mask = MT6363_RG_##vreg##_VOCAL_MASK, \
+ .vsel_range_reg = MT6363_RG_##vreg##_VOSEL_ADDR, \
+ .vsel_range_mask = MT6363_RG_##vreg##_VOSEL_MASK, \
+ .of_map_mode = mt6363_map_mode, \
+ }, \
+ .lp_mode_reg = MT6363_RG_LDO_##vreg##_ADDR, \
+ .lp_mode_mask = BIT(MT6363_RG_LDO_##vreg##_LP_BIT), \
+ .hw_lp_mode_reg = MT6363_LDO_##vreg##_HW_LP_MODE, \
+ .hw_lp_mode_mask = 0x4, \
+ .lp_imax_uA = 10000, \
+ .op_en_reg = MT6363_LDO_##vreg##_OP_EN0, \
+ .hwirq = ocp_intn, \
+}
+
+#define MT6363_LDO_VT(match, vreg, inp, vranges_num, ocp_intn) \
+ MT6363_LDO_LINEAR_CAL_OPS(match, vreg, inp, mt6363_ldo_vtable_ops,\
+ vranges_num, ocp_intn)
+
+static const unsigned int ldos_cal_selectors[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const struct linear_range ldo_volt_ranges0[] = {
+ REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2600000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3400000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3500000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges1[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1810000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges2[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2400000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2600000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges3[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1400000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1600000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges4[] = {
+ REGULATOR_LINEAR_RANGE(550000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(600000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(650000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(700000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(750000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(800000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(900000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(950000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(1000000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(1050000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(1100000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(1150000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(1700000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(1750000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(1850000, 0, 10, 5000)
+};
+
+static const struct linear_range ldo_volt_ranges5[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(650000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(700000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(750000, 0, 10, 5000),
+ REGULATOR_LINEAR_RANGE(800000, 0, 10, 5000)
+};
+
+static int mt6363_vreg_enable_setclr(struct regulator_dev *rdev)
+{
+ return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_SET_OFFSET,
+ rdev->desc->enable_mask);
+}
+
+static int mt6363_vreg_disable_setclr(struct regulator_dev *rdev)
+{
+ return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_CLR_OFFSET,
+ rdev->desc->enable_mask);
+}
+
+static inline unsigned int mt6363_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case MT6363_REGULATOR_MODE_NORMAL:
+ return REGULATOR_MODE_NORMAL;
+ case MT6363_REGULATOR_MODE_FCCM:
+ return REGULATOR_MODE_FAST;
+ case MT6363_REGULATOR_MODE_LP:
+ return REGULATOR_MODE_IDLE;
+ case MT6363_REGULATOR_MODE_ULP:
+ return REGULATOR_MODE_STANDBY;
+ default:
+ return REGULATOR_MODE_INVALID;
+ }
+}
+
+static unsigned int mt6363_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned int val;
+ int ret;
+
+ if (info->modeset_reg) {
+ ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to get mt6363 mode: %d\n", ret);
+ return ret;
+ }
+
+ if (val & info->modeset_mask)
+ return REGULATOR_MODE_FAST;
+ } else {
+ val = 0;
+ }
+
+ ret = regmap_read(rdev->regmap, info->hw_lp_mode_reg, &val);
+ val &= info->hw_lp_mode_mask;
+
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
+ return ret;
+ }
+
+ if (val)
+ return REGULATOR_MODE_IDLE;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6363_buck_unlock(struct regmap *map, bool unlock)
+{
+ u16 buf = unlock ? MT6363_BUCK_TOP_UNLOCK_VALUE : 0;
+
+ return regmap_bulk_write(map, MT6363_BUCK_TOP_KEY_PROT_LO, &buf, sizeof(buf));
+}
+
+static int mt6363_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+ struct regmap *regmap = rdev->regmap;
+ int cur_mode, ret;
+
+ if (!info->modeset_reg && mode == REGULATOR_MODE_FAST)
+ return -EOPNOTSUPP;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ ret = mt6363_buck_unlock(regmap, true);
+ if (ret)
+ break;
+
+ ret = regmap_set_bits(regmap, info->modeset_reg, info->modeset_mask);
+
+ mt6363_buck_unlock(regmap, false);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ cur_mode = mt6363_regulator_get_mode(rdev);
+ if (cur_mode < 0) {
+ ret = cur_mode;
+ break;
+ }
+
+ if (cur_mode == REGULATOR_MODE_FAST) {
+ ret = mt6363_buck_unlock(regmap, true);
+ if (ret)
+ break;
+
+ ret = regmap_clear_bits(regmap, info->modeset_reg, info->modeset_mask);
+
+ mt6363_buck_unlock(regmap, false);
+ break;
+ } else if (cur_mode == REGULATOR_MODE_IDLE) {
+ ret = regmap_clear_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+ if (ret == 0)
+ usleep_range(100, 200);
+ } else {
+ ret = 0;
+ }
+ break;
+ case REGULATOR_MODE_IDLE:
+ ret = regmap_set_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to set mode %u: %d\n", mode, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt6363_regulator_set_load(struct regulator_dev *rdev, int load_uA)
+{
+ struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned int opmode_cfg, opmode_en;
+ int i, ret;
+
+ if (!info->lp_imax_uA)
+ return -EINVAL;
+
+ if (load_uA >= info->lp_imax_uA) {
+ ret = mt6363_regulator_set_mode(rdev, REGULATOR_MODE_NORMAL);
+ if (ret)
+ return ret;
+
+ opmode_cfg = NORMAL_OP_CFG;
+ opmode_en = NORMAL_OP_EN;
+ } else {
+ opmode_cfg = info->orig_op_cfg;
+ opmode_en = info->orig_op_en;
+ }
+
+ ret = regmap_write(rdev->regmap, info->op_en_reg + OP_CFG_OFFSET, opmode_cfg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < 3; i++) {
+ ret = regmap_write(rdev->regmap, info->op_en_reg + i,
+ (opmode_en >> (i * 8)) & GENMASK(7, 0));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt6363_vemc_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+ const u16 tma_unlock_key = MT6363_TMA_UNLOCK_VALUE;
+ const struct regulator_desc *rdesc = rdev->desc;
+ struct regmap *regmap = rdev->regmap;
+ unsigned int range, val;
+ int i, ret;
+ u16 mask;
+
+ for (i = 0; i < rdesc->n_linear_ranges; i++) {
+ const struct linear_range *r = &rdesc->linear_ranges[i];
+ unsigned int voltages_in_range = linear_range_values_in_range(r);
+
+ if (sel < voltages_in_range)
+ break;
+ sel -= voltages_in_range;
+ }
+
+ if (i == rdesc->n_linear_ranges)
+ return -EINVAL;
+
+ ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &val);
+ if (ret)
+ return ret;
+
+ if (val > 1)
+ return -EINVAL;
+
+ /* Unlock TMA for writing */
+ ret = regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L,
+ &tma_unlock_key, sizeof(tma_unlock_key));
+ if (ret)
+ return ret;
+
+ /* If HW trapping value is 1, use VEMC_VOSEL_1 instead of VEMC_VOSEL_0 */
+ if (val == 1) {
+ mask = MT6363_RG_VEMC_VOSEL_1_MASK;
+ sel = FIELD_PREP(MT6363_RG_VEMC_VOSEL_1_MASK, sel);
+ } else {
+ mask = rdesc->vsel_mask;
+ }
+
+ sel <<= ffs(rdesc->vsel_mask) - 1;
+ sel += rdesc->linear_ranges[i].min_sel;
+
+ range = rdesc->linear_range_selectors_bitfield[i];
+ range <<= ffs(rdesc->vsel_range_mask) - 1;
+
+ /* Write to the vreg calibration register for voltage finetuning */
+ ret = regmap_update_bits(regmap, rdesc->vsel_range_reg,
+ rdesc->vsel_range_mask, range);
+ if (ret)
+ goto lock_tma;
+
+ /* Function must return the result of this write operation */
+ ret = regmap_update_bits(regmap, rdesc->vsel_reg, mask, sel);
+
+lock_tma:
+ /* Unconditionally re-lock TMA */
+ val = 0;
+ regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L, &val, 2);
+
+ return ret;
+}
+
+static int mt6363_vemc_get_voltage_sel(struct regulator_dev *rdev)
+{
+ const struct regulator_desc *rdesc = rdev->desc;
+ unsigned int vosel, trap, calsel;
+ int vcal, vsel, range, ret;
+
+ ret = regmap_read(rdev->regmap, rdesc->vsel_reg, &vosel);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(rdev->regmap, rdesc->vsel_range_reg, &calsel);
+ if (ret)
+ return ret;
+
+ calsel &= rdesc->vsel_range_mask;
+ for (range = 0; range < rdesc->n_linear_ranges; range++)
+ if (rdesc->linear_range_selectors_bitfield[range] != calsel)
+ break;
+
+ if (range == rdesc->n_linear_ranges)
+ return -EINVAL;
+
+ ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &trap);
+ if (ret)
+ return ret;
+
+ /* If HW trapping value is 1, use VEMC_VOSEL_1 instead of VEMC_VOSEL_0 */
+ if (trap > 1)
+ return -EINVAL;
+ else if (trap == 1)
+ vsel = FIELD_GET(MT6363_RG_VEMC_VOSEL_1_MASK, vosel);
+ else
+ vsel = vosel & rdesc->vsel_mask;
+
+ vcal = linear_range_values_in_range_array(rdesc->linear_ranges, range);
+
+ return vsel + vcal;
+}
+
+static int mt6363_va15_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+ struct regmap *regmap = rdev->regmap;
+ int ret;
+
+ ret = mt6363_buck_unlock(regmap, true);
+ if (ret)
+ return ret;
+
+ ret = regulator_set_voltage_sel_pickable_regmap(rdev, sel);
+ if (ret)
+ goto va15_unlock;
+
+ ret = regmap_update_bits(regmap, MT6363_RG_BUCK_EFUSE_RSV1,
+ MT6363_RG_BUCK_EFUSE_RSV1_MASK, sel);
+ if (ret)
+ goto va15_unlock;
+
+va15_unlock:
+ mt6363_buck_unlock(rdev->regmap, false);
+ return ret;
+}
+
+static void mt6363_oc_irq_enable_work(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct mt6363_regulator_info *info =
+ container_of(dwork, struct mt6363_regulator_info, oc_work);
+
+ enable_irq(info->virq);
+}
+
+static irqreturn_t mt6363_oc_isr(int irq, void *data)
+{
+ struct regulator_dev *rdev = (struct regulator_dev *)data;
+ struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+
+ disable_irq_nosync(info->virq);
+
+ if (regulator_is_enabled_regmap(rdev))
+ regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL);
+
+ schedule_delayed_work(&info->oc_work, msecs_to_jiffies(OC_IRQ_ENABLE_DELAY_MS));
+
+ return IRQ_HANDLED;
+}
+
+static int mt6363_set_ocp(struct regulator_dev *rdev, int lim, int severity, bool enable)
+{
+ struct mt6363_regulator_info *info = rdev_get_drvdata(rdev);
+
+ /* MT6363 supports only enabling protection and does not support limits */
+ if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
+ return -EOPNOTSUPP;
+
+ /* If there is no OCP interrupt, there's nothing to set */
+ if (info->virq <= 0)
+ return -EOPNOTSUPP;
+
+ return devm_request_threaded_irq(&rdev->dev, info->virq, NULL,
+ mt6363_oc_isr, IRQF_ONESHOT,
+ info->desc.name, rdev);
+}
+
+static const struct regulator_ops mt6363_vreg_setclr_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .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,
+ .enable = mt6363_vreg_enable_setclr,
+ .disable = mt6363_vreg_disable_setclr,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6363_regulator_set_mode,
+ .get_mode = mt6363_regulator_get_mode,
+ .set_load = mt6363_regulator_set_load,
+ .set_over_current_protection = mt6363_set_ocp,
+};
+
+static const struct regulator_ops mt6363_ldo_linear_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .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,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6363_regulator_set_mode,
+ .get_mode = mt6363_regulator_get_mode,
+ .set_over_current_protection = mt6363_set_ocp,
+};
+
+static const struct regulator_ops mt6363_ldo_vtable_ops = {
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .map_voltage = regulator_map_voltage_pickable_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6363_regulator_set_mode,
+ .get_mode = mt6363_regulator_get_mode,
+ .set_load = mt6363_regulator_set_load,
+ .set_over_current_protection = mt6363_set_ocp,
+};
+
+static const struct regulator_ops mt6363_ldo_vemc_ops = {
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .map_voltage = regulator_map_voltage_pickable_linear_range,
+ .set_voltage_sel = mt6363_vemc_set_voltage_sel,
+ .get_voltage_sel = mt6363_vemc_get_voltage_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6363_regulator_set_mode,
+ .get_mode = mt6363_regulator_get_mode,
+ .set_load = mt6363_regulator_set_load,
+ .set_over_current_protection = mt6363_set_ocp,
+};
+
+static const struct regulator_ops mt6363_ldo_va15_ops = {
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .map_voltage = regulator_map_voltage_pickable_linear_range,
+ .set_voltage_sel = mt6363_va15_set_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6363_regulator_set_mode,
+ .get_mode = mt6363_regulator_get_mode,
+ .set_load = mt6363_regulator_set_load,
+ .set_over_current_protection = mt6363_set_ocp,
+};
+
+/* The array is indexed by id(MT6363_ID_XXX) */
+static struct mt6363_regulator_info mt6363_regulators[] = {
+ MT6363_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+ MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_FCCM_ADDR, 1),
+ MT6363_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+ MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_FCCM_ADDR, 2),
+ MT6363_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+ MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_FCCM_ADDR, 3),
+ MT6363_BUCK("vbuck4", VBUCK4, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+ MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_1_FCCM_ADDR, 4),
+ MT6363_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+ MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_1_FCCM_ADDR, 5),
+ MT6363_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+ MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_1_FCCM_ADDR, 6),
+ MT6363_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250, MT6363_RG_BUCK0_EN_ADDR,
+ MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_1_FCCM_ADDR, 7),
+ MT6363_BUCK("vs1", VS1, 0, 2200000, 12500, MT6363_RG_BUCK1_EN_ADDR,
+ MT6363_RG_BUCK1_LP_ADDR, MT6363_RG_VS1_FCCM_ADDR, 8),
+ MT6363_BUCK("vs2", VS2, 0, 1600000, 12500, MT6363_RG_BUCK0_EN_ADDR,
+ MT6363_RG_BUCK0_LP_ADDR, MT6363_RG_BUCK0_FCCM_ADDR, 0),
+ MT6363_BUCK("vs3", VS3, 0, 1193750, 6250, MT6363_RG_BUCK1_EN_ADDR,
+ MT6363_RG_BUCK1_LP_ADDR, MT6363_RG_VS3_FCCM_ADDR, 9),
+ MT6363_LDO_VT("va12-1", VA12_1, "vs2-ldo2", 3, 37),
+ MT6363_LDO_VT("va12-2", VA12_2, "vs2-ldo2", 3, 38),
+ MT6363_LDO_LINEAR_CAL_OPS("va15", VA15, "vs1-ldo1", mt6363_ldo_va15_ops, 3, 39),
+ MT6363_LDO_VT("vaux18", VAUX18, "vsys-ldo1", 2, 31),
+ MT6363_LDO_VT("vcn13", VCN13, "vs2-ldo2", 1, 17),
+ MT6363_LDO_VT("vcn15", VCN15, "vs1-ldo2", 3, 16),
+ MT6363_LDO_LINEAR_CAL_OPS("vemc", VEMC, "vsys-ldo1", mt6363_ldo_vemc_ops, 0, 32),
+ MT6363_LDO_VT("vio0p75", VIO075, "vs1-ldo1", 5, 36),
+ MT6363_LDO_VT("vio18", VIO18, "vs1-ldo2", 3, 35),
+ MT6363_LDO_VT("vm18", VM18, "vs1-ldo1", 4, 40),
+ MT6363_LDO_L("vsram-apu", VSRAM_APU, "vs3-ldo1", 400000, 1193750, 6250, BUCK1, 30),
+ MT6363_LDO_L("vsram-cpub", VSRAM_CPUB, "vs2-ldo1", 400000, 1193750, 6250, BUCK1, 27),
+ MT6363_LDO_L("vsram-cpum", VSRAM_CPUM, "vs2-ldo1", 400000, 1193750, 6250, BUCK1, 28),
+ MT6363_LDO_L("vsram-cpul", VSRAM_CPUL, "vs2-ldo2", 400000, 1193750, 6250, BUCK1, 29),
+ MT6363_LDO_L_SC("vsram-digrf", VSRAM_DIGRF, "vs3-ldo1", 400000, 1193750, 6250, BUCK1, 23),
+ MT6363_LDO_L_SC("vsram-mdfe", VSRAM_MDFE, "vs3-ldo1", 400000, 1193750, 6250, BUCK1, 24),
+ MT6363_LDO_L_SC("vsram-modem", VSRAM_MODEM, "vs3-ldo2", 400000, 1193750, 6250, BUCK1, 25),
+ MT6363_LDO_VT("vrf0p9", VRF09, "vs3-ldo2", 1, 18),
+ MT6363_LDO_VT("vrf12", VRF12, "vs2-ldo1", 3, 19),
+ MT6363_LDO_VT("vrf13", VRF13, "vs2-ldo1", 1, 20),
+ MT6363_LDO_VT("vrf18", VRF18, "vs1-ldo1", 3, 21),
+ MT6363_LDO_VT("vrf-io18", VRFIO18, "vs1-ldo1", 3, 22),
+ MT6363_LDO_VT("vtref18", VTREF18, "vsys-ldo1", 2, 26),
+ MT6363_LDO_VT("vufs12", VUFS12, "vs2-ldo1", 4, 33),
+ MT6363_LDO_VT("vufs18", VUFS18, "vs1-ldo2", 3, 34),
+};
+
+static int mt6363_backup_op_setting(struct regmap *map, struct mt6363_regulator_info *info)
+{
+ unsigned int i, val;
+ int ret;
+
+ ret = regmap_read(map, info->op_en_reg + OP_CFG_OFFSET, &val);
+ if (ret)
+ return ret;
+
+ info->orig_op_cfg = val;
+
+ for (i = 0; i < 3; i++) {
+ ret = regmap_read(map, info->op_en_reg + i, &val);
+ if (ret)
+ return ret;
+
+ info->orig_op_en |= val << (i * 8);
+ }
+
+ return 0;
+}
+
+static void mt6363_irq_remove(void *data)
+{
+ int *virq = data;
+
+ irq_dispose_mapping(*virq);
+}
+
+static void mt6363_spmi_remove(void *data)
+{
+ struct spmi_device *sdev = data;
+
+ spmi_device_remove(sdev);
+};
+
+static struct regmap *mt6363_spmi_register_regmap(struct device *dev)
+{
+ struct regmap_config mt6363_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = 0x1f90,
+ .fast_io = true,
+ };
+ struct spmi_device *sdev, *sparent;
+ u32 base;
+ int ret;
+
+ if (!dev->parent)
+ return ERR_PTR(-ENODEV);
+
+ ret = device_property_read_u32(dev, "reg", &base);
+ if (ret)
+ return ERR_PTR(ret);
+
+ sparent = to_spmi_device(dev->parent);
+ if (!sparent)
+ return ERR_PTR(-ENODEV);
+
+ sdev = spmi_device_alloc(sparent->ctrl);
+ if (!sdev)
+ return ERR_PTR(-ENODEV);
+
+ sdev->usid = sparent->usid;
+ dev_set_name(&sdev->dev, "%d-%02x-regulator", sdev->ctrl->nr, sdev->usid);
+ ret = device_add(&sdev->dev);
+ if (ret) {
+ put_device(&sdev->dev);
+ return ERR_PTR(ret);
+ };
+
+ ret = devm_add_action_or_reset(dev, mt6363_spmi_remove, sdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ mt6363_regmap_config.reg_base = base;
+
+ return devm_regmap_init_spmi_ext(sdev, &mt6363_regmap_config);
+}
+
+static int mt6363_regulator_probe(struct platform_device *pdev)
+{
+ struct device_node *interrupt_parent;
+ struct regulator_config config = {};
+ struct mt6363_regulator_info *info;
+ struct device *dev = &pdev->dev;
+ struct regulator_dev *rdev;
+ struct irq_domain *domain;
+ struct irq_fwspec fwspec;
+ struct spmi_device *sdev;
+ int i, ret;
+
+ config.regmap = mt6363_spmi_register_regmap(dev);
+ if (IS_ERR(config.regmap))
+ return dev_err_probe(dev, PTR_ERR(config.regmap),
+ "Cannot get regmap\n");
+ config.dev = dev;
+ sdev = to_spmi_device(dev->parent);
+
+ interrupt_parent = of_irq_find_parent(dev->of_node);
+ if (!interrupt_parent)
+ return dev_err_probe(dev, -EINVAL, "Cannot find IRQ parent\n");
+
+ domain = irq_find_host(interrupt_parent);
+ of_node_put(interrupt_parent);
+ fwspec.fwnode = domain->fwnode;
+
+ fwspec.param_count = 3;
+ fwspec.param[0] = sdev->usid;
+ fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+
+ for (i = 0; i < ARRAY_SIZE(mt6363_regulators); i++) {
+ info = &mt6363_regulators[i];
+
+ fwspec.param[1] = info->hwirq;
+ info->virq = irq_create_fwspec_mapping(&fwspec);
+ if (!info->virq)
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to map IRQ%d\n", info->hwirq);
+
+ ret = devm_add_action_or_reset(dev, mt6363_irq_remove, &info->virq);
+ if (ret) {
+ irq_dispose_mapping(info->hwirq);
+ return ret;
+ }
+
+ config.driver_data = info;
+ INIT_DELAYED_WORK(&info->oc_work, mt6363_oc_irq_enable_work);
+
+ rdev = devm_regulator_register(dev, &info->desc, &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "failed to register %s\n", info->desc.name);
+
+ if (info->lp_imax_uA) {
+ ret = mt6363_backup_op_setting(config.regmap, info);
+ if (ret) {
+ dev_warn(dev, "Failed to backup op_setting for %s\n",
+ info->desc.name);
+ info->lp_imax_uA = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id mt6363_regulator_match[] = {
+ { .compatible = "mediatek,mt6363-regulator" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver mt6363_regulator_driver = {
+ .driver = {
+ .name = "mt6363-regulator",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = mt6363_regulator_match,
+ },
+ .probe = mt6363_regulator_probe,
+};
+module_platform_driver(mt6363_regulator_driver);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6363 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/mt6370-regulator.c b/drivers/regulator/mt6370-regulator.c
index 27cb32b726e0..c2cea904b0ca 100644
--- a/drivers/regulator/mt6370-regulator.c
+++ b/drivers/regulator/mt6370-regulator.c
@@ -320,7 +320,7 @@ static int mt6370_regulator_irq_register(struct mt6370_priv *priv)
return 0;
}
-static int mt6370_regualtor_register(struct mt6370_priv *priv)
+static int mt6370_regulator_register(struct mt6370_priv *priv)
{
struct regulator_dev *rdev;
struct regulator_config cfg = {};
@@ -363,7 +363,7 @@ static int mt6370_regulator_probe(struct platform_device *pdev)
return -ENODEV;
}
- ret = mt6370_regualtor_register(priv);
+ ret = mt6370_regulator_register(priv);
if (ret)
return ret;
diff --git a/drivers/regulator/mtk-dvfsrc-regulator.c b/drivers/regulator/mtk-dvfsrc-regulator.c
index f5662c569464..c0c9a6751c26 100644
--- a/drivers/regulator/mtk-dvfsrc-regulator.c
+++ b/drivers/regulator/mtk-dvfsrc-regulator.c
@@ -117,6 +117,24 @@ static const struct dvfsrc_regulator_pdata mt6873_data = {
.size = ARRAY_SIZE(mt6873_regulators),
};
+static const unsigned int mt6893_voltages[] = {
+ 575000,
+ 600000,
+ 650000,
+ 725000,
+ 750000,
+};
+
+static const struct regulator_desc mt6893_regulators[] = {
+ MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt6893_voltages),
+ MTK_DVFSRC_VREG("dvfsrc-vscp", VSCP, mt6893_voltages),
+};
+
+static const struct dvfsrc_regulator_pdata mt6893_data = {
+ .descs = mt6893_regulators,
+ .size = ARRAY_SIZE(mt6893_regulators),
+};
+
static const unsigned int mt8183_voltages[] = {
725000,
800000,
@@ -148,6 +166,24 @@ static const struct dvfsrc_regulator_pdata mt8195_data = {
.size = ARRAY_SIZE(mt8195_regulators),
};
+static const unsigned int mt8196_voltages[] = {
+ 575000,
+ 600000,
+ 650000,
+ 725000,
+ 825000,
+ 875000,
+};
+
+static const struct regulator_desc mt8196_regulators[] = {
+ MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8196_voltages),
+};
+
+static const struct dvfsrc_regulator_pdata mt8196_data = {
+ .descs = mt8196_regulators,
+ .size = ARRAY_SIZE(mt8196_regulators),
+};
+
static int dvfsrc_vcore_regulator_probe(struct platform_device *pdev)
{
struct regulator_config config = { .dev = &pdev->dev };
@@ -173,9 +209,11 @@ static int dvfsrc_vcore_regulator_probe(struct platform_device *pdev)
static const struct of_device_id mtk_dvfsrc_regulator_match[] = {
{ .compatible = "mediatek,mt6873-dvfsrc-regulator", .data = &mt6873_data },
+ { .compatible = "mediatek,mt6893-dvfsrc-regulator", .data = &mt6893_data },
{ .compatible = "mediatek,mt8183-dvfsrc-regulator", .data = &mt8183_data },
{ .compatible = "mediatek,mt8192-dvfsrc-regulator", .data = &mt6873_data },
{ .compatible = "mediatek,mt8195-dvfsrc-regulator", .data = &mt8195_data },
+ { .compatible = "mediatek,mt8196-dvfsrc-regulator", .data = &mt8196_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 3d85762beda6..33463926a2a6 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -79,10 +79,10 @@ static void of_get_regulator_prot_limits(struct device_node *np,
static int of_get_regulation_constraints(struct device *dev,
struct device_node *np,
- struct regulator_init_data **init_data,
+ struct regulator_init_data *init_data,
const struct regulator_desc *desc)
{
- struct regulation_constraints *constraints = &(*init_data)->constraints;
+ struct regulation_constraints *constraints = &init_data->constraints;
struct regulator_state *suspend_state;
struct device_node *suspend_np;
unsigned int mode;
@@ -125,6 +125,9 @@ static int of_get_regulation_constraints(struct device *dev,
if (constraints->min_uA != constraints->max_uA)
constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
+ if (!of_property_read_u32(np, "regulator-power-budget-milliwatt", &pval))
+ constraints->pw_budget_mW = pval;
+
constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
constraints->always_on = of_property_read_bool(np, "regulator-always-on");
if (!constraints->always_on) /* status change should be possible. */
@@ -175,7 +178,7 @@ static int of_get_regulation_constraints(struct device *dev,
if (!ret)
constraints->enable_time = pval;
- ret = of_property_read_u32(np, "regulator-uv-survival-time-ms", &pval);
+ ret = of_property_read_u32(np, "regulator-uv-less-critical-window-ms", &pval);
if (!ret)
constraints->uv_less_critical_window_ms = pval;
else
@@ -356,7 +359,7 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
if (!init_data)
return NULL; /* Out of memory? */
- if (of_get_regulation_constraints(dev, node, &init_data, desc))
+ if (of_get_regulation_constraints(dev, node, init_data, desc))
return NULL;
return init_data;
@@ -446,7 +449,7 @@ int of_regulator_match(struct device *dev, struct device_node *node,
"failed to parse DT for regulator %pOFn\n",
child);
of_node_put(child);
- return -EINVAL;
+ goto err_put;
}
match->of_node = of_node_get(child);
count++;
@@ -455,6 +458,18 @@ int of_regulator_match(struct device *dev, struct device_node *node,
}
return count;
+
+err_put:
+ for (i = 0; i < num_matches; i++) {
+ struct of_regulator_match *match = &matches[i];
+
+ match->init_data = NULL;
+ if (match->of_node) {
+ of_node_put(match->of_node);
+ match->of_node = NULL;
+ }
+ }
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(of_regulator_match);
@@ -683,6 +698,27 @@ struct regulator *_of_regulator_get(struct device *dev, struct device_node *node
}
/**
+ * of_regulator_get - get regulator via device tree lookup
+ * @dev: device used for dev_printk() messages
+ * @node: device node for regulator "consumer"
+ * @id: Supply name
+ *
+ * Return: pointer to struct regulator corresponding to the regulator producer,
+ * or PTR_ERR() encoded error number.
+ *
+ * This is intended for use by consumers that want to get a regulator
+ * supply directly from a device node. This will _not_ consider supply
+ * aliases. See regulator_dev_lookup().
+ */
+struct regulator *of_regulator_get(struct device *dev,
+ struct device_node *node,
+ const char *id)
+{
+ return _of_regulator_get(dev, node, id, NORMAL_GET);
+}
+EXPORT_SYMBOL_GPL(of_regulator_get);
+
+/**
* of_regulator_get_optional - get optional regulator via device tree lookup
* @dev: device used for dev_printk() messages
* @node: device node for regulator "consumer"
diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
index 9714afe347dc..5fa868264250 100644
--- a/drivers/regulator/pca9450-regulator.c
+++ b/drivers/regulator/pca9450-regulator.c
@@ -9,6 +9,7 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/reboot.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -16,12 +17,18 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/pca9450.h>
+#include <dt-bindings/regulator/nxp,pca9450-regulator.h>
+
+static unsigned int pca9450_buck_get_mode(struct regulator_dev *rdev);
+static int pca9450_buck_set_mode(struct regulator_dev *rdev, unsigned int mode);
struct pc9450_dvs_config {
unsigned int run_reg; /* dvs0 */
unsigned int run_mask;
unsigned int standby_reg; /* dvs1 */
unsigned int standby_mask;
+ unsigned int mode_reg; /* ctrl */
+ unsigned int mode_mask;
};
struct pca9450_regulator_desc {
@@ -36,6 +43,7 @@ struct pca9450 {
enum pca9450_chip_type type;
unsigned int rcnt;
int irq;
+ bool sd_vsel_fixed_low;
};
static const struct regmap_range pca9450_status_range = {
@@ -77,6 +85,8 @@ static const struct regulator_ops pca9450_dvs_buck_regulator_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = regulator_set_ramp_delay_regmap,
+ .set_mode = pca9450_buck_set_mode,
+ .get_mode = pca9450_buck_get_mode,
};
static const struct regulator_ops pca9450_buck_regulator_ops = {
@@ -87,6 +97,8 @@ static const struct regulator_ops pca9450_buck_regulator_ops = {
.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_mode = pca9450_buck_set_mode,
+ .get_mode = pca9450_buck_get_mode,
};
static const struct regulator_ops pca9450_ldo_regulator_ops = {
@@ -98,6 +110,61 @@ static const struct regulator_ops pca9450_ldo_regulator_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
+static unsigned int pca9450_ldo5_get_reg_voltage_sel(struct regulator_dev *rdev)
+{
+ struct pca9450 *pca9450 = rdev_get_drvdata(rdev);
+
+ if (pca9450->sd_vsel_fixed_low)
+ return PCA9450_REG_LDO5CTRL_L;
+
+ if (pca9450->sd_vsel_gpio && !gpiod_get_value(pca9450->sd_vsel_gpio))
+ return PCA9450_REG_LDO5CTRL_L;
+
+ return rdev->desc->vsel_reg;
+}
+
+static int pca9450_ldo5_get_voltage_sel_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, pca9450_ldo5_get_reg_voltage_sel(rdev), &val);
+ if (ret != 0)
+ return ret;
+
+ val &= rdev->desc->vsel_mask;
+ val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+ return val;
+}
+
+static int pca9450_ldo5_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned int sel)
+{
+ int ret;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+ ret = regmap_update_bits(rdev->regmap, pca9450_ldo5_get_reg_voltage_sel(rdev),
+ 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;
+}
+
+static const struct regulator_ops pca9450_ldo5_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 = pca9450_ldo5_set_voltage_sel_regmap,
+ .get_voltage_sel = pca9450_ldo5_get_voltage_sel_regmap,
+};
+
/*
* BUCK1/2/3
* 0.60 to 2.1875V (12.5mV step)
@@ -182,7 +249,7 @@ static int buck_set_dvs(const struct regulator_desc *desc,
}
if (ret == 0) {
- struct pca9450_regulator_desc *regulator = container_of(desc,
+ const struct pca9450_regulator_desc *regulator = container_of_const(desc,
struct pca9450_regulator_desc, desc);
/* Enable DVS control through PMIC_STBY_REQ for this BUCK */
@@ -196,7 +263,7 @@ static int pca9450_set_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
- struct pca9450_regulator_desc *data = container_of(desc,
+ const struct pca9450_regulator_desc *data = container_of_const(desc,
struct pca9450_regulator_desc, desc);
const struct pc9450_dvs_config *dvs = &data->dvs;
unsigned int reg, mask;
@@ -227,10 +294,68 @@ static int pca9450_set_dvs_levels(struct device_node *np,
return ret;
}
-static const struct pca9450_regulator_desc pca9450a_regulators[] = {
+static inline unsigned int pca9450_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case PCA9450_BUCK_MODE_AUTO:
+ return REGULATOR_MODE_NORMAL;
+ case PCA9450_BUCK_MODE_FORCE_PWM:
+ return REGULATOR_MODE_FAST;
+ default:
+ return REGULATOR_MODE_INVALID;
+ }
+}
+
+static int pca9450_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ const struct pca9450_regulator_desc *desc = container_of_const(rdev->desc,
+ struct pca9450_regulator_desc, desc);
+ const struct pc9450_dvs_config *dvs = &desc->dvs;
+ int val;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = dvs->mode_mask;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(&rdev->dev, "pca9450 buck set_mode %#x, %#x, %#x\n",
+ dvs->mode_reg, dvs->mode_mask, val);
+
+ return regmap_update_bits(rdev->regmap, dvs->mode_reg,
+ dvs->mode_mask, val);
+}
+
+static unsigned int pca9450_buck_get_mode(struct regulator_dev *rdev)
+{
+ const struct pca9450_regulator_desc *desc = container_of_const(rdev->desc,
+ struct pca9450_regulator_desc, desc);
+ const struct pc9450_dvs_config *dvs = &desc->dvs;
+ int ret = 0, regval;
+
+ ret = regmap_read(rdev->regmap, dvs->mode_reg, &regval);
+ if (ret != 0) {
+ dev_err(&rdev->dev,
+ "Failed to get pca9450 buck mode: %d\n", ret);
+ return ret;
+ }
+
+ if ((regval & dvs->mode_mask) == dvs->mode_mask)
+ return REGULATOR_MODE_FAST;
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+static struct pca9450_regulator_desc pca9450a_regulators[] = {
{
.desc = {
.name = "buck1",
+ .supply_name = "inb13",
.of_match = of_match_ptr("BUCK1"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK1,
@@ -247,19 +372,24 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.ramp_mask = BUCK1_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
.n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
+ .enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
+ .of_map_mode = pca9450_map_mode,
},
.dvs = {
.run_reg = PCA9450_REG_BUCK1OUT_DVS0,
.run_mask = BUCK1OUT_DVS0_MASK,
.standby_reg = PCA9450_REG_BUCK1OUT_DVS1,
.standby_mask = BUCK1OUT_DVS1_MASK,
+ .mode_reg = PCA9450_REG_BUCK1CTRL,
+ .mode_mask = BUCK1_FPWM,
},
},
{
.desc = {
.name = "buck2",
+ .supply_name = "inb26",
.of_match = of_match_ptr("BUCK2"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK2,
@@ -272,23 +402,28 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK2OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK2CTRL,
.enable_mask = BUCK2_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ_STBYREQ,
.ramp_reg = PCA9450_REG_BUCK2CTRL,
.ramp_mask = BUCK2_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
.n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
+ .of_map_mode = pca9450_map_mode,
},
.dvs = {
.run_reg = PCA9450_REG_BUCK2OUT_DVS0,
.run_mask = BUCK2OUT_DVS0_MASK,
.standby_reg = PCA9450_REG_BUCK2OUT_DVS1,
.standby_mask = BUCK2OUT_DVS1_MASK,
+ .mode_reg = PCA9450_REG_BUCK2CTRL,
+ .mode_mask = BUCK2_FPWM,
},
},
{
.desc = {
.name = "buck3",
+ .supply_name = "inb13",
.of_match = of_match_ptr("BUCK3"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK3,
@@ -301,23 +436,28 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK3OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK3CTRL,
.enable_mask = BUCK3_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
.ramp_reg = PCA9450_REG_BUCK3CTRL,
.ramp_mask = BUCK3_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
.n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
+ .of_map_mode = pca9450_map_mode,
},
.dvs = {
.run_reg = PCA9450_REG_BUCK3OUT_DVS0,
.run_mask = BUCK3OUT_DVS0_MASK,
.standby_reg = PCA9450_REG_BUCK3OUT_DVS1,
.standby_mask = BUCK3OUT_DVS1_MASK,
+ .mode_reg = PCA9450_REG_BUCK3CTRL,
+ .mode_mask = BUCK3_FPWM,
},
},
{
.desc = {
.name = "buck4",
+ .supply_name = "inb45",
.of_match = of_match_ptr("BUCK4"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK4,
@@ -330,12 +470,19 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK4OUT_MASK,
.enable_reg = PCA9450_REG_BUCK4CTRL,
.enable_mask = BUCK4_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK4CTRL,
+ .mode_mask = BUCK4_FPWM,
},
},
{
.desc = {
.name = "buck5",
+ .supply_name = "inb45",
.of_match = of_match_ptr("BUCK5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK5,
@@ -348,12 +495,19 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK5OUT_MASK,
.enable_reg = PCA9450_REG_BUCK5CTRL,
.enable_mask = BUCK5_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK5CTRL,
+ .mode_mask = BUCK5_FPWM,
},
},
{
.desc = {
.name = "buck6",
+ .supply_name = "inb26",
.of_match = of_match_ptr("BUCK6"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK6,
@@ -366,12 +520,19 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK6OUT_MASK,
.enable_reg = PCA9450_REG_BUCK6CTRL,
.enable_mask = BUCK6_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK6CTRL,
+ .mode_mask = BUCK6_FPWM,
},
},
{
.desc = {
.name = "ldo1",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO1"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO1,
@@ -390,6 +551,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
{
.desc = {
.name = "ldo2",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO2"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO2,
@@ -408,6 +570,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
{
.desc = {
.name = "ldo3",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO3"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO3,
@@ -426,6 +589,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
{
.desc = {
.name = "ldo4",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO4"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO4,
@@ -444,17 +608,18 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
{
.desc = {
.name = "ldo5",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO5,
- .ops = &pca9450_ldo_regulator_ops,
+ .ops = &pca9450_ldo5_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
.linear_ranges = pca9450_ldo5_volts,
.n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
.vsel_reg = PCA9450_REG_LDO5CTRL_H,
.vsel_mask = LDO5HOUT_MASK,
- .enable_reg = PCA9450_REG_LDO5CTRL_H,
+ .enable_reg = PCA9450_REG_LDO5CTRL_L,
.enable_mask = LDO5H_EN_MASK,
.owner = THIS_MODULE,
},
@@ -465,10 +630,11 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
* Buck3 removed on PCA9450B and connected with Buck1 internal for dual phase
* on PCA9450C as no Buck3.
*/
-static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
+static struct pca9450_regulator_desc pca9450bc_regulators[] = {
{
.desc = {
.name = "buck1",
+ .supply_name = "inb13",
.of_match = of_match_ptr("BUCK1"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK1,
@@ -481,23 +647,28 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK1OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK1CTRL,
.enable_mask = BUCK1_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
.ramp_reg = PCA9450_REG_BUCK1CTRL,
.ramp_mask = BUCK1_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
.n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
+ .of_map_mode = pca9450_map_mode,
},
.dvs = {
.run_reg = PCA9450_REG_BUCK1OUT_DVS0,
.run_mask = BUCK1OUT_DVS0_MASK,
.standby_reg = PCA9450_REG_BUCK1OUT_DVS1,
.standby_mask = BUCK1OUT_DVS1_MASK,
+ .mode_reg = PCA9450_REG_BUCK1CTRL,
+ .mode_mask = BUCK1_FPWM,
},
},
{
.desc = {
.name = "buck2",
+ .supply_name = "inb26",
.of_match = of_match_ptr("BUCK2"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK2,
@@ -510,23 +681,28 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK2OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK2CTRL,
.enable_mask = BUCK2_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ_STBYREQ,
.ramp_reg = PCA9450_REG_BUCK2CTRL,
.ramp_mask = BUCK2_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
.n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
+ .of_map_mode = pca9450_map_mode,
},
.dvs = {
.run_reg = PCA9450_REG_BUCK2OUT_DVS0,
.run_mask = BUCK2OUT_DVS0_MASK,
.standby_reg = PCA9450_REG_BUCK2OUT_DVS1,
.standby_mask = BUCK2OUT_DVS1_MASK,
+ .mode_reg = PCA9450_REG_BUCK2CTRL,
+ .mode_mask = BUCK2_FPWM,
},
},
{
.desc = {
.name = "buck4",
+ .supply_name = "inb45",
.of_match = of_match_ptr("BUCK4"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK4,
@@ -539,12 +715,19 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK4OUT_MASK,
.enable_reg = PCA9450_REG_BUCK4CTRL,
.enable_mask = BUCK4_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK4CTRL,
+ .mode_mask = BUCK4_FPWM,
},
},
{
.desc = {
.name = "buck5",
+ .supply_name = "inb45",
.of_match = of_match_ptr("BUCK5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK5,
@@ -557,12 +740,19 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK5OUT_MASK,
.enable_reg = PCA9450_REG_BUCK5CTRL,
.enable_mask = BUCK5_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK5CTRL,
+ .mode_mask = BUCK5_FPWM,
},
},
{
.desc = {
.name = "buck6",
+ .supply_name = "inb26",
.of_match = of_match_ptr("BUCK6"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK6,
@@ -575,12 +765,19 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK6OUT_MASK,
.enable_reg = PCA9450_REG_BUCK6CTRL,
.enable_mask = BUCK6_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK6CTRL,
+ .mode_mask = BUCK6_FPWM,
},
},
{
.desc = {
.name = "ldo1",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO1"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO1,
@@ -599,6 +796,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
{
.desc = {
.name = "ldo2",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO2"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO2,
@@ -617,6 +815,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
{
.desc = {
.name = "ldo3",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO3"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO3,
@@ -635,6 +834,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
{
.desc = {
.name = "ldo4",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO4"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO4,
@@ -653,27 +853,29 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
{
.desc = {
.name = "ldo5",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO5,
- .ops = &pca9450_ldo_regulator_ops,
+ .ops = &pca9450_ldo5_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
.linear_ranges = pca9450_ldo5_volts,
.n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
.vsel_reg = PCA9450_REG_LDO5CTRL_H,
.vsel_mask = LDO5HOUT_MASK,
- .enable_reg = PCA9450_REG_LDO5CTRL_H,
+ .enable_reg = PCA9450_REG_LDO5CTRL_L,
.enable_mask = LDO5H_EN_MASK,
.owner = THIS_MODULE,
},
},
};
-static const struct pca9450_regulator_desc pca9451a_regulators[] = {
+static struct pca9450_regulator_desc pca9451a_regulators[] = {
{
.desc = {
.name = "buck1",
+ .supply_name = "inb13",
.of_match = of_match_ptr("BUCK1"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK1,
@@ -692,17 +894,21 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
.n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
+ .of_map_mode = pca9450_map_mode,
},
.dvs = {
.run_reg = PCA9450_REG_BUCK1OUT_DVS0,
.run_mask = BUCK1OUT_DVS0_MASK,
.standby_reg = PCA9450_REG_BUCK1OUT_DVS1,
.standby_mask = BUCK1OUT_DVS1_MASK,
+ .mode_reg = PCA9450_REG_BUCK1CTRL,
+ .mode_mask = BUCK1_FPWM,
},
},
{
.desc = {
.name = "buck2",
+ .supply_name = "inb26",
.of_match = of_match_ptr("BUCK2"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK2,
@@ -721,17 +927,21 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
.n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
+ .of_map_mode = pca9450_map_mode,
},
.dvs = {
.run_reg = PCA9450_REG_BUCK2OUT_DVS0,
.run_mask = BUCK2OUT_DVS0_MASK,
.standby_reg = PCA9450_REG_BUCK2OUT_DVS1,
.standby_mask = BUCK2OUT_DVS1_MASK,
+ .mode_reg = PCA9450_REG_BUCK2CTRL,
+ .mode_mask = BUCK2_FPWM,
},
},
{
.desc = {
.name = "buck4",
+ .supply_name = "inb45",
.of_match = of_match_ptr("BUCK4"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK4,
@@ -746,11 +956,17 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
.enable_mask = BUCK4_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK4CTRL,
+ .mode_mask = BUCK4_FPWM,
},
},
{
.desc = {
.name = "buck5",
+ .supply_name = "inb45",
.of_match = of_match_ptr("BUCK5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK5,
@@ -765,11 +981,17 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
.enable_mask = BUCK5_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK5CTRL,
+ .mode_mask = BUCK5_FPWM,
},
},
{
.desc = {
.name = "buck6",
+ .supply_name = "inb26",
.of_match = of_match_ptr("BUCK6"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_BUCK6,
@@ -784,11 +1006,17 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
.enable_mask = BUCK6_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
+ .of_map_mode = pca9450_map_mode,
+ },
+ .dvs = {
+ .mode_reg = PCA9450_REG_BUCK6CTRL,
+ .mode_mask = BUCK6_FPWM,
},
},
{
.desc = {
.name = "ldo1",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO1"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO1,
@@ -806,7 +1034,27 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
},
{
.desc = {
+ .name = "ldo3",
+ .supply_name = "inl1",
+ .of_match = of_match_ptr("LDO3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PCA9450_LDO3,
+ .ops = &pca9450_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PCA9450_LDO3_VOLTAGE_NUM,
+ .linear_ranges = pca9450_ldo34_volts,
+ .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
+ .vsel_reg = PCA9450_REG_LDO3CTRL,
+ .vsel_mask = LDO3OUT_MASK,
+ .enable_reg = PCA9450_REG_LDO3CTRL,
+ .enable_mask = LDO3_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
.name = "ldo4",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO4"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO4,
@@ -825,17 +1073,18 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
{
.desc = {
.name = "ldo5",
+ .supply_name = "inl1",
.of_match = of_match_ptr("LDO5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO5,
- .ops = &pca9450_ldo_regulator_ops,
+ .ops = &pca9450_ldo5_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
.linear_ranges = pca9450_ldo5_volts,
.n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
.vsel_reg = PCA9450_REG_LDO5CTRL_H,
.vsel_mask = LDO5HOUT_MASK,
- .enable_reg = PCA9450_REG_LDO5CTRL_H,
+ .enable_reg = PCA9450_REG_LDO5CTRL_L,
.enable_mask = LDO5H_EN_MASK,
.owner = THIS_MODULE,
},
@@ -880,15 +1129,170 @@ static irqreturn_t pca9450_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static int pca9450_i2c_restart_handler(struct sys_off_data *data)
+{
+ struct pca9450 *pca9450 = data->cb_data;
+ struct i2c_client *i2c = container_of(pca9450->dev, struct i2c_client, dev);
+
+ dev_dbg(&i2c->dev, "Restarting device..\n");
+ if (i2c_smbus_write_byte_data(i2c, PCA9450_REG_SWRST, SW_RST_COMMAND) == 0) {
+ /* tRESTART is 250ms, so 300 should be enough to make sure it happened */
+ mdelay(300);
+ /* When we get here, the PMIC didn't power cycle for some reason. so warn.*/
+ dev_warn(&i2c->dev, "Device didn't respond to restart command\n");
+ } else {
+ dev_err(&i2c->dev, "Restart command failed\n");
+ }
+
+ return 0;
+}
+
+static int pca9450_of_init(struct pca9450 *pca9450)
+{
+ struct i2c_client *i2c = container_of(pca9450->dev, struct i2c_client, dev);
+ int ret;
+ unsigned int val;
+ unsigned int reset_ctrl;
+ unsigned int rstb_deb_ctrl;
+ unsigned int t_on_deb, t_off_deb;
+ unsigned int t_on_step, t_off_step;
+ unsigned int t_restart;
+
+ if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset"))
+ reset_ctrl = WDOG_B_CFG_WARM;
+ else
+ reset_ctrl = WDOG_B_CFG_COLD_LDO12;
+
+ /* Set reset behavior on assertion of WDOG_B signal */
+ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL,
+ WDOG_B_CFG_MASK, reset_ctrl);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Failed to set WDOG_B reset behavior\n");
+
+ ret = of_property_read_u32(i2c->dev.of_node, "npx,pmic-rst-b-debounce-ms", &val);
+ if (ret == -EINVAL)
+ rstb_deb_ctrl = T_PMIC_RST_DEB_50MS;
+ else if (ret)
+ return ret;
+ else {
+ switch (val) {
+ case 10: rstb_deb_ctrl = T_PMIC_RST_DEB_10MS; break;
+ case 50: rstb_deb_ctrl = T_PMIC_RST_DEB_50MS; break;
+ case 100: rstb_deb_ctrl = T_PMIC_RST_DEB_100MS; break;
+ case 500: rstb_deb_ctrl = T_PMIC_RST_DEB_500MS; break;
+ case 1000: rstb_deb_ctrl = T_PMIC_RST_DEB_1S; break;
+ case 2000: rstb_deb_ctrl = T_PMIC_RST_DEB_2S; break;
+ case 4000: rstb_deb_ctrl = T_PMIC_RST_DEB_4S; break;
+ case 8000: rstb_deb_ctrl = T_PMIC_RST_DEB_8S; break;
+ default: return -EINVAL;
+ }
+ }
+ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL,
+ T_PMIC_RST_DEB_MASK, rstb_deb_ctrl);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Failed to set PMIC_RST_B debounce time\n");
+
+ ret = of_property_read_u32(i2c->dev.of_node, "nxp,pmic-on-req-on-debounce-us", &val);
+ if (ret == -EINVAL)
+ t_on_deb = T_ON_DEB_20MS;
+ else if (ret)
+ return ret;
+ else {
+ switch (val) {
+ case 120: t_on_deb = T_ON_DEB_120US; break;
+ case 20000: t_on_deb = T_ON_DEB_20MS; break;
+ case 100000: t_on_deb = T_ON_DEB_100MS; break;
+ case 750000: t_on_deb = T_ON_DEB_750MS; break;
+ default: return -EINVAL;
+ }
+ }
+
+ ret = of_property_read_u32(i2c->dev.of_node, "nxp,pmic-on-req-off-debounce-us", &val);
+ if (ret == -EINVAL)
+ t_off_deb = T_OFF_DEB_120US;
+ else if (ret)
+ return ret;
+ else {
+ switch (val) {
+ case 120: t_off_deb = T_OFF_DEB_120US; break;
+ case 2000: t_off_deb = T_OFF_DEB_2MS; break;
+ default: return -EINVAL;
+ }
+ }
+
+ ret = of_property_read_u32(i2c->dev.of_node, "nxp,power-on-step-ms", &val);
+ if (ret == -EINVAL)
+ t_on_step = T_ON_STEP_2MS;
+ else if (ret)
+ return ret;
+ else {
+ switch (val) {
+ case 1: t_on_step = T_ON_STEP_1MS; break;
+ case 2: t_on_step = T_ON_STEP_2MS; break;
+ case 4: t_on_step = T_ON_STEP_4MS; break;
+ case 8: t_on_step = T_ON_STEP_8MS; break;
+ default: return -EINVAL;
+ }
+ }
+
+ ret = of_property_read_u32(i2c->dev.of_node, "nxp,power-down-step-ms", &val);
+ if (ret == -EINVAL)
+ t_off_step = T_OFF_STEP_8MS;
+ else if (ret)
+ return ret;
+ else {
+ switch (val) {
+ case 2: t_off_step = T_OFF_STEP_2MS; break;
+ case 4: t_off_step = T_OFF_STEP_4MS; break;
+ case 8: t_off_step = T_OFF_STEP_8MS; break;
+ case 16: t_off_step = T_OFF_STEP_16MS; break;
+ default: return -EINVAL;
+ }
+ }
+
+ ret = of_property_read_u32(i2c->dev.of_node, "nxp,restart-ms", &val);
+ if (ret == -EINVAL)
+ t_restart = T_RESTART_250MS;
+ else if (ret)
+ return ret;
+ else {
+ switch (val) {
+ case 250: t_restart = T_RESTART_250MS; break;
+ case 500: t_restart = T_RESTART_500MS; break;
+ default: return -EINVAL;
+ }
+ }
+
+ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_PWRCTRL,
+ T_ON_DEB_MASK | T_OFF_DEB_MASK | T_ON_STEP_MASK |
+ T_OFF_STEP_MASK | T_RESTART_MASK,
+ t_on_deb | t_off_deb | t_on_step |
+ t_off_step | t_restart);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to set PWR_CTRL debounce configuration\n");
+
+ if (of_property_read_bool(i2c->dev.of_node, "nxp,i2c-lt-enable")) {
+ /* Enable I2C Level Translator */
+ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_CONFIG2,
+ I2C_LT_MASK, I2C_LT_ON_STANDBY_RUN);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to enable I2C level translator\n");
+ }
+
+ return 0;
+}
+
static int pca9450_i2c_probe(struct i2c_client *i2c)
{
enum pca9450_chip_type type = (unsigned int)(uintptr_t)
of_device_get_match_data(&i2c->dev);
- const struct pca9450_regulator_desc *regulator_desc;
+ const struct pca9450_regulator_desc *regulator_desc;
struct regulator_config config = { };
+ struct regulator_dev *ldo5;
struct pca9450 *pca9450;
unsigned int device_id, i;
- unsigned int reset_ctrl;
int ret;
pca9450 = devm_kzalloc(&i2c->dev, sizeof(struct pca9450), GFP_KERNEL);
@@ -905,6 +1309,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
pca9450->rcnt = ARRAY_SIZE(pca9450bc_regulators);
break;
case PCA9450_TYPE_PCA9451A:
+ case PCA9450_TYPE_PCA9452:
regulator_desc = pca9451a_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9451a_regulators);
break;
@@ -921,25 +1326,21 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
pca9450->regmap = devm_regmap_init_i2c(i2c,
&pca9450_regmap_config);
- if (IS_ERR(pca9450->regmap)) {
- dev_err(&i2c->dev, "regmap initialization failed\n");
- return PTR_ERR(pca9450->regmap);
- }
+ if (IS_ERR(pca9450->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->regmap),
+ "regmap initialization failed\n");
ret = regmap_read(pca9450->regmap, PCA9450_REG_DEV_ID, &device_id);
- if (ret) {
- dev_err(&i2c->dev, "Read device id error\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Read device id error\n");
/* Check your board and dts for match the right pmic */
if (((device_id >> 4) != 0x1 && type == PCA9450_TYPE_PCA9450A) ||
((device_id >> 4) != 0x3 && type == PCA9450_TYPE_PCA9450BC) ||
- ((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9451A)) {
- dev_err(&i2c->dev, "Device id(%x) mismatched\n",
- device_id >> 4);
- return -EINVAL;
- }
+ ((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9451A) ||
+ ((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9452))
+ return dev_err_probe(&i2c->dev, -EINVAL,
+ "Device id(%x) mismatched\n", device_id >> 4);
for (i = 0; i < pca9450->rcnt; i++) {
const struct regulator_desc *desc;
@@ -949,17 +1350,20 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
r = &regulator_desc[i];
desc = &r->desc;
+ if (type == PCA9450_TYPE_PCA9451A && !strcmp(desc->name, "ldo3"))
+ continue;
+
config.regmap = pca9450->regmap;
config.dev = pca9450->dev;
+ config.driver_data = pca9450;
rdev = devm_regulator_register(pca9450->dev, desc, &config);
- if (IS_ERR(rdev)) {
- ret = PTR_ERR(rdev);
- dev_err(pca9450->dev,
- "Failed to register regulator(%s): %d\n",
- desc->name, ret);
- return ret;
- }
+ if (IS_ERR(rdev))
+ return dev_err_probe(pca9450->dev, PTR_ERR(rdev),
+ "Failed to register regulator(%s)\n", desc->name);
+
+ if (!strcmp(desc->name, "ldo5"))
+ ldo5 = rdev;
}
if (pca9450->irq) {
@@ -967,65 +1371,47 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
pca9450_irq_handler,
(IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
"pca9450-irq", pca9450);
- if (ret != 0) {
- dev_err(pca9450->dev, "Failed to request IRQ: %d\n",
- pca9450->irq);
- return ret;
- }
+ if (ret != 0)
+ return dev_err_probe(pca9450->dev, ret, "Failed to request IRQ: %d\n",
+ pca9450->irq);
+
/* Unmask all interrupt except PWRON/WDOG/RSVD */
ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK,
IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS |
IRQ_THERM_105 | IRQ_THERM_125,
IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD);
- if (ret) {
- dev_err(&i2c->dev, "Unmask irq error\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
}
/* Clear PRESET_EN bit in BUCK123_DVS to use DVS registers */
ret = regmap_clear_bits(pca9450->regmap, PCA9450_REG_BUCK123_DVS,
BUCK123_PRESET_EN);
- if (ret) {
- dev_err(&i2c->dev, "Failed to clear PRESET_EN bit: %d\n", ret);
- return ret;
- }
-
- if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset"))
- reset_ctrl = WDOG_B_CFG_WARM;
- else
- reset_ctrl = WDOG_B_CFG_COLD_LDO12;
-
- /* Set reset behavior on assertion of WDOG_B signal */
- ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL,
- WDOG_B_CFG_MASK, reset_ctrl);
- if (ret) {
- dev_err(&i2c->dev, "Failed to set WDOG_B reset behavior\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Failed to clear PRESET_EN bit\n");
- if (of_property_read_bool(i2c->dev.of_node, "nxp,i2c-lt-enable")) {
- /* Enable I2C Level Translator */
- ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_CONFIG2,
- I2C_LT_MASK, I2C_LT_ON_STANDBY_RUN);
- if (ret) {
- dev_err(&i2c->dev,
- "Failed to enable I2C level translator\n");
- return ret;
- }
- }
+ ret = pca9450_of_init(pca9450);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unable to parse OF data\n");
/*
- * The driver uses the LDO5CTRL_H register to control the LDO5 regulator.
- * This is only valid if the SD_VSEL input of the PMIC is high. Let's
- * check if the pin is available as GPIO and set it to high.
+ * For LDO5 we need to be able to check the status of the SD_VSEL input in
+ * order to know which control register is used. Most boards connect SD_VSEL
+ * to the VSELECT signal, so we can use the GPIO that is internally routed
+ * to this signal (if SION bit is set in IOMUX).
*/
- pca9450->sd_vsel_gpio = gpiod_get_optional(pca9450->dev, "sd-vsel", GPIOD_OUT_HIGH);
+ pca9450->sd_vsel_gpio = gpiod_get_optional(&ldo5->dev, "sd-vsel", GPIOD_IN);
+ if (IS_ERR(pca9450->sd_vsel_gpio))
+ return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->sd_vsel_gpio),
+ "Failed to get SD_VSEL GPIO\n");
- if (IS_ERR(pca9450->sd_vsel_gpio)) {
- dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n");
- return PTR_ERR(pca9450->sd_vsel_gpio);
- }
+ pca9450->sd_vsel_fixed_low =
+ of_property_read_bool(ldo5->dev.of_node, "nxp,sd-vsel-fixed-low");
+
+ if (devm_register_sys_off_handler(&i2c->dev, SYS_OFF_MODE_RESTART,
+ PCA9450_RESTART_HANDLER_PRIORITY,
+ pca9450_i2c_restart_handler, pca9450))
+ dev_warn(&i2c->dev, "Failed to register restart handler\n");
dev_info(&i2c->dev, "%s probed.\n",
type == PCA9450_TYPE_PCA9450A ? "pca9450a" :
@@ -1051,6 +1437,10 @@ static const struct of_device_id pca9450_of_match[] = {
.compatible = "nxp,pca9451a",
.data = (void *)PCA9450_TYPE_PCA9451A,
},
+ {
+ .compatible = "nxp,pca9452",
+ .data = (void *)PCA9450_TYPE_PCA9452,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, pca9450_of_match);
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
deleted file mode 100644
index 9f08a62c800e..000000000000
--- a/drivers/regulator/pcf50633-regulator.c
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* NXP PCF50633 PMIC Driver
- *
- * (C) 2006-2008 by Openmoko, Inc.
- * Author: Balaji Rao <balajirrao@openmoko.org>
- * All rights reserved.
- *
- * Broken down from monstrous PCF50633 driver mainly by
- * Harald Welte and Andy Green and Werner Almesberger
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-
-#include <linux/mfd/pcf50633/core.h>
-#include <linux/mfd/pcf50633/pmic.h>
-
-#define PCF50633_REGULATOR(_name, _id, _min_uV, _uV_step, _min_sel, _n) \
- { \
- .name = _name, \
- .id = PCF50633_REGULATOR_##_id, \
- .ops = &pcf50633_regulator_ops, \
- .n_voltages = _n, \
- .min_uV = _min_uV, \
- .uV_step = _uV_step, \
- .linear_min_sel = _min_sel, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .vsel_reg = PCF50633_REG_##_id##OUT, \
- .vsel_mask = 0xff, \
- .enable_reg = PCF50633_REG_##_id##OUT + 1, \
- .enable_mask = PCF50633_REGULATOR_ON, \
- }
-
-static const struct regulator_ops pcf50633_regulator_ops = {
- .set_voltage_sel = regulator_set_voltage_sel_regmap,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .list_voltage = regulator_list_voltage_linear,
- .map_voltage = regulator_map_voltage_linear,
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
-};
-
-static const struct regulator_desc regulators[] = {
- [PCF50633_REGULATOR_AUTO] =
- PCF50633_REGULATOR("auto", AUTO, 1800000, 25000, 0x2f, 128),
- [PCF50633_REGULATOR_DOWN1] =
- PCF50633_REGULATOR("down1", DOWN1, 625000, 25000, 0, 96),
- [PCF50633_REGULATOR_DOWN2] =
- PCF50633_REGULATOR("down2", DOWN2, 625000, 25000, 0, 96),
- [PCF50633_REGULATOR_LDO1] =
- PCF50633_REGULATOR("ldo1", LDO1, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO2] =
- PCF50633_REGULATOR("ldo2", LDO2, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO3] =
- PCF50633_REGULATOR("ldo3", LDO3, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO4] =
- PCF50633_REGULATOR("ldo4", LDO4, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO5] =
- PCF50633_REGULATOR("ldo5", LDO5, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO6] =
- PCF50633_REGULATOR("ldo6", LDO6, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_HCLDO] =
- PCF50633_REGULATOR("hcldo", HCLDO, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_MEMLDO] =
- PCF50633_REGULATOR("memldo", MEMLDO, 900000, 100000, 0, 28),
-};
-
-static int pcf50633_regulator_probe(struct platform_device *pdev)
-{
- struct regulator_dev *rdev;
- struct pcf50633 *pcf;
- struct regulator_config config = { };
-
- /* Already set by core driver */
- pcf = dev_to_pcf50633(pdev->dev.parent);
-
- config.dev = &pdev->dev;
- config.init_data = dev_get_platdata(&pdev->dev);
- config.driver_data = pcf;
- config.regmap = pcf->regmap;
-
- rdev = devm_regulator_register(&pdev->dev, &regulators[pdev->id],
- &config);
- if (IS_ERR(rdev))
- return PTR_ERR(rdev);
-
- platform_set_drvdata(pdev, rdev);
-
- if (pcf->pdata->regulator_registered)
- pcf->pdata->regulator_registered(pcf, pdev->id);
-
- return 0;
-}
-
-static struct platform_driver pcf50633_regulator_driver = {
- .driver = {
- .name = "pcf50633-regulator",
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
- },
- .probe = pcf50633_regulator_probe,
-};
-
-static int __init pcf50633_regulator_init(void)
-{
- return platform_driver_register(&pcf50633_regulator_driver);
-}
-subsys_initcall(pcf50633_regulator_init);
-
-static void __exit pcf50633_regulator_exit(void)
-{
- platform_driver_unregister(&pcf50633_regulator_driver);
-}
-module_exit(pcf50633_regulator_exit);
-
-MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
-MODULE_DESCRIPTION("PCF50633 regulator driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pcf50633-regulator");
diff --git a/drivers/regulator/pf0900-regulator.c b/drivers/regulator/pf0900-regulator.c
new file mode 100644
index 000000000000..b5effee32917
--- /dev/null
+++ b/drivers/regulator/pf0900-regulator.c
@@ -0,0 +1,975 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2025 NXP.
+// NXP PF0900 pmic driver
+
+#include <linux/bitfield.h>
+#include <linux/crc8.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+enum pf0900_regulators {
+ PF0900_SW1 = 0,
+ PF0900_SW2,
+ PF0900_SW3,
+ PF0900_SW4,
+ PF0900_SW5,
+ PF0900_LDO1,
+ PF0900_LDO2,
+ PF0900_LDO3,
+ PF0900_VAON,
+ PF0900_REGULATOR_CNT,
+};
+
+enum {
+ PF0900_DVS_LEVEL_RUN = 0,
+ PF0900_DVS_LEVEL_STANDBY,
+ PF0900_DVS_LEVEL_MAX,
+};
+
+
+#define PF0900_VAON_VOLTAGE_NUM 0x03
+#define PF0900_SW_VOLTAGE_NUM 0x100
+#define PF0900_LDO_VOLTAGE_NUM 0x20
+
+#define REGU_SW_CNT 0x5
+#define REGU_LDO_VAON_CNT 0x4
+
+enum {
+ PF0900_REG_DEV_ID = 0x00,
+ PF0900_REG_DEV_FAM = 0x01,
+ PF0900_REG_REV_ID = 0x02,
+ PF0900_REG_PROG_ID1 = 0x03,
+ PF0900_REG_PROG_ID2 = 0x04,
+ PF0900_REG_SYSTEM_INT = 0x05,
+ PF0900_REG_STATUS1_INT = 0x06,
+ PF0900_REG_STATUS1_MSK = 0x07,
+ PF0900_REG_STATUS1_SNS = 0x08,
+ PF0900_REG_STATUS2_INT = 0x09,
+ PF0900_REG_STATUS2_MSK = 0x0A,
+ PF0900_REG_STATUS2_SNS = 0x0B,
+ PF0900_REG_STATUS3_INT = 0x0C,
+ PF0900_REG_STATUS3_MSK = 0x0D,
+ PF0900_REG_SW_MODE_INT = 0x0E,
+ PF0900_REG_SW_MODE_MSK = 0x0F,
+ PF0900_REG_SW_ILIM_INT = 0x10,
+ PF0900_REG_SW_ILIM_MSK = 0x11,
+ PF0900_REG_SW_ILIM_SNS = 0x12,
+ PF0900_REG_LDO_ILIM_INT = 0x13,
+ PF0900_REG_LDO_ILIM_MSK = 0x14,
+ PF0900_REG_LDO_ILIM_SNS = 0x15,
+ PF0900_REG_SW_UV_INT = 0x16,
+ PF0900_REG_SW_UV_MSK = 0x17,
+ PF0900_REG_SW_UV_SNS = 0x18,
+ PF0900_REG_SW_OV_INT = 0x19,
+ PF0900_REG_SW_OV_MSK = 0x1A,
+ PF0900_REG_SW_OV_SNS = 0x1B,
+ PF0900_REG_LDO_UV_INT = 0x1C,
+ PF0900_REG_LDO_UV_MSK = 0x1D,
+ PF0900_REG_LDO_UV_SNS = 0x1E,
+ PF0900_REG_LDO_OV_INT = 0x1F,
+ PF0900_REG_LDO_OV_MSK = 0x20,
+ PF0900_REG_LDO_OV_SNS = 0x21,
+ PF0900_REG_PWRON_INT = 0x22,
+ PF0900_REG_IO_INT = 0x24,
+ PF0900_REG_IO_MSK = 0x25,
+ PF0900_REG_IO_SNS = 0x26,
+ PF0900_REG_IOSHORT_SNS = 0x27,
+ PF0900_REG_ABIST_OV1 = 0x28,
+ PF0900_REG_ABIST_OV2 = 0x29,
+ PF0900_REG_ABIST_UV1 = 0x2A,
+ PF0900_REG_ABIST_UV2 = 0x2B,
+ PF0900_REG_ABIST_IO = 0x2C,
+ PF0900_REG_TEST_FLAGS = 0x2D,
+ PF0900_REG_HFAULT_FLAGS = 0x2E,
+ PF0900_REG_FAULT_FLAGS = 0x2F,
+ PF0900_REG_FS0B_CFG = 0x30,
+ PF0900_REG_FCCU_CFG = 0x31,
+ PF0900_REG_RSTB_CFG1 = 0x32,
+ PF0900_REG_SYSTEM_CMD = 0x33,
+ PF0900_REG_FS0B_CMD = 0x34,
+ PF0900_REG_SECURE_WR1 = 0x35,
+ PF0900_REG_SECURE_WR2 = 0x36,
+ PF0900_REG_VMON_CFG1 = 0x37,
+ PF0900_REG_SYS_CFG1 = 0x38,
+ PF0900_REG_GPO_CFG = 0x39,
+ PF0900_REG_GPO_CTRL = 0x3A,
+ PF0900_REG_PWRUP_CFG = 0x3B,
+ PF0900_REG_RSTB_PWRUP = 0x3C,
+ PF0900_REG_GPIO1_PWRUP = 0x3D,
+ PF0900_REG_GPIO2_PWRUP = 0x3E,
+ PF0900_REG_GPIO3_PWRUP = 0x3F,
+ PF0900_REG_GPIO4_PWRUP = 0x40,
+ PF0900_REG_VMON1_PWRUP = 0x41,
+ PF0900_REG_VMON2_PWRUP = 0x42,
+ PF0900_REG_SW1_PWRUP = 0x43,
+ PF0900_REG_SW2_PWRUP = 0x44,
+ PF0900_REG_SW3_PWRUP = 0x45,
+ PF0900_REG_SW4_PWRUP = 0x46,
+ PF0900_REG_SW5_PWRUP = 0x47,
+ PF0900_REG_LDO1_PWRUP = 0x48,
+ PF0900_REG_LDO2_PWRUP = 0x49,
+ PF0900_REG_LDO3_PWRUP = 0x4A,
+ PF0900_REG_VAON_PWRUP = 0x4B,
+ PF0900_REG_FREQ_CTRL = 0x4C,
+ PF0900_REG_PWRON_CFG = 0x4D,
+ PF0900_REG_WD_CTRL1 = 0x4E,
+ PF0900_REG_WD_CTRL2 = 0x4F,
+ PF0900_REG_WD_CFG1 = 0x50,
+ PF0900_REG_WD_CFG2 = 0x51,
+ PF0900_REG_WD_CNT1 = 0x52,
+ PF0900_REG_WD_CNT2 = 0x53,
+ PF0900_REG_FAULT_CFG = 0x54,
+ PF0900_REG_FAULT_CNT = 0x55,
+ PF0900_REG_DFS_CNT = 0x56,
+ PF0900_REG_AMUX_CFG = 0x57,
+ PF0900_REG_VMON1_RUN_CFG = 0x58,
+ PF0900_REG_VMON1_STBY_CFG = 0x59,
+ PF0900_REG_VMON1_CTRL = 0x5A,
+ PF0900_REG_VMON2_RUN_CFG = 0x5B,
+ PF0900_REG_VMON2_STBY_CFG = 0x5C,
+ PF0900_REG_VMON2_CTRL = 0x5D,
+ PF0900_REG_SW1_VRUN = 0x5E,
+ PF0900_REG_SW1_VSTBY = 0x5F,
+ PF0900_REG_SW1_MODE = 0x60,
+ PF0900_REG_SW1_CFG1 = 0x61,
+ PF0900_REG_SW1_CFG2 = 0x62,
+ PF0900_REG_SW2_VRUN = 0x63,
+ PF0900_REG_SW2_VSTBY = 0x64,
+ PF0900_REG_SW2_MODE = 0x65,
+ PF0900_REG_SW2_CFG1 = 0x66,
+ PF0900_REG_SW2_CFG2 = 0x67,
+ PF0900_REG_SW3_VRUN = 0x68,
+ PF0900_REG_SW3_VSTBY = 0x69,
+ PF0900_REG_SW3_MODE = 0x6A,
+ PF0900_REG_SW3_CFG1 = 0x6B,
+ PF0900_REG_SW3_CFG2 = 0x6C,
+ PF0900_REG_SW4_VRUN = 0x6D,
+ PF0900_REG_SW4_VSTBY = 0x6E,
+ PF0900_REG_SW4_MODE = 0x6F,
+ PF0900_REG_SW4_CFG1 = 0x70,
+ PF0900_REG_SW4_CFG2 = 0x71,
+ PF0900_REG_SW5_VRUN = 0x72,
+ PF0900_REG_SW5_VSTBY = 0x73,
+ PF0900_REG_SW5_MODE = 0x74,
+ PF0900_REG_SW5_CFG1 = 0x75,
+ PF0900_REG_SW5_CFG2 = 0x76,
+ PF0900_REG_LDO1_RUN = 0x77,
+ PF0900_REG_LDO1_STBY = 0x78,
+ PF0900_REG_LDO1_CFG2 = 0x79,
+ PF0900_REG_LDO2_RUN = 0x7A,
+ PF0900_REG_LDO2_STBY = 0x7B,
+ PF0900_REG_LDO2_CFG2 = 0x7C,
+ PF0900_REG_LDO3_RUN = 0x7D,
+ PF0900_REG_LDO3_STBY = 0x7E,
+ PF0900_REG_LDO3_CFG2 = 0x7F,
+ PF0900_REG_VAON_CFG1 = 0x80,
+ PF0900_REG_VAON_CFG2 = 0x81,
+ PF0900_REG_SYS_DIAG = 0x82,
+ PF0900_MAX_REGISTER,
+};
+
+/* PF0900 SW MODE */
+#define SW_RUN_MODE_OFF 0x00
+#define SW_RUN_MODE_PWM 0x01
+#define SW_RUN_MODE_PFM 0x02
+#define SW_STBY_MODE_OFF 0x00
+#define SW_STBY_MODE_PWM 0x04
+#define SW_STBY_MODE_PFM 0x08
+
+/* PF0900 SW MODE MASK */
+#define SW_RUN_MODE_MASK GENMASK(1, 0)
+#define SW_STBY_MODE_MASK GENMASK(3, 2)
+
+/* PF0900 SW VRUN/VSTBY MASK */
+#define PF0900_SW_VOL_MASK GENMASK(7, 0)
+
+/* PF0900_REG_VAON_CFG1 bits */
+#define PF0900_VAON_1P8V 0x01
+
+#define PF0900_VAON_MASK GENMASK(1, 0)
+
+/* PF0900_REG_SWX_CFG1 MASK */
+#define PF0900_SW_DVS_MASK GENMASK(4, 3)
+
+/* PF0900_REG_LDO_RUN MASK */
+#define VLDO_RUN_MASK GENMASK(4, 0)
+#define LDO_RUN_EN_MASK BIT(5)
+
+/* PF0900_REG_STATUS1_INT bits */
+#define PF0900_IRQ_PWRUP BIT(3)
+
+/* PF0900_REG_ILIM_INT bits */
+#define PF0900_IRQ_SW1_IL BIT(0)
+#define PF0900_IRQ_SW2_IL BIT(1)
+#define PF0900_IRQ_SW3_IL BIT(2)
+#define PF0900_IRQ_SW4_IL BIT(3)
+#define PF0900_IRQ_SW5_IL BIT(4)
+
+#define PF0900_IRQ_LDO1_IL BIT(0)
+#define PF0900_IRQ_LDO2_IL BIT(1)
+#define PF0900_IRQ_LDO3_IL BIT(2)
+
+/* PF0900_REG_UV_INT bits */
+#define PF0900_IRQ_SW1_UV BIT(0)
+#define PF0900_IRQ_SW2_UV BIT(1)
+#define PF0900_IRQ_SW3_UV BIT(2)
+#define PF0900_IRQ_SW4_UV BIT(3)
+#define PF0900_IRQ_SW5_UV BIT(4)
+
+#define PF0900_IRQ_LDO1_UV BIT(0)
+#define PF0900_IRQ_LDO2_UV BIT(1)
+#define PF0900_IRQ_LDO3_UV BIT(2)
+#define PF0900_IRQ_VAON_UV BIT(3)
+
+/* PF0900_REG_OV_INT bits */
+#define PF0900_IRQ_SW1_OV BIT(0)
+#define PF0900_IRQ_SW2_OV BIT(1)
+#define PF0900_IRQ_SW3_OV BIT(2)
+#define PF0900_IRQ_SW4_OV BIT(3)
+#define PF0900_IRQ_SW5_OV BIT(4)
+
+#define PF0900_IRQ_LDO1_OV BIT(0)
+#define PF0900_IRQ_LDO2_OV BIT(1)
+#define PF0900_IRQ_LDO3_OV BIT(2)
+#define PF0900_IRQ_VAON_OV BIT(3)
+
+struct pf0900_regulator_desc {
+ struct regulator_desc desc;
+ unsigned int suspend_enable_mask;
+ unsigned int suspend_voltage_reg;
+ unsigned int suspend_voltage_cache;
+};
+
+struct pf0900_drvdata {
+ const struct pf0900_regulator_desc *desc;
+ unsigned int rcnt;
+};
+
+struct pf0900 {
+ struct device *dev;
+ struct regmap *regmap;
+ const struct pf0900_drvdata *drvdata;
+ struct regulator_dev *rdevs[PF0900_REGULATOR_CNT];
+ int irq;
+ unsigned short addr;
+ bool crc_en;
+};
+
+enum pf0900_regulator_type {
+ PF0900_SW = 0,
+ PF0900_LDO,
+};
+
+#define PF0900_REGU_IRQ(_reg, _type, _event) \
+ { \
+ .reg = _reg, \
+ .type = _type, \
+ .event = _event, \
+ }
+
+struct pf0900_regulator_irq {
+ unsigned int reg;
+ unsigned int type;
+ unsigned int event;
+};
+
+static const struct regmap_range pf0900_range = {
+ .range_min = PF0900_REG_DEV_ID,
+ .range_max = PF0900_REG_SYS_DIAG,
+};
+
+static const struct regmap_access_table pf0900_volatile_regs = {
+ .yes_ranges = &pf0900_range,
+ .n_yes_ranges = 1,
+};
+
+static const struct regmap_config pf0900_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &pf0900_volatile_regs,
+ .max_register = PF0900_MAX_REGISTER - 1,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static uint8_t crc8_j1850(unsigned short addr, unsigned int reg,
+ unsigned int val)
+{
+ uint8_t crcBuf[3];
+ uint8_t t_crc;
+ uint8_t i, j;
+
+ crcBuf[0] = addr;
+ crcBuf[1] = reg;
+ crcBuf[2] = val;
+ t_crc = 0xFF;
+
+ /*
+ * The CRC calculation is based on the standard CRC-8-SAE as
+ * defined in the SAE-J1850 specification with the following
+ * characteristics.
+ * Polynomial = 0x1D
+ * Initial Value = 0xFF
+ * The CRC byte is calculated by shifting 24-bit data through
+ * the CRC polynomial.The 24-bits package is built as follows:
+ * DEVICE_ADDR[b8] + REGISTER_ADDR [b8] +DATA[b8]
+ * The DEVICE_ADDR is calculated as the 7-bit slave address
+ * shifted left one space plus the corresponding read/write bit.
+ * (7Bit Address [b7] << 1 ) + R/W = DEVICE_ADDR[b8]
+ */
+ for (i = 0; i < sizeof(crcBuf); i++) {
+ t_crc ^= crcBuf[i];
+ for (j = 0; j < 8; j++) {
+ if ((t_crc & 0x80) != 0) {
+ t_crc <<= 1;
+ t_crc ^= 0x1D;
+ } else {
+ t_crc <<= 1;
+ }
+ }
+ }
+
+ return t_crc;
+}
+
+static int pf0900_regmap_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct pf0900 *pf0900 = dev_get_drvdata(dev);
+ int ret;
+ u8 crc;
+
+ if (!pf0900 || !pf0900->dev)
+ return -EINVAL;
+
+ if (reg >= PF0900_MAX_REGISTER) {
+ dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg);
+ return -EINVAL;
+ }
+
+ if (pf0900->crc_en) {
+ ret = i2c_smbus_read_word_data(i2c, reg);
+ if (ret < 0) {
+ dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret);
+ return ret;
+ }
+
+ *val = (u16)ret;
+ crc = crc8_j1850(pf0900->addr << 1 | 0x1, reg, FIELD_GET(GENMASK(7, 0), *val));
+ if (crc != FIELD_GET(GENMASK(15, 8), *val)) {
+ dev_err(pf0900->dev, "Crc check error!\n");
+ return -EINVAL;
+ }
+ *val = FIELD_GET(GENMASK(7, 0), *val);
+ } else {
+ ret = i2c_smbus_read_byte_data(i2c, reg);
+ if (ret < 0) {
+ dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret);
+ return ret;
+ }
+ *val = ret;
+ }
+
+ return 0;
+}
+
+static int pf0900_regmap_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct pf0900 *pf0900 = dev_get_drvdata(dev);
+ uint8_t data[2];
+ int ret;
+
+ if (!pf0900 || !pf0900->dev)
+ return -EINVAL;
+
+ if (reg >= PF0900_MAX_REGISTER) {
+ dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg);
+ return -EINVAL;
+ }
+
+ data[0] = val;
+ if (pf0900->crc_en) {
+ /* Get CRC */
+ data[1] = crc8_j1850(pf0900->addr << 1, reg, data[0]);
+ val = FIELD_PREP(GENMASK(15, 8), data[1]) | data[0];
+ ret = i2c_smbus_write_word_data(i2c, reg, val);
+ } else {
+ ret = i2c_smbus_write_byte_data(i2c, reg, data[0]);
+ }
+
+ if (ret) {
+ dev_err(pf0900->dev, "Write reg=0x%x error!\n", reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pf0900_suspend_enable(struct regulator_dev *rdev)
+{
+ struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev);
+ struct regmap *rmap = rdev_get_regmap(rdev);
+
+ return regmap_update_bits(rmap, rdata->desc.enable_reg,
+ rdata->suspend_enable_mask, SW_STBY_MODE_PFM);
+}
+
+static int pf0900_suspend_disable(struct regulator_dev *rdev)
+{
+ struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev);
+ struct regmap *rmap = rdev_get_regmap(rdev);
+
+ return regmap_update_bits(rmap, rdata->desc.enable_reg,
+ rdata->suspend_enable_mask, SW_STBY_MODE_OFF);
+}
+
+static int pf0900_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev);
+ struct regmap *rmap = rdev_get_regmap(rdev);
+ int ret;
+
+ if (rdata->suspend_voltage_cache == uV)
+ return 0;
+
+ ret = regulator_map_voltage_iterate(rdev, uV, uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
+ return ret;
+ }
+
+ dev_dbg(rdev_get_dev(rdev), "uV: %i, reg: 0x%x, msk: 0x%x, val: 0x%x\n",
+ uV, rdata->suspend_voltage_reg, rdata->desc.vsel_mask, ret);
+ ret = regmap_update_bits(rmap, rdata->suspend_voltage_reg,
+ rdata->desc.vsel_mask, ret);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to set %i uV\n", uV);
+ return ret;
+ }
+
+ rdata->suspend_voltage_cache = uV;
+
+ return 0;
+}
+
+static const struct regmap_bus pf0900_regmap_bus = {
+ .reg_read = pf0900_regmap_read,
+ .reg_write = pf0900_regmap_write,
+};
+
+static const struct regulator_ops pf0900_avon_regulator_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static const struct regulator_ops pf0900_dvs_sw_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 = regulator_set_ramp_delay_regmap,
+ .set_suspend_enable = pf0900_suspend_enable,
+ .set_suspend_disable = pf0900_suspend_disable,
+ .set_suspend_voltage = pf0900_set_suspend_voltage,
+};
+
+static const struct regulator_ops pf0900_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 = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+/*
+ * SW1/2/3/4/5
+ * SW1_DVS[1:0] SW1 DVS ramp rate setting
+ * 00: 15.6mV/8usec
+ * 01: 15.6mV/4usec
+ * 10: 15.6mV/2usec
+ * 11: 15.6mV/1usec
+ */
+static const unsigned int pf0900_dvs_sw_ramp_table[] = {
+ 1950, 3900, 7800, 15600
+};
+
+/* VAON 1.8V, 3.0V, or 3.3V */
+static const int pf0900_vaon_voltages[] = {
+ 0, 1800000, 3000000, 3300000,
+};
+
+/*
+ * SW1 0.5V to 3.3V
+ * 0.5V to 1.35V (6.25mV step)
+ * 1.8V to 2.5V (125mV step)
+ * 2.8V to 3.3V (250mV step)
+ */
+static const struct linear_range pf0900_dvs_sw1_volts[] = {
+ REGULATOR_LINEAR_RANGE(0, 0x00, 0x08, 0),
+ REGULATOR_LINEAR_RANGE(500000, 0x09, 0x91, 6250),
+ REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500),
+ REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0),
+ REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000),
+ REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0),
+};
+
+/*
+ * SW2/3/4/5 0.3V to 3.3V
+ * 0.45V to 1.35V (6.25mV step)
+ * 1.8V to 2.5V (125mV step)
+ * 2.8V to 3.3V (250mV step)
+ */
+static const struct linear_range pf0900_dvs_sw2345_volts[] = {
+ REGULATOR_LINEAR_RANGE(300000, 0x00, 0x00, 0),
+ REGULATOR_LINEAR_RANGE(450000, 0x01, 0x91, 6250),
+ REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500),
+ REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0),
+ REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000),
+ REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0),
+};
+
+/*
+ * LDO1
+ * 0.75V to 3.3V
+ */
+static const struct linear_range pf0900_ldo1_volts[] = {
+ REGULATOR_LINEAR_RANGE(750000, 0x00, 0x0F, 50000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000),
+};
+
+/*
+ * LDO2/3
+ * 0.65V to 3.3V (50mV step)
+ */
+static const struct linear_range pf0900_ldo23_volts[] = {
+ REGULATOR_LINEAR_RANGE(650000, 0x00, 0x0D, 50000),
+ REGULATOR_LINEAR_RANGE(1400000, 0x0E, 0x0F, 100000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000),
+};
+
+static const struct pf0900_regulator_desc pf0900_regulators[] = {
+ {
+ .desc = {
+ .name = "sw1",
+ .of_match = of_match_ptr("sw1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW1,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw1_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw1_volts),
+ .vsel_reg = PF0900_REG_SW1_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW1_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW1_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW1_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "sw2",
+ .of_match = of_match_ptr("sw2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW2,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw2345_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts),
+ .vsel_reg = PF0900_REG_SW2_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW2_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW2_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW2_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "sw3",
+ .of_match = of_match_ptr("sw3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW3,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw2345_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts),
+ .vsel_reg = PF0900_REG_SW3_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW3_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW3_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW3_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "sw4",
+ .of_match = of_match_ptr("sw4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW4,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw2345_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts),
+ .vsel_reg = PF0900_REG_SW4_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW4_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW4_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW4_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "sw5",
+ .of_match = of_match_ptr("sw5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_SW5,
+ .ops = &pf0900_dvs_sw_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_SW_VOLTAGE_NUM,
+ .linear_ranges = pf0900_dvs_sw2345_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts),
+ .vsel_reg = PF0900_REG_SW5_VRUN,
+ .vsel_mask = PF0900_SW_VOL_MASK,
+ .enable_reg = PF0900_REG_SW5_MODE,
+ .enable_mask = SW_RUN_MODE_MASK,
+ .enable_val = SW_RUN_MODE_PWM,
+ .ramp_reg = PF0900_REG_SW5_CFG1,
+ .ramp_mask = PF0900_SW_DVS_MASK,
+ .ramp_delay_table = pf0900_dvs_sw_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table),
+ .owner = THIS_MODULE,
+ },
+ .suspend_enable_mask = SW_STBY_MODE_MASK,
+ .suspend_voltage_reg = PF0900_REG_SW5_VSTBY,
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("ldo1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_LDO1,
+ .ops = &pf0900_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_LDO_VOLTAGE_NUM,
+ .linear_ranges = pf0900_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_ldo1_volts),
+ .vsel_reg = PF0900_REG_LDO1_RUN,
+ .vsel_mask = VLDO_RUN_MASK,
+ .enable_reg = PF0900_REG_LDO1_RUN,
+ .enable_mask = LDO_RUN_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("ldo2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_LDO2,
+ .ops = &pf0900_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_LDO_VOLTAGE_NUM,
+ .linear_ranges = pf0900_ldo23_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts),
+ .vsel_reg = PF0900_REG_LDO2_RUN,
+ .vsel_mask = VLDO_RUN_MASK,
+ .enable_reg = PF0900_REG_LDO2_RUN,
+ .enable_mask = LDO_RUN_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("ldo3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_LDO3,
+ .ops = &pf0900_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_LDO_VOLTAGE_NUM,
+ .linear_ranges = pf0900_ldo23_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts),
+ .vsel_reg = PF0900_REG_LDO3_RUN,
+ .vsel_mask = VLDO_RUN_MASK,
+ .enable_reg = PF0900_REG_LDO3_RUN,
+ .enable_mask = LDO_RUN_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "vaon",
+ .of_match = of_match_ptr("vaon"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF0900_VAON,
+ .ops = &pf0900_avon_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF0900_VAON_VOLTAGE_NUM,
+ .volt_table = pf0900_vaon_voltages,
+ .enable_reg = PF0900_REG_VAON_CFG1,
+ .enable_mask = PF0900_VAON_MASK,
+ .enable_val = PF0900_VAON_1P8V,
+ .vsel_reg = PF0900_REG_VAON_CFG1,
+ .vsel_mask = PF0900_VAON_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+struct pf0900_regulator_irq regu_irqs[] = {
+ PF0900_REGU_IRQ(PF0900_REG_SW_ILIM_INT, PF0900_SW, REGULATOR_ERROR_OVER_CURRENT_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_LDO_ILIM_INT, PF0900_LDO, REGULATOR_ERROR_OVER_CURRENT_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_SW_UV_INT, PF0900_SW, REGULATOR_ERROR_UNDER_VOLTAGE_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_LDO_UV_INT, PF0900_LDO, REGULATOR_ERROR_UNDER_VOLTAGE_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_SW_OV_INT, PF0900_SW, REGULATOR_ERROR_OVER_VOLTAGE_WARN),
+ PF0900_REGU_IRQ(PF0900_REG_LDO_OV_INT, PF0900_LDO, REGULATOR_ERROR_OVER_VOLTAGE_WARN),
+};
+
+static irqreturn_t pf0900_irq_handler(int irq, void *data)
+{
+ unsigned int val, regu, i, index;
+ struct pf0900 *pf0900 = data;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(regu_irqs); i++) {
+ ret = regmap_read(pf0900->regmap, regu_irqs[i].reg, &val);
+ if (ret < 0) {
+ dev_err(pf0900->dev, "Failed to read %d\n", ret);
+ return IRQ_NONE;
+ }
+ if (val) {
+ ret = regmap_write_bits(pf0900->regmap, regu_irqs[i].reg, val, val);
+ if (ret < 0) {
+ dev_err(pf0900->dev, "Failed to update %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ if (regu_irqs[i].type == PF0900_SW) {
+ for (index = 0; index < REGU_SW_CNT; index++) {
+ if (val & BIT(index)) {
+ regu = (enum pf0900_regulators)index;
+ regulator_notifier_call_chain(pf0900->rdevs[regu],
+ regu_irqs[i].event,
+ NULL);
+ }
+ }
+ } else if (regu_irqs[i].type == PF0900_LDO) {
+ for (index = 0; index < REGU_LDO_VAON_CNT; index++) {
+ if (val & BIT(index)) {
+ regu = (enum pf0900_regulators)index + PF0900_LDO1;
+ regulator_notifier_call_chain(pf0900->rdevs[regu],
+ regu_irqs[i].event,
+ NULL);
+ }
+ }
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pf0900_i2c_probe(struct i2c_client *i2c)
+{
+ const struct pf0900_regulator_desc *regulator_desc;
+ const struct pf0900_drvdata *drvdata = NULL;
+ struct device_node *np = i2c->dev.of_node;
+ unsigned int device_id, device_fam, i;
+ struct regulator_config config = { };
+ struct pf0900 *pf0900;
+ int ret;
+
+ if (!i2c->irq)
+ return dev_err_probe(&i2c->dev, -EINVAL, "No IRQ configured?\n");
+
+ pf0900 = devm_kzalloc(&i2c->dev, sizeof(struct pf0900), GFP_KERNEL);
+ if (!pf0900)
+ return -ENOMEM;
+
+ drvdata = device_get_match_data(&i2c->dev);
+ if (!drvdata)
+ return dev_err_probe(&i2c->dev, -EINVAL, "unable to find driver data\n");
+
+ regulator_desc = drvdata->desc;
+ pf0900->drvdata = drvdata;
+ pf0900->crc_en = of_property_read_bool(np, "nxp,i2c-crc-enable");
+ pf0900->irq = i2c->irq;
+ pf0900->dev = &i2c->dev;
+ pf0900->addr = i2c->addr;
+
+ dev_set_drvdata(&i2c->dev, pf0900);
+
+ pf0900->regmap = devm_regmap_init(&i2c->dev, &pf0900_regmap_bus, &i2c->dev,
+ &pf0900_regmap_config);
+ if (IS_ERR(pf0900->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(pf0900->regmap),
+ "regmap initialization failed\n");
+ ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_ID, &device_id);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Read device id error\n");
+
+ ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_FAM, &device_fam);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Read device fam error\n");
+
+ /* Check your board and dts for match the right pmic */
+ if (device_fam == 0x09 && (device_id & 0x1F) != 0x0)
+ return dev_err_probe(&i2c->dev, -EINVAL, "Device id(%x) mismatched\n",
+ device_id >> 4);
+
+ for (i = 0; i < drvdata->rcnt; i++) {
+ const struct regulator_desc *desc;
+ const struct pf0900_regulator_desc *r;
+
+ r = &regulator_desc[i];
+ desc = &r->desc;
+ config.regmap = pf0900->regmap;
+ config.driver_data = (void *)r;
+ config.dev = pf0900->dev;
+
+ pf0900->rdevs[i] = devm_regulator_register(pf0900->dev, desc, &config);
+ if (IS_ERR(pf0900->rdevs[i]))
+ return dev_err_probe(pf0900->dev, PTR_ERR(pf0900->rdevs[i]),
+ "Failed to register regulator(%s)\n", desc->name);
+ }
+
+ ret = devm_request_threaded_irq(pf0900->dev, pf0900->irq, NULL,
+ pf0900_irq_handler,
+ (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
+ "pf0900-irq", pf0900);
+
+ if (ret != 0)
+ return dev_err_probe(pf0900->dev, ret, "Failed to request IRQ: %d\n",
+ pf0900->irq);
+ /*
+ * The PWRUP_M is unmasked by default. When the device enter in RUN state,
+ * it will assert the PWRUP_I interrupt and assert the INTB pin to inform
+ * the MCU that it has finished the power up sequence properly.
+ */
+ ret = regmap_write_bits(pf0900->regmap, PF0900_REG_STATUS1_INT, PF0900_IRQ_PWRUP,
+ PF0900_IRQ_PWRUP);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Clean PWRUP_I error\n");
+
+ /* mask interrupt PWRUP */
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_STATUS1_MSK, PF0900_IRQ_PWRUP,
+ PF0900_IRQ_PWRUP);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_ILIM_MSK, PF0900_IRQ_SW1_IL |
+ PF0900_IRQ_SW2_IL | PF0900_IRQ_SW3_IL | PF0900_IRQ_SW4_IL |
+ PF0900_IRQ_SW5_IL, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_UV_MSK, PF0900_IRQ_SW1_UV |
+ PF0900_IRQ_SW2_UV | PF0900_IRQ_SW3_UV | PF0900_IRQ_SW4_UV |
+ PF0900_IRQ_SW5_UV, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_OV_MSK, PF0900_IRQ_SW1_OV |
+ PF0900_IRQ_SW2_OV | PF0900_IRQ_SW3_OV | PF0900_IRQ_SW4_OV |
+ PF0900_IRQ_SW5_OV, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_ILIM_MSK, PF0900_IRQ_LDO1_IL |
+ PF0900_IRQ_LDO2_IL | PF0900_IRQ_LDO3_IL, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_UV_MSK, PF0900_IRQ_LDO1_UV |
+ PF0900_IRQ_LDO2_UV | PF0900_IRQ_LDO3_UV | PF0900_IRQ_VAON_UV, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_OV_MSK, PF0900_IRQ_LDO1_OV |
+ PF0900_IRQ_LDO2_OV | PF0900_IRQ_LDO3_OV | PF0900_IRQ_VAON_OV, 0);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ return 0;
+}
+
+static struct pf0900_drvdata pf0900_drvdata = {
+ .desc = pf0900_regulators,
+ .rcnt = ARRAY_SIZE(pf0900_regulators),
+};
+
+static const struct of_device_id pf0900_of_match[] = {
+ { .compatible = "nxp,pf0900", .data = &pf0900_drvdata},
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, pf0900_of_match);
+
+static struct i2c_driver pf0900_i2c_driver = {
+ .driver = {
+ .name = "nxp-pf0900",
+ .of_match_table = pf0900_of_match,
+ },
+ .probe = pf0900_i2c_probe,
+};
+
+module_i2c_driver(pf0900_i2c_driver);
+
+MODULE_AUTHOR("Joy Zou <joy.zou@nxp.com>");
+MODULE_DESCRIPTION("NXP PF0900 Power Management IC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pf1550-regulator.c b/drivers/regulator/pf1550-regulator.c
new file mode 100644
index 000000000000..037b8ec94066
--- /dev/null
+++ b/drivers/regulator/pf1550-regulator.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// regulator driver for the PF1550
+//
+// Copyright (C) 2016 Freescale Semiconductor, Inc.
+// Robin Gong <yibin.gong@freescale.com>
+//
+// Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+// Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+//
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define PF1550_REGULATOR_IRQ_NR 11
+#define PF1550_MAX_REGULATOR 7
+
+struct pf1550_desc {
+ struct regulator_desc desc;
+ unsigned char stby_reg;
+ unsigned char stby_mask;
+ unsigned char stby_enable_reg;
+ unsigned char stby_enable_mask;
+};
+
+struct pf1550_regulator_info {
+ struct device *dev;
+ const struct pf1550_ddata *pf1550;
+ struct pf1550_desc regulator_descs[PF1550_MAX_REGULATOR];
+ struct regulator_dev *rdevs[PF1550_MAX_REGULATOR];
+};
+
+static const int pf1550_sw12_volts[] = {
+ 1100000, 1200000, 1350000, 1500000, 1800000, 2500000, 3000000, 3300000,
+};
+
+static const int pf1550_ldo13_volts[] = {
+ 750000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
+ 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
+static int pf1550_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ int id = rdev_get_id(rdev);
+ unsigned int ramp_bits = 0;
+ int ret;
+
+ if (id > PF1550_VREFDDR)
+ return -EACCES;
+
+ if (ramp_delay < 0 || ramp_delay > 6250)
+ return -EINVAL;
+
+ ramp_delay = 6250 / ramp_delay;
+ ramp_bits = ramp_delay >> 1;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg + 4, 0x10,
+ ramp_bits << 4);
+ if (ret < 0)
+ dev_err(&rdev->dev, "ramp failed, err %d\n", ret);
+
+ return ret;
+}
+
+static int pf1550_set_suspend_enable(struct regulator_dev *rdev)
+{
+ const struct pf1550_desc *desc = container_of_const(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ unsigned int val = desc->stby_enable_mask;
+
+ return regmap_update_bits(rdev->regmap, desc->stby_enable_reg,
+ desc->stby_enable_mask, val);
+}
+
+static int pf1550_set_suspend_disable(struct regulator_dev *rdev)
+{
+ const struct pf1550_desc *desc = container_of_const(rdev->desc,
+ struct pf1550_desc,
+ desc);
+
+ return regmap_update_bits(rdev->regmap, desc->stby_enable_reg,
+ desc->stby_enable_mask, 0);
+}
+
+static int pf1550_buck_set_table_suspend_voltage(struct regulator_dev *rdev,
+ int uV)
+{
+ const struct pf1550_desc *desc = container_of_const(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ int ret;
+
+ ret = regulator_map_voltage_ascend(rdev, uV, uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
+ return ret;
+ }
+
+ return regmap_update_bits(rdev->regmap, desc->stby_reg,
+ desc->stby_mask, ret);
+}
+
+static int pf1550_buck_set_linear_suspend_voltage(struct regulator_dev *rdev,
+ int uV)
+{
+ const struct pf1550_desc *desc = container_of_const(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ int ret;
+
+ ret = regulator_map_voltage_linear(rdev, uV, uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
+ return ret;
+ }
+
+ return regmap_update_bits(rdev->regmap, desc->stby_reg,
+ desc->stby_mask, ret);
+}
+
+static const struct regulator_ops pf1550_sw1_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_voltage = pf1550_buck_set_table_suspend_voltage,
+ .map_voltage = regulator_map_voltage_ascend,
+ .set_ramp_delay = pf1550_set_ramp_delay,
+};
+
+static const struct regulator_ops pf1550_sw2_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_voltage = pf1550_buck_set_linear_suspend_voltage,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_ramp_delay = pf1550_set_ramp_delay,
+};
+
+static const struct regulator_ops pf1550_ldo1_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static const struct regulator_ops pf1550_ldo2_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .map_voltage = regulator_map_voltage_linear,
+};
+
+static const struct regulator_ops pf1550_fixed_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+#define PF_VREF(_chip, match, _name, voltage) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = 1, \
+ .ops = &pf1550_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (voltage), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_SW(_chip, match, _name, min, max, mask, step) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pf1550_sw2_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .linear_min_sel = 0, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_reg = _chip ## _PMIC_REG_ ## _name ## _STBY_VOLT, \
+ .stby_mask = (mask), \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_LDO1(_chip, match, _name, mask, voltages) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ARRAY_SIZE(voltages), \
+ .ops = &pf1550_ldo1_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .volt_table = voltages, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_LDO2(_chip, match, _name, mask, min, max, step) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pf1550_ldo2_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .linear_min_sel = 0, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+static struct pf1550_desc pf1550_regulators[] = {
+ PF_SW(PF1550, "sw1", SW1, 600000, 1387500, 0x3f, 12500),
+ PF_SW(PF1550, "sw2", SW2, 600000, 1387500, 0x3f, 12500),
+ PF_SW(PF1550, "sw3", SW3, 1800000, 3300000, 0xf, 100000),
+ PF_VREF(PF1550, "vrefddr", VREFDDR, 1200000),
+ PF_LDO1(PF1550, "ldo1", LDO1, 0x1f, pf1550_ldo13_volts),
+ PF_LDO2(PF1550, "ldo2", LDO2, 0xf, 1800000, 3300000, 100000),
+ PF_LDO1(PF1550, "ldo3", LDO3, 0x1f, pf1550_ldo13_volts),
+};
+
+static irqreturn_t pf1550_regulator_irq_handler(int irq, void *data)
+{
+ struct pf1550_regulator_info *info = data;
+ struct device *dev = info->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ int i, irq_type = -1;
+ unsigned int event;
+
+ for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++)
+ if (irq == platform_get_irq(pdev, i))
+ irq_type = i;
+
+ switch (irq_type) {
+ /* The _LS interrupts indicate over-current event. The _HS interrupts
+ * which are more accurate and can detect catastrophic faults, issue
+ * an error event. The current limit FAULT interrupt is similar to the
+ * _HS'
+ */
+ case PF1550_PMIC_IRQ_SW1_LS:
+ case PF1550_PMIC_IRQ_SW2_LS:
+ case PF1550_PMIC_IRQ_SW3_LS:
+ event = REGULATOR_EVENT_OVER_CURRENT_WARN;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "SW3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_SW1_HS:
+ case PF1550_PMIC_IRQ_SW2_HS:
+ case PF1550_PMIC_IRQ_SW3_HS:
+ event = REGULATOR_EVENT_OVER_CURRENT;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "SW3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_LDO1_FAULT:
+ case PF1550_PMIC_IRQ_LDO2_FAULT:
+ case PF1550_PMIC_IRQ_LDO3_FAULT:
+ event = REGULATOR_EVENT_OVER_CURRENT;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "LDO3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_TEMP_110:
+ case PF1550_PMIC_IRQ_TEMP_125:
+ event = REGULATOR_EVENT_OVER_TEMP;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ default:
+ dev_err(dev, "regulator interrupt: irq %d occurred\n",
+ irq_type);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pf1550_regulator_probe(struct platform_device *pdev)
+{
+ const struct pf1550_ddata *pf1550 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct pf1550_regulator_info *info;
+ int i, irq = -1, ret = 0;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ config.regmap = dev_get_regmap(pf1550->dev, NULL);
+ if (!config.regmap)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to get parent regmap\n");
+
+ config.dev = pf1550->dev;
+ config.regmap = pf1550->regmap;
+ info->dev = &pdev->dev;
+ info->pf1550 = pf1550;
+
+ memcpy(info->regulator_descs, pf1550_regulators,
+ sizeof(info->regulator_descs));
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_regulators); i++) {
+ struct regulator_desc *desc;
+
+ desc = &info->regulator_descs[i].desc;
+
+ if ((desc->id == PF1550_SW2 && !pf1550->dvs2_enable) ||
+ (desc->id == PF1550_SW1 && !pf1550->dvs1_enable)) {
+ /* OTP_SW2_DVS_ENB == 1? or OTP_SW1_DVS_ENB == 1? */
+ desc->volt_table = pf1550_sw12_volts;
+ desc->n_voltages = ARRAY_SIZE(pf1550_sw12_volts);
+ desc->ops = &pf1550_sw1_ops;
+ }
+
+ info->rdevs[i] = devm_regulator_register(&pdev->dev, desc,
+ &config);
+ if (IS_ERR(info->rdevs[i]))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(info->rdevs[i]),
+ "failed to initialize regulator-%d\n",
+ i);
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ pf1550_regulator_irq_handler,
+ IRQF_NO_SUSPEND,
+ "pf1550-regulator", info);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed: irq request (IRQ: %d)\n",
+ i);
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id pf1550_regulator_id[] = {
+ { "pf1550-regulator", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_regulator_id);
+
+static struct platform_driver pf1550_regulator_driver = {
+ .driver = {
+ .name = "pf1550-regulator",
+ },
+ .probe = pf1550_regulator_probe,
+ .id_table = pf1550_regulator_id,
+};
+module_platform_driver(pf1550_regulator_driver);
+
+MODULE_DESCRIPTION("NXP PF1550 regulator driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pf530x-regulator.c b/drivers/regulator/pf530x-regulator.c
new file mode 100644
index 000000000000..f789c4b6a499
--- /dev/null
+++ b/drivers/regulator/pf530x-regulator.c
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+// documentation of this device is available at
+// https://www.nxp.com/docs/en/data-sheet/PF5300.pdf
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+/* registers */
+#define PF530X_DEVICEID 0x00
+#define PF530X_REV 0x01
+#define PF530X_EMREV 0x02
+#define PF530X_PROGID 0x03
+#define PF530X_CONFIG1 0x04
+#define PF530X_INT_STATUS1 0x05
+#define PF530X_INT_SENSE1 0x06
+#define PF530X_INT_STATUS2 0x07
+#define PF530X_INT_SENSE2 0x08
+#define PF530X_BIST_STAT1 0x09
+#define PF530X_BIST_CTRL 0x0a
+#define PF530X_STATE 0x0b
+#define PF530X_STATE_CTRL 0x0c
+#define PF530X_SW1_VOLT 0x0d
+#define PF530X_SW1_STBY_VOLT 0x0e
+#define PF530X_SW1_CTRL1 0x0f
+#define PF530X_SW1_CTRL2 0x10
+#define PF530X_CLK_CTRL 0x11
+#define PF530X_SEQ_CTRL1 0x12
+#define PF530X_SEQ_CTRL2 0x13
+#define PF530X_RANDOM_CHK 0x14
+#define PF530X_RANDOM_GEN 0x15
+#define PF530X_WD_CTRL1 0x16
+#define PF530X_WD_SEED 0x17
+#define PF530X_WD_ANSWER 0x18
+#define PF530X_FLT_CNT1 0x19
+#define PF530X_FLT_CNT2 0x1a
+#define PF530X_OTP_MODE 0x2f
+
+enum pf530x_states {
+ PF530X_STATE_POF,
+ PF530X_STATE_FUSE_LOAD,
+ PF530X_STATE_LP_OFF,
+ PF530X_STATE_SELF_TEST,
+ PF530X_STATE_POWER_UP,
+ PF530X_STATE_INIT,
+ PF530X_STATE_IO_RELEASE,
+ PF530X_STATE_RUN,
+ PF530X_STATE_STANDBY,
+ PF530X_STATE_FAULT,
+ PF530X_STATE_FAILSAFE,
+ PF530X_STATE_POWER_DOWN,
+ PF530X_STATE_2MS_SELFTEST_RETRY,
+ PF530X_STATE_OFF_DLY,
+};
+
+#define PF530_FAM 0x50
+enum pf530x_devid {
+ PF5300 = 0x3,
+ PF5301 = 0x4,
+ PF5302 = 0x5,
+};
+
+#define PF530x_FAM 0x50
+#define PF530x_DEVICE_FAM_MASK GENMASK(7, 4)
+#define PF530x_DEVICE_ID_MASK GENMASK(3, 0)
+
+#define PF530x_STATE_MASK GENMASK(3, 0)
+#define PF530x_STATE_RUN 0x07
+#define PF530x_STATE_STANDBY 0x08
+#define PF530x_STATE_LP_OFF 0x02
+
+#define PF530X_OTP_STBY_MODE GENMASK(3, 2)
+#define PF530X_OTP_RUN_MODE GENMASK(1, 0)
+
+#define PF530X_INT_STATUS_OV BIT(1)
+#define PF530X_INT_STATUS_UV BIT(2)
+#define PF530X_INT_STATUS_ILIM BIT(3)
+
+#define SW1_ILIM_S BIT(0)
+#define VMON_UV_S BIT(1)
+#define VMON_OV_S BIT(2)
+#define VIN_OVLO_S BIT(3)
+#define BG_ERR_S BIT(6)
+
+#define THERM_155_S BIT(3)
+#define THERM_140_S BIT(2)
+#define THERM_125_S BIT(1)
+#define THERM_110_S BIT(0)
+
+struct pf530x_chip {
+ struct regmap *regmap;
+ struct device *dev;
+};
+
+static const struct regmap_config pf530x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PF530X_OTP_MODE,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int pf530x_get_status(struct regulator_dev *rdev)
+{
+ unsigned int state;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, PF530X_INT_SENSE1, &state);
+ if (ret != 0)
+ return ret;
+
+ if ((state & (BG_ERR_S | SW1_ILIM_S | VMON_UV_S | VMON_OV_S | VIN_OVLO_S))
+ != 0)
+ return REGULATOR_STATUS_ERROR;
+
+ // no errors, check if what non-error state we're in
+ ret = regmap_read(rdev->regmap, PF530X_STATE, &state);
+ if (ret != 0)
+ return ret;
+
+ state &= PF530x_STATE_MASK;
+
+ switch (state) {
+ case PF530x_STATE_RUN:
+ ret = REGULATOR_STATUS_NORMAL;
+ break;
+ case PF530x_STATE_STANDBY:
+ ret = REGULATOR_STATUS_STANDBY;
+ break;
+ case PF530x_STATE_LP_OFF:
+ ret = REGULATOR_STATUS_OFF;
+ break;
+ default:
+ ret = REGULATOR_STATUS_ERROR;
+ break;
+ }
+ return ret;
+}
+
+static int pf530x_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
+{
+ unsigned int status;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, PF530X_INT_STATUS1, &status);
+
+ if (ret != 0)
+ return ret;
+
+ *flags = 0;
+
+ if (status & PF530X_INT_STATUS_OV)
+ *flags |= REGULATOR_ERROR_OVER_VOLTAGE_WARN;
+
+ if (status & PF530X_INT_STATUS_UV)
+ *flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
+
+ if (status & PF530X_INT_STATUS_ILIM)
+ *flags |= REGULATOR_ERROR_OVER_CURRENT;
+
+ ret = regmap_read(rdev->regmap, PF530X_INT_SENSE2, &status);
+
+ if (ret != 0)
+ return ret;
+
+ if ((status & (THERM_155_S |
+ THERM_140_S |
+ THERM_125_S |
+ THERM_110_S)) != 0)
+ *flags |= REGULATOR_ERROR_OVER_TEMP_WARN;
+
+ return 0;
+}
+
+static const struct regulator_ops pf530x_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .get_status = pf530x_get_status,
+ .get_error_flags = pf530x_get_error_flags,
+ .set_bypass = regulator_set_bypass_regmap,
+ .get_bypass = regulator_get_bypass_regmap,
+};
+
+static const struct linear_range vrange = REGULATOR_LINEAR_RANGE(500000, 0, 140, 5000);
+
+static const struct regulator_desc pf530x_reg_desc = {
+ .name = "SW1",
+ .ops = &pf530x_regulator_ops,
+ .linear_ranges = &vrange,
+ .n_linear_ranges = 1,
+ .type = REGULATOR_VOLTAGE,
+ .id = 0,
+ .owner = THIS_MODULE,
+ .vsel_reg = PF530X_SW1_VOLT,
+ .vsel_mask = 0xFF,
+ .bypass_reg = PF530X_SW1_CTRL2,
+ .bypass_mask = 0x07,
+ .bypass_val_on = 0x07,
+ .bypass_val_off = 0x00,
+ .enable_reg = PF530X_SW1_CTRL1,
+ .enable_mask = GENMASK(5, 2),
+ .enable_val = GENMASK(5, 2),
+ .disable_val = 0,
+};
+
+static int pf530x_identify(struct pf530x_chip *chip)
+{
+ unsigned int value;
+ u8 dev_fam, dev_id, full_layer_rev, metal_layer_rev, prog_idh, prog_idl, emrev;
+ const char *name = NULL;
+ int ret;
+
+ ret = regmap_read(chip->regmap, PF530X_DEVICEID, &value);
+ if (ret) {
+ dev_err(chip->dev, "failed to read chip family\n");
+ return ret;
+ }
+
+ dev_fam = value & PF530x_DEVICE_FAM_MASK;
+ switch (dev_fam) {
+ case PF530x_FAM:
+ break;
+ default:
+ dev_err(chip->dev,
+ "Chip 0x%x is not from PF530X family\n", dev_fam);
+ return ret;
+ }
+
+ dev_id = value & PF530x_DEVICE_ID_MASK;
+ switch (dev_id) {
+ case PF5300:
+ name = "PF5300";
+ break;
+ case PF5301:
+ name = "PF5301";
+ break;
+ case PF5302:
+ name = "PF5302";
+ break;
+ default:
+ dev_err(chip->dev, "Unknown pf530x device id 0x%x\n", dev_id);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(chip->regmap, PF530X_REV, &value);
+ if (ret) {
+ dev_err(chip->dev, "failed to read chip rev\n");
+ return ret;
+ }
+
+ full_layer_rev = ((value & 0xF0) == 0) ? '0' : ((((value & 0xF0) >> 4) - 1) + 'A');
+ metal_layer_rev = value & 0xF;
+
+ ret = regmap_read(chip->regmap, PF530X_EMREV, &value);
+ if (ret) {
+ dev_err(chip->dev, "failed to read chip emrev register\n");
+ return ret;
+ }
+
+ prog_idh = (value >> 4) + 'A';
+ // prog_idh skips 'O', per page 96 of the datasheet
+ if (prog_idh >= 'O')
+ prog_idh += 1;
+
+ emrev = value & 0x7;
+
+ ret = regmap_read(chip->regmap, PF530X_PROGID, &value);
+ if (ret) {
+ dev_err(chip->dev, "failed to read chip progid register\n");
+ return ret;
+ }
+
+ if (value >= 0x22) {
+ dev_err(chip->dev, "invalid value for progid register\n");
+ return -ENODEV;
+ } else if (value < 10) {
+ prog_idl = value + '0';
+ } else {
+ prog_idl = (value - 10) + 'A';
+ // prog_idh skips 'O', per page 97 of the datasheet
+ if (prog_idl >= 'O')
+ prog_idl += 1;
+ }
+
+ dev_info(chip->dev, "%s Regulator found (Rev %c%d ProgID %c%c EMREV %x).\n",
+ name, full_layer_rev, metal_layer_rev, prog_idh, prog_idl, emrev);
+
+ return 0;
+}
+
+static int pf530x_i2c_probe(struct i2c_client *client)
+{
+ struct regulator_config config = { NULL, };
+ struct pf530x_chip *chip;
+ int ret;
+ struct regulator_dev *rdev;
+ struct regulator_init_data *init_data;
+
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, chip);
+ chip->dev = &client->dev;
+
+ chip->regmap = devm_regmap_init_i2c(client, &pf530x_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ ret = PTR_ERR(chip->regmap);
+ dev_err(&client->dev,
+ "regmap allocation failed with err %d\n", ret);
+ return ret;
+ }
+
+ ret = pf530x_identify(chip);
+ if (ret)
+ return ret;
+
+ init_data = of_get_regulator_init_data(chip->dev, chip->dev->of_node, &pf530x_reg_desc);
+ if (!init_data)
+ return -ENODATA;
+
+ config.dev = chip->dev;
+ config.of_node = chip->dev->of_node;
+ config.regmap = chip->regmap;
+ config.init_data = init_data;
+
+ // the config parameter gets copied, it's ok to pass a pointer on the stack here
+ rdev = devm_regulator_register(&client->dev, &pf530x_reg_desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&client->dev, "failed to register %s regulator\n", pf530x_reg_desc.name);
+ return PTR_ERR(rdev);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id pf530x_dt_ids[] = {
+ { .compatible = "nxp,pf5300",},
+ { }
+};
+MODULE_DEVICE_TABLE(of, pf530x_dt_ids);
+
+static const struct i2c_device_id pf530x_i2c_id[] = {
+ { "pf5300", 0 },
+ { "pf5301", 0 },
+ { "pf5302", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, pf530x_i2c_id);
+
+static struct i2c_driver pf530x_regulator_driver = {
+ .id_table = pf530x_i2c_id,
+ .driver = {
+ .name = "pf530x",
+ .of_match_table = pf530x_dt_ids,
+ },
+ .probe = pf530x_i2c_probe,
+};
+module_i2c_driver(pf530x_regulator_driver);
+
+MODULE_AUTHOR("Woodrow Douglass <wdouglass@carnegierobotics.com>");
+MODULE_DESCRIPTION("Regulator Driver for NXP's PF5300/PF5301/PF5302 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pf9453-regulator.c b/drivers/regulator/pf9453-regulator.c
new file mode 100644
index 000000000000..779a6fdb0574
--- /dev/null
+++ b/drivers/regulator/pf9453-regulator.c
@@ -0,0 +1,870 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2024 NXP.
+ * NXP PF9453 pmic driver
+ */
+
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.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>
+
+struct pf9453_dvs_config {
+ unsigned int run_reg; /* dvs0 */
+ unsigned int run_mask;
+ unsigned int standby_reg; /* dvs1 */
+ unsigned int standby_mask;
+};
+
+struct pf9453_regulator_desc {
+ struct regulator_desc desc;
+ const struct pf9453_dvs_config dvs;
+};
+
+struct pf9453 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct gpio_desc *sd_vsel_gpio;
+ int irq;
+};
+
+enum {
+ PF9453_BUCK1 = 0,
+ PF9453_BUCK2,
+ PF9453_BUCK3,
+ PF9453_BUCK4,
+ PF9453_LDO1,
+ PF9453_LDO2,
+ PF9453_LDOSNVS,
+ PF9453_REGULATOR_CNT
+};
+
+enum {
+ PF9453_DVS_LEVEL_RUN = 0,
+ PF9453_DVS_LEVEL_STANDBY,
+ PF9453_DVS_LEVEL_DPSTANDBY,
+ PF9453_DVS_LEVEL_MAX
+};
+
+#define PF9453_BUCK1_VOLTAGE_NUM 0x80
+#define PF9453_BUCK2_VOLTAGE_NUM 0x80
+#define PF9453_BUCK3_VOLTAGE_NUM 0x80
+#define PF9453_BUCK4_VOLTAGE_NUM 0x80
+
+#define PF9453_LDO1_VOLTAGE_NUM 0x65
+#define PF9453_LDO2_VOLTAGE_NUM 0x3b
+#define PF9453_LDOSNVS_VOLTAGE_NUM 0x59
+
+enum {
+ PF9453_REG_DEV_ID = 0x01,
+ PF9453_REG_INT1 = 0x02,
+ PF9453_REG_INT1_MASK = 0x03,
+ PF9453_REG_INT1_STATUS = 0x04,
+ PF9453_REG_VRFLT1_INT = 0x05,
+ PF9453_REG_VRFLT1_MASK = 0x06,
+ PF9453_REG_PWRON_STAT = 0x07,
+ PF9453_REG_RESET_CTRL = 0x08,
+ PF9453_REG_SW_RST = 0x09,
+ PF9453_REG_PWR_CTRL = 0x0a,
+ PF9453_REG_CONFIG1 = 0x0b,
+ PF9453_REG_CONFIG2 = 0x0c,
+ PF9453_REG_32K_CONFIG = 0x0d,
+ PF9453_REG_BUCK1CTRL = 0x10,
+ PF9453_REG_BUCK1OUT = 0x11,
+ PF9453_REG_BUCK2CTRL = 0x14,
+ PF9453_REG_BUCK2OUT = 0x15,
+ PF9453_REG_BUCK2OUT_STBY = 0x1d,
+ PF9453_REG_BUCK2OUT_MAX_LIMIT = 0x1f,
+ PF9453_REG_BUCK2OUT_MIN_LIMIT = 0x20,
+ PF9453_REG_BUCK3CTRL = 0x21,
+ PF9453_REG_BUCK3OUT = 0x22,
+ PF9453_REG_BUCK4CTRL = 0x2e,
+ PF9453_REG_BUCK4OUT = 0x2f,
+ PF9453_REG_LDO1OUT_L = 0x36,
+ PF9453_REG_LDO1CFG = 0x37,
+ PF9453_REG_LDO1OUT_H = 0x38,
+ PF9453_REG_LDOSNVS_CFG1 = 0x39,
+ PF9453_REG_LDOSNVS_CFG2 = 0x3a,
+ PF9453_REG_LDO2CFG = 0x3b,
+ PF9453_REG_LDO2OUT = 0x3c,
+ PF9453_REG_BUCK_POK = 0x3d,
+ PF9453_REG_LSW_CTRL1 = 0x40,
+ PF9453_REG_LSW_CTRL2 = 0x41,
+ PF9453_REG_LOCK = 0x4e,
+ PF9453_MAX_REG
+};
+
+#define PF9453_UNLOCK_KEY 0x5c
+#define PF9453_LOCK_KEY 0x0
+
+/* PF9453 BUCK ENMODE bits */
+#define BUCK_ENMODE_OFF 0x00
+#define BUCK_ENMODE_ONREQ 0x01
+#define BUCK_ENMODE_ONREQ_STBY 0x02
+#define BUCK_ENMODE_ONREQ_STBY_DPSTBY 0x03
+
+/* PF9453 BUCK ENMODE bits */
+#define LDO_ENMODE_OFF 0x00
+#define LDO_ENMODE_ONREQ 0x01
+#define LDO_ENMODE_ONREQ_STBY 0x02
+#define LDO_ENMODE_ONREQ_STBY_DPSTBY 0x03
+
+/* PF9453_REG_BUCK1_CTRL bits */
+#define BUCK1_AD 0x08
+#define BUCK1_FPWM 0x04
+#define BUCK1_ENMODE_MASK GENMASK(1, 0)
+
+/* PF9453_REG_BUCK2_CTRL bits */
+#define BUCK2_RAMP_MASK GENMASK(7, 6)
+#define BUCK2_RAMP_25MV 0x0
+#define BUCK2_RAMP_12P5MV 0x1
+#define BUCK2_RAMP_6P25MV 0x2
+#define BUCK2_RAMP_3P125MV 0x3
+#define BUCK2_AD 0x08
+#define BUCK2_FPWM 0x04
+#define BUCK2_ENMODE_MASK GENMASK(1, 0)
+
+/* PF9453_REG_BUCK3_CTRL bits */
+#define BUCK3_AD 0x08
+#define BUCK3_FPWM 0x04
+#define BUCK3_ENMODE_MASK GENMASK(1, 0)
+
+/* PF9453_REG_BUCK4_CTRL bits */
+#define BUCK4_AD 0x08
+#define BUCK4_FPWM 0x04
+#define BUCK4_ENMODE_MASK GENMASK(1, 0)
+
+/* PF9453_REG_BUCK123_PRESET_EN bit */
+#define BUCK123_PRESET_EN 0x80
+
+/* PF9453_BUCK1OUT bits */
+#define BUCK1OUT_MASK GENMASK(6, 0)
+
+/* PF9453_BUCK2OUT bits */
+#define BUCK2OUT_MASK GENMASK(6, 0)
+#define BUCK2OUT_STBY_MASK GENMASK(6, 0)
+
+/* PF9453_REG_BUCK3OUT bits */
+#define BUCK3OUT_MASK GENMASK(6, 0)
+
+/* PF9453_REG_BUCK4OUT bits */
+#define BUCK4OUT_MASK GENMASK(6, 0)
+
+/* PF9453_REG_LDO1_VOLT bits */
+#define LDO1_EN_MASK GENMASK(1, 0)
+#define LDO1OUT_MASK GENMASK(6, 0)
+
+/* PF9453_REG_LDO2_VOLT bits */
+#define LDO2_EN_MASK GENMASK(1, 0)
+#define LDO2OUT_MASK GENMASK(6, 0)
+
+/* PF9453_REG_LDOSNVS_VOLT bits */
+#define LDOSNVS_EN_MASK GENMASK(0, 0)
+#define LDOSNVSCFG1_MASK GENMASK(6, 0)
+
+/* PF9453_REG_IRQ bits */
+#define IRQ_RSVD 0x80
+#define IRQ_RSTB 0x40
+#define IRQ_ONKEY 0x20
+#define IRQ_RESETKEY 0x10
+#define IRQ_VR_FLT1 0x08
+#define IRQ_LOWVSYS 0x04
+#define IRQ_THERM_100 0x02
+#define IRQ_THERM_80 0x01
+
+/* PF9453_REG_RESET_CTRL bits */
+#define WDOG_B_CFG_MASK GENMASK(7, 6)
+#define WDOG_B_CFG_NONE 0x00
+#define WDOG_B_CFG_WARM 0x40
+#define WDOG_B_CFG_COLD 0x80
+
+static const struct regmap_range pf9453_status_range = {
+ .range_min = PF9453_REG_INT1,
+ .range_max = PF9453_REG_PWRON_STAT,
+};
+
+static const struct regmap_access_table pf9453_volatile_regs = {
+ .yes_ranges = &pf9453_status_range,
+ .n_yes_ranges = 1,
+};
+
+static const struct regmap_config pf9453_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &pf9453_volatile_regs,
+ .max_register = PF9453_MAX_REG - 1,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+/*
+ * BUCK2
+ * BUCK2RAM[1:0] BUCK2 DVS ramp rate setting
+ * 00: 25mV/1usec
+ * 01: 25mV/2usec
+ * 10: 25mV/4usec
+ * 11: 25mV/8usec
+ */
+static const unsigned int pf9453_dvs_buck_ramp_table[] = {
+ 25000, 12500, 6250, 3125
+};
+
+static bool is_reg_protect(uint reg)
+{
+ switch (reg) {
+ case PF9453_REG_BUCK1OUT:
+ case PF9453_REG_BUCK2OUT:
+ case PF9453_REG_BUCK3OUT:
+ case PF9453_REG_BUCK4OUT:
+ case PF9453_REG_LDO1OUT_L:
+ case PF9453_REG_LDO1OUT_H:
+ case PF9453_REG_LDO2OUT:
+ case PF9453_REG_LDOSNVS_CFG1:
+ case PF9453_REG_BUCK2OUT_MAX_LIMIT:
+ case PF9453_REG_BUCK2OUT_MIN_LIMIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int pf9453_pmic_write(struct pf9453 *pf9453, unsigned int reg, u8 mask, unsigned int val)
+{
+ int ret = -EINVAL;
+ u8 data, key;
+ u32 rxBuf;
+
+ /* If not updating entire register, perform a read-mod-write */
+ data = val;
+ key = PF9453_UNLOCK_KEY;
+
+ if (mask != 0xffU) {
+ /* Read data */
+ ret = regmap_read(pf9453->regmap, reg, &rxBuf);
+ if (ret) {
+ dev_err(pf9453->dev, "Read reg=%0x error!\n", reg);
+ return ret;
+ }
+ data = (val & mask) | (rxBuf & (~mask));
+ }
+
+ if (reg < PF9453_MAX_REG) {
+ if (is_reg_protect(reg)) {
+ ret = regmap_raw_write(pf9453->regmap, PF9453_REG_LOCK, &key, 1U);
+ if (ret) {
+ dev_err(pf9453->dev, "Write reg=%0x error!\n", reg);
+ return ret;
+ }
+
+ ret = regmap_raw_write(pf9453->regmap, reg, &data, 1U);
+ if (ret) {
+ dev_err(pf9453->dev, "Write reg=%0x error!\n", reg);
+ return ret;
+ }
+
+ key = PF9453_LOCK_KEY;
+ ret = regmap_raw_write(pf9453->regmap, PF9453_REG_LOCK, &key, 1U);
+ if (ret) {
+ dev_err(pf9453->dev, "Write reg=%0x error!\n", reg);
+ return ret;
+ }
+ } else {
+ ret = regmap_raw_write(pf9453->regmap, reg, &data, 1U);
+ if (ret) {
+ dev_err(pf9453->dev, "Write reg=%0x error!\n", reg);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * pf9453_regulator_enable_regmap - enable regulator for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their enable() operation, saving some code.
+ *
+ * Return: %0 on success, or negative errno.
+ */
+static int pf9453_regulator_enable_regmap(struct regulator_dev *rdev)
+{
+ struct pf9453 *pf9453 = dev_get_drvdata(rdev->dev.parent);
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->disable_val;
+ } else {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ }
+
+ return pf9453_pmic_write(pf9453, rdev->desc->enable_reg, rdev->desc->enable_mask, val);
+}
+
+/**
+ * pf9453_regulator_disable_regmap - disable regulator for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their disable() operation, saving some code.
+ *
+ * Return: %0 on success, or negative errno.
+ */
+static int pf9453_regulator_disable_regmap(struct regulator_dev *rdev)
+{
+ struct pf9453 *pf9453 = dev_get_drvdata(rdev->dev.parent);
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ } else {
+ val = rdev->desc->disable_val;
+ }
+
+ return pf9453_pmic_write(pf9453, rdev->desc->enable_reg, rdev->desc->enable_mask, val);
+}
+
+/**
+ * pf9453_regulator_set_voltage_sel_regmap - set voltage for regmap users
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their set_voltage_vsel operation, saving some code.
+ *
+ * Return: %0 on success, or negative errno.
+ */
+static int pf9453_regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned int sel)
+{
+ struct pf9453 *pf9453 = dev_get_drvdata(rdev->dev.parent);
+ int ret;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+ ret = pf9453_pmic_write(pf9453, rdev->desc->vsel_reg, rdev->desc->vsel_mask, sel);
+ if (ret)
+ return ret;
+
+ if (rdev->desc->apply_bit)
+ ret = pf9453_pmic_write(pf9453, rdev->desc->apply_reg,
+ rdev->desc->apply_bit, rdev->desc->apply_bit);
+ return ret;
+}
+
+static int find_closest_bigger(unsigned int target, const unsigned int *table,
+ unsigned int num_sel, unsigned int *sel)
+{
+ unsigned int s, tmp, max, maxsel = 0;
+ bool found = false;
+
+ max = table[0];
+
+ for (s = 0; s < num_sel; s++) {
+ if (table[s] > max) {
+ max = table[s];
+ maxsel = s;
+ }
+ if (table[s] >= target) {
+ if (!found || table[s] - target < tmp - target) {
+ tmp = table[s];
+ *sel = s;
+ found = true;
+ if (tmp == target)
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ *sel = maxsel;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * pf9453_regulator_set_ramp_delay_regmap - set ramp delay for regmap users
+ *
+ * @rdev: regulator to operate on
+ * @ramp_delay: desired ramp delay value in microseconds
+ *
+ * Regulators that use regmap for their register I/O can set the ramp_reg
+ * and ramp_mask fields in their descriptor and then use this as their
+ * set_ramp_delay operation, saving some code.
+ *
+ * Return: %0 on success, or negative errno.
+ */
+static int pf9453_regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay)
+{
+ struct pf9453 *pf9453 = dev_get_drvdata(rdev->dev.parent);
+ unsigned int sel;
+ int ret;
+
+ if (WARN_ON(!rdev->desc->n_ramp_values || !rdev->desc->ramp_delay_table))
+ return -EINVAL;
+
+ ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table,
+ rdev->desc->n_ramp_values, &sel);
+
+ if (ret) {
+ dev_warn(rdev_get_dev(rdev),
+ "Can't set ramp-delay %u, setting %u\n", ramp_delay,
+ rdev->desc->ramp_delay_table[sel]);
+ }
+
+ sel <<= ffs(rdev->desc->ramp_mask) - 1;
+
+ return pf9453_pmic_write(pf9453, rdev->desc->ramp_reg,
+ rdev->desc->ramp_mask, sel);
+}
+
+static const struct regulator_ops pf9453_dvs_buck_regulator_ops = {
+ .enable = pf9453_regulator_enable_regmap,
+ .disable = pf9453_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = pf9453_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 = pf9453_regulator_set_ramp_delay_regmap,
+};
+
+static const struct regulator_ops pf9453_buck_regulator_ops = {
+ .enable = pf9453_regulator_enable_regmap,
+ .disable = pf9453_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = pf9453_regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static const struct regulator_ops pf9453_ldo_regulator_ops = {
+ .enable = pf9453_regulator_enable_regmap,
+ .disable = pf9453_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = pf9453_regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+/*
+ * BUCK1/3/4
+ * 0.60 to 3.775V (25mV step)
+ */
+static const struct linear_range pf9453_buck134_volts[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x00, 0x7F, 25000),
+};
+
+/*
+ * BUCK2
+ * 0.60 to 2.1875V (12.5mV step)
+ */
+static const struct linear_range pf9453_buck2_volts[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x00, 0x7F, 12500),
+};
+
+/*
+ * LDO1
+ * 0.8 to 3.3V (25mV step)
+ */
+static const struct linear_range pf9453_ldo1_volts[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x64, 25000),
+};
+
+/*
+ * LDO2
+ * 0.5 to 1.95V (25mV step)
+ */
+static const struct linear_range pf9453_ldo2_volts[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x00, 0x3A, 25000),
+};
+
+/*
+ * LDOSNVS
+ * 1.2 to 3.4V (25mV step)
+ */
+static const struct linear_range pf9453_ldosnvs_volts[] = {
+ REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x58, 25000),
+};
+
+static int buck_set_dvs(const struct regulator_desc *desc,
+ struct device_node *np, struct pf9453 *pf9453,
+ char *prop, unsigned int reg, unsigned int mask)
+{
+ int ret, i;
+ u32 uv;
+
+ ret = of_property_read_u32(np, prop, &uv);
+ if (ret == -EINVAL)
+ return 0;
+ else if (ret)
+ return ret;
+
+ for (i = 0; i < desc->n_voltages; i++) {
+ ret = regulator_desc_list_voltage_linear_range(desc, i);
+ if (ret < 0)
+ continue;
+ if (ret == uv) {
+ i <<= ffs(desc->vsel_mask) - 1;
+ ret = pf9453_pmic_write(pf9453, reg, mask, i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int pf9453_set_dvs_levels(struct device_node *np, const struct regulator_desc *desc,
+ struct regulator_config *cfg)
+{
+ const struct pf9453_regulator_desc *data = container_of_const(desc,
+ struct pf9453_regulator_desc,
+ desc);
+ struct pf9453 *pf9453 = dev_get_drvdata(cfg->dev);
+ const struct pf9453_dvs_config *dvs = &data->dvs;
+ unsigned int reg, mask;
+ int i, ret = 0;
+ char *prop;
+
+ for (i = 0; i < PF9453_DVS_LEVEL_MAX; i++) {
+ switch (i) {
+ case PF9453_DVS_LEVEL_RUN:
+ prop = "nxp,dvs-run-voltage";
+ reg = dvs->run_reg;
+ mask = dvs->run_mask;
+ break;
+ case PF9453_DVS_LEVEL_DPSTANDBY:
+ case PF9453_DVS_LEVEL_STANDBY:
+ prop = "nxp,dvs-standby-voltage";
+ reg = dvs->standby_reg;
+ mask = dvs->standby_mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = buck_set_dvs(desc, np, pf9453, prop, reg, mask);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static const struct pf9453_regulator_desc pf9453_regulators[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_BUCK1,
+ .ops = &pf9453_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_BUCK1_VOLTAGE_NUM,
+ .linear_ranges = pf9453_buck134_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_buck134_volts),
+ .vsel_reg = PF9453_REG_BUCK1OUT,
+ .vsel_mask = BUCK1OUT_MASK,
+ .enable_reg = PF9453_REG_BUCK1CTRL,
+ .enable_mask = BUCK1_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_BUCK2,
+ .ops = &pf9453_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_BUCK2_VOLTAGE_NUM,
+ .linear_ranges = pf9453_buck2_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_buck2_volts),
+ .vsel_reg = PF9453_REG_BUCK2OUT,
+ .vsel_mask = BUCK2OUT_MASK,
+ .enable_reg = PF9453_REG_BUCK2CTRL,
+ .enable_mask = BUCK2_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
+ .ramp_reg = PF9453_REG_BUCK2CTRL,
+ .ramp_mask = BUCK2_RAMP_MASK,
+ .ramp_delay_table = pf9453_dvs_buck_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf9453_dvs_buck_ramp_table),
+ .owner = THIS_MODULE,
+ .of_parse_cb = pf9453_set_dvs_levels,
+ },
+ .dvs = {
+ .run_reg = PF9453_REG_BUCK2OUT,
+ .run_mask = BUCK2OUT_MASK,
+ .standby_reg = PF9453_REG_BUCK2OUT_STBY,
+ .standby_mask = BUCK2OUT_STBY_MASK,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("BUCK3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_BUCK3,
+ .ops = &pf9453_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_BUCK3_VOLTAGE_NUM,
+ .linear_ranges = pf9453_buck134_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_buck134_volts),
+ .vsel_reg = PF9453_REG_BUCK3OUT,
+ .vsel_mask = BUCK3OUT_MASK,
+ .enable_reg = PF9453_REG_BUCK3CTRL,
+ .enable_mask = BUCK3_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_BUCK4,
+ .ops = &pf9453_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_BUCK4_VOLTAGE_NUM,
+ .linear_ranges = pf9453_buck134_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_buck134_volts),
+ .vsel_reg = PF9453_REG_BUCK4OUT,
+ .vsel_mask = BUCK4OUT_MASK,
+ .enable_reg = PF9453_REG_BUCK4CTRL,
+ .enable_mask = BUCK4_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_LDO1,
+ .ops = &pf9453_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_LDO1_VOLTAGE_NUM,
+ .linear_ranges = pf9453_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_ldo1_volts),
+ .vsel_reg = PF9453_REG_LDO1OUT_H,
+ .vsel_mask = LDO1OUT_MASK,
+ .enable_reg = PF9453_REG_LDO1CFG,
+ .enable_mask = LDO1_EN_MASK,
+ .enable_val = LDO_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_LDO2,
+ .ops = &pf9453_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_LDO2_VOLTAGE_NUM,
+ .linear_ranges = pf9453_ldo2_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_ldo2_volts),
+ .vsel_reg = PF9453_REG_LDO2OUT,
+ .vsel_mask = LDO2OUT_MASK,
+ .enable_reg = PF9453_REG_LDO2CFG,
+ .enable_mask = LDO2_EN_MASK,
+ .enable_val = LDO_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldosnvs",
+ .of_match = of_match_ptr("LDO-SNVS"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_LDOSNVS,
+ .ops = &pf9453_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_LDOSNVS_VOLTAGE_NUM,
+ .linear_ranges = pf9453_ldosnvs_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_ldosnvs_volts),
+ .vsel_reg = PF9453_REG_LDOSNVS_CFG1,
+ .vsel_mask = LDOSNVSCFG1_MASK,
+ .enable_reg = PF9453_REG_LDOSNVS_CFG2,
+ .enable_mask = LDOSNVS_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ { }
+};
+
+static irqreturn_t pf9453_irq_handler(int irq, void *data)
+{
+ struct pf9453 *pf9453 = data;
+ struct regmap *regmap = pf9453->regmap;
+ unsigned int status;
+ int ret;
+
+ ret = regmap_read(regmap, PF9453_REG_INT1, &status);
+ if (ret < 0) {
+ dev_err(pf9453->dev, "Failed to read INT1(%d)\n", ret);
+ return IRQ_NONE;
+ }
+
+ if (status & IRQ_RSTB)
+ dev_warn(pf9453->dev, "IRQ_RSTB interrupt.\n");
+
+ if (status & IRQ_ONKEY)
+ dev_warn(pf9453->dev, "IRQ_ONKEY interrupt.\n");
+
+ if (status & IRQ_VR_FLT1)
+ dev_warn(pf9453->dev, "VRFLT1 interrupt.\n");
+
+ if (status & IRQ_RESETKEY)
+ dev_warn(pf9453->dev, "IRQ_RESETKEY interrupt.\n");
+
+ if (status & IRQ_LOWVSYS)
+ dev_warn(pf9453->dev, "LOWVSYS interrupt.\n");
+
+ if (status & IRQ_THERM_100)
+ dev_warn(pf9453->dev, "IRQ_THERM_100 interrupt.\n");
+
+ if (status & IRQ_THERM_80)
+ dev_warn(pf9453->dev, "IRQ_THERM_80 interrupt.\n");
+
+ return IRQ_HANDLED;
+}
+
+static int pf9453_i2c_probe(struct i2c_client *i2c)
+{
+ const struct pf9453_regulator_desc *regulator_desc = of_device_get_match_data(&i2c->dev);
+ struct regulator_config config = { };
+ unsigned int reset_ctrl;
+ unsigned int device_id;
+ struct pf9453 *pf9453;
+ int ret;
+
+ if (!i2c->irq)
+ return dev_err_probe(&i2c->dev, -EINVAL, "No IRQ configured?\n");
+
+ pf9453 = devm_kzalloc(&i2c->dev, sizeof(struct pf9453), GFP_KERNEL);
+ if (!pf9453)
+ return -ENOMEM;
+
+ pf9453->regmap = devm_regmap_init_i2c(i2c, &pf9453_regmap_config);
+ if (IS_ERR(pf9453->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(pf9453->regmap),
+ "regmap initialization failed\n");
+
+ pf9453->irq = i2c->irq;
+ pf9453->dev = &i2c->dev;
+
+ dev_set_drvdata(&i2c->dev, pf9453);
+
+ ret = regmap_read(pf9453->regmap, PF9453_REG_DEV_ID, &device_id);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Read device id error\n");
+
+ /* Check your board and dts for match the right pmic */
+ if ((device_id >> 4) != 0xb)
+ return dev_err_probe(&i2c->dev, -EINVAL, "Device id(%x) mismatched\n",
+ device_id >> 4);
+
+ while (regulator_desc->desc.name) {
+ const struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+
+ desc = &regulator_desc->desc;
+
+ config.regmap = pf9453->regmap;
+ config.dev = pf9453->dev;
+
+ rdev = devm_regulator_register(pf9453->dev, desc, &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(pf9453->dev, PTR_ERR(rdev),
+ "Failed to register regulator(%s)\n", desc->name);
+
+ regulator_desc++;
+ }
+
+ ret = devm_request_threaded_irq(pf9453->dev, pf9453->irq, NULL, pf9453_irq_handler,
+ (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
+ "pf9453-irq", pf9453);
+ if (ret)
+ return dev_err_probe(pf9453->dev, ret, "Failed to request IRQ: %d\n", pf9453->irq);
+
+ /* Unmask all interrupt except PWRON/WDOG/RSVD */
+ ret = pf9453_pmic_write(pf9453, PF9453_REG_INT1_MASK,
+ IRQ_ONKEY | IRQ_RESETKEY | IRQ_RSTB | IRQ_VR_FLT1
+ | IRQ_LOWVSYS | IRQ_THERM_100 | IRQ_THERM_80, IRQ_RSVD);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset"))
+ reset_ctrl = WDOG_B_CFG_WARM;
+ else
+ reset_ctrl = WDOG_B_CFG_COLD;
+
+ /* Set reset behavior on assertion of WDOG_B signal */
+ ret = pf9453_pmic_write(pf9453, PF9453_REG_RESET_CTRL, WDOG_B_CFG_MASK, reset_ctrl);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Failed to set WDOG_B reset behavior\n");
+
+ /*
+ * The driver uses the LDO1OUT_H register to control the LDO1 regulator.
+ * This is only valid if the SD_VSEL input of the PMIC is high. Let's
+ * check if the pin is available as GPIO and set it to high.
+ */
+ pf9453->sd_vsel_gpio = gpiod_get_optional(pf9453->dev, "sd-vsel", GPIOD_OUT_HIGH);
+
+ if (IS_ERR(pf9453->sd_vsel_gpio))
+ return dev_err_probe(&i2c->dev, PTR_ERR(pf9453->sd_vsel_gpio),
+ "Failed to get SD_VSEL GPIO\n");
+
+ return 0;
+}
+
+static const struct of_device_id pf9453_of_match[] = {
+ {
+ .compatible = "nxp,pf9453",
+ .data = pf9453_regulators,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pf9453_of_match);
+
+static struct i2c_driver pf9453_i2c_driver = {
+ .driver = {
+ .name = "nxp-pf9453",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = pf9453_of_match,
+ },
+ .probe = pf9453_i2c_probe,
+};
+
+module_i2c_driver(pf9453_i2c_driver);
+
+MODULE_AUTHOR("Joy Zou <joy.zou@nxp.com>");
+MODULE_DESCRIPTION("NXP PF9453 Power Management IC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/qcom-labibb-regulator.c b/drivers/regulator/qcom-labibb-regulator.c
index ba3f9391565f..1b14015caca6 100644
--- a/drivers/regulator/qcom-labibb-regulator.c
+++ b/drivers/regulator/qcom-labibb-regulator.c
@@ -230,7 +230,7 @@ static void qcom_labibb_ocp_recovery_worker(struct work_struct *work)
return;
reschedule:
- mod_delayed_work(system_wq, &vreg->ocp_recovery_work,
+ mod_delayed_work(system_dfl_wq, &vreg->ocp_recovery_work,
msecs_to_jiffies(OCP_RECOVERY_INTERVAL_MS));
}
@@ -510,7 +510,7 @@ reschedule:
* taking action is not truly urgent anymore.
*/
vreg->sc_count++;
- mod_delayed_work(system_wq, &vreg->sc_recovery_work,
+ mod_delayed_work(system_dfl_wq, &vreg->sc_recovery_work,
msecs_to_jiffies(SC_RECOVERY_INTERVAL_MS));
}
diff --git a/drivers/regulator/qcom-pm8008-regulator.c b/drivers/regulator/qcom-pm8008-regulator.c
index da017c1969d0..90c78ee1c37b 100644
--- a/drivers/regulator/qcom-pm8008-regulator.c
+++ b/drivers/regulator/qcom-pm8008-regulator.c
@@ -96,7 +96,7 @@ static int pm8008_regulator_get_voltage_sel(struct regulator_dev *rdev)
uV = le16_to_cpu(val) * 1000;
- return (uV - preg->desc.min_uV) / preg->desc.uV_step;
+ return regulator_map_voltage_linear_range(rdev, uV, INT_MAX);
}
static const struct regulator_ops pm8008_regulator_ops = {
diff --git a/drivers/regulator/qcom-refgen-regulator.c b/drivers/regulator/qcom-refgen-regulator.c
index cfa72ce85bc8..299ac3c8c3bc 100644
--- a/drivers/regulator/qcom-refgen-regulator.c
+++ b/drivers/regulator/qcom-refgen-regulator.c
@@ -94,7 +94,6 @@ static const struct regmap_config qcom_refgen_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .fast_io = true,
};
static int qcom_refgen_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index 6c343b4b9d15..6e4cb2871fca 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
-// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -32,6 +32,34 @@ enum rpmh_regulator_type {
XOB,
};
+/**
+ * enum regulator_hw_type - supported regulator types
+ * @SMPS: Switch mode power supply.
+ * @LDO: Linear Dropout regulator.
+ * @BOB: Buck/Boost type regulator.
+ * @VS: Simple voltage ON/OFF switch.
+ * @NUM_REGULATOR_TYPES: Number of regulator types.
+ */
+enum regulator_hw_type {
+ SMPS,
+ LDO,
+ BOB,
+ VS,
+ NUM_REGULATOR_TYPES,
+};
+
+struct resource_name_formats {
+ const char *rsc_name_fmt;
+ const char *rsc_name_fmt1;
+};
+
+static const struct resource_name_formats vreg_rsc_name_lookup[NUM_REGULATOR_TYPES] = {
+ [SMPS] = {"S%d%s", "smp%s%d"},
+ [LDO] = {"L%d%s", "ldo%s%d"},
+ [BOB] = {"B%d%s", "bob%s%d"},
+ [VS] = {"VS%d%s", "vs%s%d"},
+};
+
#define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0
#define RPMH_REGULATOR_REG_ENABLE 0x4
#define RPMH_REGULATOR_REG_VRM_MODE 0x8
@@ -64,6 +92,12 @@ enum rpmh_regulator_type {
#define PMIC5_BOB_MODE_AUTO 6
#define PMIC5_BOB_MODE_PWM 7
+#define PMIC530_LDO_MODE_RETENTION 3
+#define PMIC530_LDO_MODE_LPM 4
+#define PMIC530_LDO_MODE_OPM 5
+#define PMIC530_LDO_MODE_HPM 7
+
+#define PMIC_ID_LEN 4
/**
* struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
* @regulator_type: RPMh accelerator type used to manage this
@@ -136,17 +170,17 @@ struct rpmh_vreg {
* struct rpmh_vreg_init_data - initialization data for an RPMh regulator
* @name: Name for the regulator which also corresponds
* to the device tree subnode name of the regulator
- * @resource_name: RPMh regulator resource name format string.
- * This must include exactly one field: '%s' which
- * is filled at run-time with the PMIC ID provided
- * by device tree property qcom,pmic-id. Example:
- * "ldo%s1" for RPMh resource "ldoa1".
+ * @index: This is the index number of the regulator present
+ * on the PMIC.
+ * @vreg_hw_type: Regulator HW type enum, this must be BOB, SMPS,
+ * LDO, VS, based on the regulator HW type.
* @supply_name: Parent supply regulator name
* @hw_data: Configuration data for this PMIC regulator type
*/
struct rpmh_vreg_init_data {
const char *name;
- const char *resource_name;
+ enum regulator_hw_type vreg_hw_type;
+ int index;
const char *supply_name;
const struct rpmh_vreg_hw_data *hw_data;
};
@@ -417,6 +451,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
{
struct regulator_config reg_config = {};
char rpmh_resource_name[20] = "";
+ const char *rsc_name;
const struct rpmh_vreg_init_data *rpmh_data;
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
@@ -433,8 +468,16 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
return -EINVAL;
}
- scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name),
- rpmh_data->resource_name, pmic_id);
+ if (strnlen(pmic_id, PMIC_ID_LEN) > 1 && strnstr(pmic_id, "_E", PMIC_ID_LEN)) {
+ rsc_name = vreg_rsc_name_lookup[rpmh_data->vreg_hw_type].rsc_name_fmt;
+ scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name),
+ rsc_name, rpmh_data->index, pmic_id);
+
+ } else {
+ rsc_name = vreg_rsc_name_lookup[rpmh_data->vreg_hw_type].rsc_name_fmt1;
+ scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name),
+ rsc_name, pmic_id, rpmh_data->index);
+ }
vreg->addr = cmd_db_read_addr(rpmh_resource_name);
if (!vreg->addr) {
@@ -519,6 +562,14 @@ static const int pmic_mode_map_pmic5_ldo_hpm[REGULATOR_MODE_STANDBY + 1] = {
[REGULATOR_MODE_FAST] = -EINVAL,
};
+static const int pmic_mode_map_pmic530_ldo[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC530_LDO_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC530_LDO_MODE_LPM,
+ [REGULATOR_MODE_NORMAL] = PMIC530_LDO_MODE_OPM,
+ [REGULATOR_MODE_FAST] = PMIC530_LDO_MODE_HPM,
+};
+
static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
{
unsigned int mode;
@@ -541,6 +592,30 @@ static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
return mode;
}
+static unsigned int rpmh_regulator_pmic530_ldo_of_map_mode(unsigned int rpmh_mode)
+{
+ unsigned int mode;
+
+ switch (rpmh_mode) {
+ case RPMH_REGULATOR_MODE_HPM:
+ mode = REGULATOR_MODE_FAST;
+ break;
+ case RPMH_REGULATOR_MODE_AUTO:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ case RPMH_REGULATOR_MODE_LPM:
+ mode = REGULATOR_MODE_IDLE;
+ break;
+ case RPMH_REGULATOR_MODE_RET:
+ mode = REGULATOR_MODE_STANDBY;
+ break;
+ default:
+ mode = REGULATOR_MODE_INVALID;
+ break;
+ }
+ return mode;
+}
+
static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = {
[REGULATOR_MODE_INVALID] = -EINVAL,
[REGULATOR_MODE_STANDBY] = PMIC4_SMPS_MODE_RETENTION,
@@ -843,26 +918,15 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = {
.of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
};
-static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = {
+static const struct rpmh_vreg_hw_data pmic5_ftsmps525 = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_ops,
.voltage_ranges = (struct linear_range[]) {
REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000),
+ REGULATOR_LINEAR_RANGE(1376000, 268, 438, 8000),
},
- .n_linear_ranges = 1,
- .n_voltages = 268,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 268,
+ .n_linear_ranges = 2,
+ .n_voltages = 439,
.pmic_mode_map = pmic_mode_map_pmic5_smps,
.of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
};
@@ -915,621 +979,816 @@ static const struct rpmh_vreg_hw_data pmic5_bob = {
.of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
};
-#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
+static const struct rpmh_vreg_hw_data pmic5_nldo530 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 211,
+ .hpm_min_load_uA = 30000,
+ .pmic_mode_map = pmic_mode_map_pmic530_ldo,
+ .of_map_mode = rpmh_regulator_pmic530_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo530_mvp150 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 256,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic530_ldo,
+ .of_map_mode = rpmh_regulator_pmic530_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo530_mvp300 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 256,
+ .hpm_min_load_uA = 20000,
+ .pmic_mode_map = pmic_mode_map_pmic530_ldo,
+ .of_map_mode = rpmh_regulator_pmic530_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo530_mvp600 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 256,
+ .hpm_min_load_uA = 40000,
+ .pmic_mode_map = pmic_mode_map_pmic530_ldo,
+ .of_map_mode = rpmh_regulator_pmic530_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_ftsmps530 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(252000, 0, 305, 4000),
+ REGULATOR_LINEAR_RANGE(1480000, 306, 464, 8000),
+ },
+ .n_linear_ranges = 2,
+ .n_voltages = 465,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+#define RPMH_VREG(_name, _vreg_hw_type, _index, _hw_data, _supply_name) \
{ \
.name = _name, \
- .resource_name = _resource_name, \
+ .vreg_hw_type = _vreg_hw_type, \
+ .index = _index, \
.hw_data = _hw_data, \
.supply_name = _supply_name, \
}
static const struct rpmh_vreg_init_data pm8998_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic4_hfsmps3, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic4_ftsmps426, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic4_ftsmps426, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic4_ftsmps426, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic4_ftsmps426, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic4_ftsmps426, "vdd-s10"),
- RPMH_VREG("smps11", "smp%s11", &pmic4_ftsmps426, "vdd-s11"),
- RPMH_VREG("smps12", "smp%s12", &pmic4_ftsmps426, "vdd-s12"),
- RPMH_VREG("smps13", "smp%s13", &pmic4_ftsmps426, "vdd-s13"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l27"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l8-l17"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l3-l11"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic4_nldo, "vdd-l4-l5"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l4-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic4_nldo, "vdd-l2-l8-l17"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo, "vdd-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo, "vdd-l10-l23-l25"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic4_nldo, "vdd-l3-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo, "vdd-l13-l19-l21"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l16-l28"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic4_nldo, "vdd-l2-l8-l17"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l18-l22"),
- RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l13-l19-l21"),
- RPMH_VREG("ldo20", "ldo%s20", &pmic4_pldo, "vdd-l20-l24"),
- RPMH_VREG("ldo21", "ldo%s21", &pmic4_pldo, "vdd-l13-l19-l21"),
- RPMH_VREG("ldo22", "ldo%s22", &pmic4_pldo, "vdd-l18-l22"),
- RPMH_VREG("ldo23", "ldo%s23", &pmic4_pldo, "vdd-l10-l23-l25"),
- RPMH_VREG("ldo24", "ldo%s24", &pmic4_pldo, "vdd-l20-l24"),
- RPMH_VREG("ldo25", "ldo%s25", &pmic4_pldo, "vdd-l10-l23-l25"),
- RPMH_VREG("ldo26", "ldo%s26", &pmic4_nldo, "vdd-l26"),
- RPMH_VREG("ldo27", "ldo%s27", &pmic4_nldo, "vdd-l1-l27"),
- RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"),
- RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"),
- RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic4_hfsmps3, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic4_hfsmps3, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic4_hfsmps3, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic4_ftsmps426, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic4_ftsmps426, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic4_ftsmps426, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic4_ftsmps426, "vdd-s9"),
+ RPMH_VREG("smps10", SMPS, 10, &pmic4_ftsmps426, "vdd-s10"),
+ RPMH_VREG("smps11", SMPS, 11, &pmic4_ftsmps426, "vdd-s11"),
+ RPMH_VREG("smps12", SMPS, 12, &pmic4_ftsmps426, "vdd-s12"),
+ RPMH_VREG("smps13", SMPS, 13, &pmic4_ftsmps426, "vdd-s13"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic4_nldo, "vdd-l1-l27"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic4_nldo, "vdd-l3-l11"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic4_nldo, "vdd-l4-l5"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic4_nldo, "vdd-l4-l5"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic4_pldo, "vdd-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic4_pldo, "vdd-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic4_nldo, "vdd-l3-l11"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic4_pldo, "vdd-l16-l28"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo18", LDO, 18, &pmic4_pldo, "vdd-l18-l22"),
+ RPMH_VREG("ldo19", LDO, 19, &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo20", LDO, 20, &pmic4_pldo, "vdd-l20-l24"),
+ RPMH_VREG("ldo21", LDO, 21, &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo22", LDO, 22, &pmic4_pldo, "vdd-l18-l22"),
+ RPMH_VREG("ldo23", LDO, 23, &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo24", LDO, 24, &pmic4_pldo, "vdd-l20-l24"),
+ RPMH_VREG("ldo25", LDO, 25, &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo26", LDO, 26, &pmic4_nldo, "vdd-l26"),
+ RPMH_VREG("ldo27", LDO, 27, &pmic4_nldo, "vdd-l1-l27"),
+ RPMH_VREG("ldo28", LDO, 28, &pmic4_pldo, "vdd-l16-l28"),
+ RPMH_VREG("lvs1", VS, 1, &pmic4_lvs, "vin-lvs-1-2"),
+ RPMH_VREG("lvs2", VS, 2, &pmic4_lvs, "vin-lvs-1-2"),
{}
};
static const struct rpmh_vreg_init_data pmg1110_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
{}
};
static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
- RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
+ RPMH_VREG("bob", BOB, 1, &pmic4_bob, "vdd-bob"),
{}
};
static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic4_ftsmps426, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic4_ftsmps426, "vdd-s4"),
{}
};
static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps510, "vdd-s10"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, "vdd-l3-l4-l5-l18"),
{}
};
static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l1-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
- RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_pldo_lv, "vdd-l1-l8"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo_lv, "vdd-l1-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("bob", BOB, 1, &pmic5_bob, "vdd-bob"),
{}
};
static const struct rpmh_vreg_init_data pmm8155au_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps510, "vdd-s10"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, "vdd-l3-l4-l5-l18"),
{}
};
static const struct rpmh_vreg_init_data pmm8654au_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps527, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps527, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps527, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps527, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps527, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps527, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps527, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps527, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps527, "vdd-s9"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-s9"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-s9"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-s9"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6-l7"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l6-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo515_mv, "vdd-l8-l9"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps527, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps527, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps527, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps527, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps527, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps527, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps527, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps527, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps527, "vdd-s9"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo515, "vdd-l6-l7"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo515, "vdd-l6-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo515_mv, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l8-l9"),
{}
};
static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_hfsmps510, "vdd-s10"),
- RPMH_VREG("smps11", "smp%s11", &pmic5_hfsmps510, "vdd-s11"),
- RPMH_VREG("smps12", "smp%s12", &pmic5_hfsmps510, "vdd-s12"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l5"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", SMPS, 10, &pmic5_hfsmps510, "vdd-s10"),
+ RPMH_VREG("smps11", SMPS, 11, &pmic5_hfsmps510, "vdd-s11"),
+ RPMH_VREG("smps12", SMPS, 12, &pmic5_hfsmps510, "vdd-s12"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l4"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3-l5"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l1-l4"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l3-l5"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo, "vdd-l6-l9-l10"),
{}
};
static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps515, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l12"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo_lv, "vdd-l2-l8"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l9-l11"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l2-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l6-l9-l11"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l6-l9-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l1-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps515, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps510, "vdd-s10"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_pldo_lv, "vdd-l1-l12"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo_lv, "vdd-l2-l8"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l6-l9-l11"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo_lv, "vdd-l2-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l6-l9-l11"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo, "vdd-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l6-l9-l11"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo_lv, "vdd-l1-l12"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("bob", BOB, 1, &pmic5_bob, "vdd-bob"),
{}
};
static const struct rpmh_vreg_init_data pm8450_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps520, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps520, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps520, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps520, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps520, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps520, "vdd-s6"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo_lv, "vdd-l4"),
{}
};
static const struct rpmh_vreg_init_data pm8550_vreg_data[] = {
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1-l4-l10"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l13-l14"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l1-l4-l10"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l7"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l6-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l8-l9"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l1-l4-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l2-l13-l14"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l2-l13-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l17"),
- RPMH_VREG("bob1", "bob%s1", &pmic5_bob, "vdd-bob1"),
- RPMH_VREG("bob2", "bob%s2", &pmic5_bob, "vdd-bob2"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l16"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l6-l7"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l6-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l8-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo515, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo515, "vdd-l11"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo515, "vdd-l12"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo515, "vdd-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l5-l16"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l17"),
+ RPMH_VREG("bob1", BOB, 1, &pmic5_bob, "vdd-bob1"),
+ RPMH_VREG("bob2", BOB, 2, &pmic5_bob, "vdd-bob2"),
{}
};
static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_lv, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_mv, "vdd-s6"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"),
{}
};
static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps525, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps525, "vdd-s8"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"),
{}
};
static const struct rpmh_vreg_init_data pmc8380_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps525, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps525, "vdd-s8"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"),
{}
};
static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps515, "vdd-s2"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo_lv, "vdd-l7"),
{}
};
static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515_1, "vdd-s2"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps515_1, "vdd-s2"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo_lv, "vdd-l7"),
{}
};
static const struct rpmh_vreg_init_data pm8010_vreg_data[] = {
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo502, "vdd-l1-l2"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo502, "vdd-l1-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo502ln, "vdd-l3-l4"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo502ln, "vdd-l3-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo502, "vdd-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo502ln, "vdd-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo502, "vdd-l7"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo502, "vdd-l1-l2"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo502, "vdd-l1-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo502ln, "vdd-l3-l4"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo502ln, "vdd-l3-l4"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo502, "vdd-l5"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo502ln, "vdd-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo502, "vdd-l7"),
};
static const struct rpmh_vreg_init_data pm6150_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l7-l8"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l4-l7-l8"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l4-l7-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4-l7-l8"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo, "vdd-l4-l7-l8"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l4-l7-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo_lv, "vdd-l10-l14-l15"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo_lv, "vdd-l11-l12-l13"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo_lv, "vdd-l11-l12-l13"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo_lv, "vdd-l11-l12-l13"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo_lv, "vdd-l10-l14-l15"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_pldo_lv, "vdd-l10-l14-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("ldo18", LDO, 18, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("ldo19", LDO, 19, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
{}
};
static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l1-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
- RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_pldo_lv, "vdd-l1-l8"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo, "vdd-l1-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("bob", BOB, 1, &pmic5_bob, "vdd-bob"),
{}
};
static const struct rpmh_vreg_init_data pm6350_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, NULL),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, NULL),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, NULL),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, NULL),
/* smps3 - smps5 not configured */
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, NULL),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, NULL),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, NULL),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, NULL),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, NULL),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, NULL),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, NULL),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, NULL),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, NULL),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, NULL),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, NULL),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo, NULL),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, NULL),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, NULL),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, NULL),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, NULL),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, NULL),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_nldo, NULL),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, NULL),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, NULL),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo, NULL),
/* ldo17 not configured */
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, NULL),
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo, NULL),
- RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo, NULL),
- RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo, NULL),
- RPMH_VREG("ldo22", "ldo%s22", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, NULL),
+ RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo, NULL),
+ RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo, NULL),
+ RPMH_VREG("ldo21", LDO, 21, &pmic5_nldo, NULL),
+ RPMH_VREG("ldo22", LDO, 22, &pmic5_nldo, NULL),
+};
+
+static const struct rpmh_vreg_init_data pmcx0102_vreg_data[] = {
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps530, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps530, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps530, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps530, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps530, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps530, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps530, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps530, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps530, "vdd-s9"),
+ RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps530, "vdd-s10"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo530, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo530, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo530, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo530, "vdd-l4"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmh0101_vreg_data[] = {
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo530, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo530_mvp300, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo530, "vdd-l3-l11"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo530, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo530_mvp150, "vdd-l5-l16"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo530_mvp300, "vdd-l6-l7"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo530_mvp300, "vdd-l6-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo530_mvp150, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo515_mv, "vdd-l8-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo530, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo530, "vdd-l3-l11"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo530, "vdd-l12"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo530_mvp150, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo530_mvp150, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo530, "vdd-l15"),
+ RPMH_VREG("ldo16", LDO, 15, &pmic5_pldo530_mvp600, "vdd-l5-l16"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo515_mv, "vdd-l17"),
+ RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo530, "vdd-l18"),
+ RPMH_VREG("bob1", BOB, 1, &pmic5_bob, "vdd-bob1"),
+ RPMH_VREG("bob2", BOB, 2, &pmic5_bob, "vdd-bob2"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmh0104_vreg_data[] = {
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps530, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps530, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps530, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps530, "vdd-s4"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmh0110_vreg_data[] = {
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps530, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps530, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps530, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps530, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps530, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps530, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps530, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps530, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps530, "vdd-s9"),
+ RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps530, "vdd-s10"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo530, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo530, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo530, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo530, "vdd-l4"),
+ {}
};
static const struct rpmh_vreg_init_data pmx55_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_hfsmps510, "vdd-s7"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l9"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l12"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7-l8"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l7-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l3-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10-l11-l13"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l10-l11-l13"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l4-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l10-l11-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l16"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_hfsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_hfsmps510, "vdd-s7"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3-l9"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4-l12"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo, "vdd-l7-l8"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l7-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l3-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l10-l11-l13"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l10-l11-l13"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo, "vdd-l4-l12"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l10-l11-l13"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_nldo, "vdd-l14"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, "vdd-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l16"),
{}
};
static const struct rpmh_vreg_init_data pmx65_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_hfsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l18"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6-l16"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6-l16"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8-l9"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l8-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l6-l16"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo, "vdd-l17"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_hfsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_hfsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2-l18"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l6-l16"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l5-l6-l16"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo, "vdd-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l8-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo, "vdd-l12"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_nldo, "vdd-l14"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, "vdd-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l5-l6-l16"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_nldo, "vdd-l17"),
/* ldo18 not configured */
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo, "vdd-l19"),
- RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo, "vdd-l20"),
- RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo, "vdd-l21"),
+ RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo, "vdd-l19"),
+ RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo, "vdd-l20"),
+ RPMH_VREG("ldo21", LDO, 21, &pmic5_nldo, "vdd-l21"),
{}
};
static const struct rpmh_vreg_init_data pmx75_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525_lv, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525_lv, "vdd-s10"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-18"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l4-l16"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo_lv, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo_lv, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo515, "vdd-l8-l9"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo515, "vdd-l8-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo515, "vdd-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo515, "vdd-l4-l16"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo515, "vdd-l17"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps525, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps525, "vdd-s8"),
+ RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps525, "vdd-s9"),
+ RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps525, "vdd-s10"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2-18"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-l4-l16"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo_lv, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo_lv, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo515, "vdd-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo515, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo515, "vdd-l8-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo515, "vdd-l12"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_nldo515, "vdd-l14"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo515, "vdd-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo515, "vdd-l4-l16"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_nldo515, "vdd-l17"),
/* ldo18 not configured */
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo515, "vdd-l19"),
- RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo515, "vdd-l20-l21"),
- RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo515, "vdd-l20-l21"),
+ RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo515, "vdd-l19"),
+ RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo515, "vdd-l20-l21"),
+ RPMH_VREG("ldo21", LDO, 21, &pmic5_nldo515, "vdd-l20-l21"),
};
static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps520, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, "vdd-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14-l16"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, "vdd-l14-l16"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps520, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps520, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps520, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps520, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps520, "vdd-s6"),
+ RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps520, "vdd-s7"),
+ RPMH_VREG("smps8", SMPS, 8, &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l5"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_nldo, "vdd-l13"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_nldo, "vdd-l14-l16"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo, "vdd-l14-l16"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo18", LDO, 18, &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo19", LDO, 19, &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm7550_vreg_data[] = {
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-l4-l5"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo515, "vdd-l4-l5"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo515, "vdd-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo515, "vdd-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo515, "vdd-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo515, "vdd-l9-l10"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo515, "vdd-l9-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo515, "vdd-l11"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo515_mv, "vdd-l12-l14"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo515_mv, "vdd-l13-l16"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, "vdd-l12-l14"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l13-l16"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo18", LDO, 18, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo19", LDO, 19, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo20", LDO, 20, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo21", LDO, 21, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo22", LDO, 22, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("ldo23", LDO, 23, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"),
+ RPMH_VREG("bob", BOB, 1, &pmic5_bob, "vdd-bob"),
{}
};
static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps515, "vdd-s3"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps520, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps520, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic5_hfsmps515, "vdd-s3"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo_lv, "vdd-l4"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l7-bob"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmr735b_vreg_data[] = {
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo_lv, "vdd-l4"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l5"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo, "vdd-l7-l8"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l7-l8"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l9"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo_lv, "vdd-l10"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo, "vdd-l11"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo, "vdd-l12"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmr735d_vreg_data[] = {
+ RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1-l2-l5"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l1-l2-l5"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3-l4"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-l3-l4"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo515, "vdd-l1-l2-l5"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo515, "vdd-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo515, "vdd-l7"),
{}
};
static const struct rpmh_vreg_init_data pm660_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic4_hfsmps3, "vdd-s6"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l6-l7"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l2-l3"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic4_ftsmps426, "vdd-s3"),
+ RPMH_VREG("smps4", SMPS, 4, &pmic4_hfsmps3, "vdd-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic4_hfsmps3, "vdd-s5"),
+ RPMH_VREG("smps6", SMPS, 6, &pmic4_hfsmps3, "vdd-s6"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic4_nldo, "vdd-l1-l6-l7"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic4_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic4_nldo, "vdd-l2-l3"),
/* ldo4 is inaccessible on PM660 */
- RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic4_nldo, "vdd-l1-l6-l7"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic4_nldo, "vdd-l1-l6-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic4_nldo, "vdd-l5"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic4_nldo, "vdd-l1-l6-l7"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic4_nldo, "vdd-l1-l6-l7"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo9", LDO, 9, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo10", LDO, 10, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo11", LDO, 11, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo12", LDO, 12, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo13", LDO, 13, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo14", LDO, 14, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo15", LDO, 15, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo16", LDO, 16, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo17", LDO, 17, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo18", LDO, 18, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo19", LDO, 19, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
{}
};
static const struct rpmh_vreg_init_data pm660l_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic4_ftsmps426, "vdd-s5"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l9-l10"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic4_pldo, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic4_pldo, "vdd-l4-l6"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l4-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
- RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
+ RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", SMPS, 3, &pmic4_ftsmps426, "vdd-s3-s4"),
+ RPMH_VREG("smps5", SMPS, 5, &pmic4_ftsmps426, "vdd-s5"),
+ RPMH_VREG("ldo1", LDO, 1, &pmic4_nldo, "vdd-l1-l9-l10"),
+ RPMH_VREG("ldo2", LDO, 2, &pmic4_pldo, "vdd-l2"),
+ RPMH_VREG("ldo3", LDO, 3, &pmic4_pldo, "vdd-l3-l5-l7-l8"),
+ RPMH_VREG("ldo4", LDO, 4, &pmic4_pldo, "vdd-l4-l6"),
+ RPMH_VREG("ldo5", LDO, 5, &pmic4_pldo, "vdd-l3-l5-l7-l8"),
+ RPMH_VREG("ldo6", LDO, 6, &pmic4_pldo, "vdd-l4-l6"),
+ RPMH_VREG("ldo7", LDO, 7, &pmic4_pldo, "vdd-l3-l5-l7-l8"),
+ RPMH_VREG("ldo8", LDO, 8, &pmic4_pldo, "vdd-l3-l5-l7-l8"),
+ RPMH_VREG("bob", BOB, 1, &pmic4_bob, "vdd-bob"),
{}
};
@@ -1651,6 +1910,22 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.data = pmc8380_vreg_data,
},
{
+ .compatible = "qcom,pmcx0102-rpmh-regulators",
+ .data = pmcx0102_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmh0101-rpmh-regulators",
+ .data = pmh0101_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmh0104-rpmh-regulators",
+ .data = pmh0104_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmh0110-rpmh-regulators",
+ .data = pmh0110_vreg_data,
+ },
+ {
.compatible = "qcom,pmm8155au-rpmh-regulators",
.data = pmm8155au_vreg_data,
},
@@ -1675,10 +1950,22 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.data = pm7325_vreg_data,
},
{
+ .compatible = "qcom,pm7550-rpmh-regulators",
+ .data = pm7550_vreg_data,
+ },
+ {
.compatible = "qcom,pmr735a-rpmh-regulators",
.data = pmr735a_vreg_data,
},
{
+ .compatible = "qcom,pmr735b-rpmh-regulators",
+ .data = pmr735b_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmr735d-rpmh-regulators",
+ .data = pmr735d_vreg_data,
+ },
+ {
.compatible = "qcom,pm660-rpmh-regulators",
.data = pm660_vreg_data,
},
diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c
index d66a0f61637e..c1a41ce70b36 100644
--- a/drivers/regulator/qcom_spmi-regulator.c
+++ b/drivers/regulator/qcom_spmi-regulator.c
@@ -400,7 +400,7 @@ struct spmi_voltage_range {
* so that range[i].set_point_max_uV < range[i+1].set_point_min_uV.
*/
struct spmi_voltage_set_points {
- struct spmi_voltage_range *range;
+ const struct spmi_voltage_range *range;
int count;
unsigned n_voltages;
};
@@ -474,6 +474,9 @@ struct spmi_regulator_data {
.set_point_max_uV = _set_point_max_uV, \
.step_uV = _step_uV, \
.range_sel = _range_sel, \
+ .n_voltages = (_set_point_max_uV != 0) ? \
+ ((_set_point_max_uV - _set_point_min_uV) / _step_uV) + 1 : \
+ 0, \
}
#define DEFINE_SPMI_SET_POINTS(name) \
@@ -489,110 +492,110 @@ struct spmi_voltage_set_points name##_set_points = { \
* increasing and unique. The set_voltage callback functions expect these
* properties to hold.
*/
-static struct spmi_voltage_range pldo_ranges[] = {
+static const struct spmi_voltage_range pldo_ranges[] = {
SPMI_VOLTAGE_RANGE(2, 750000, 750000, 1537500, 1537500, 12500),
SPMI_VOLTAGE_RANGE(3, 1500000, 1550000, 3075000, 3075000, 25000),
SPMI_VOLTAGE_RANGE(4, 1750000, 3100000, 4900000, 4900000, 50000),
};
-static struct spmi_voltage_range nldo1_ranges[] = {
+static const struct spmi_voltage_range nldo1_ranges[] = {
SPMI_VOLTAGE_RANGE(2, 750000, 750000, 1537500, 1537500, 12500),
};
-static struct spmi_voltage_range nldo2_ranges[] = {
+static const struct spmi_voltage_range nldo2_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 375000, 0, 0, 1537500, 12500),
SPMI_VOLTAGE_RANGE(1, 375000, 375000, 768750, 768750, 6250),
SPMI_VOLTAGE_RANGE(2, 750000, 775000, 1537500, 1537500, 12500),
};
-static struct spmi_voltage_range nldo3_ranges[] = {
+static const struct spmi_voltage_range nldo3_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 375000, 375000, 1537500, 1537500, 12500),
SPMI_VOLTAGE_RANGE(1, 375000, 0, 0, 1537500, 12500),
SPMI_VOLTAGE_RANGE(2, 750000, 0, 0, 1537500, 12500),
};
-static struct spmi_voltage_range ln_ldo_ranges[] = {
+static const struct spmi_voltage_range ln_ldo_ranges[] = {
SPMI_VOLTAGE_RANGE(1, 690000, 690000, 1110000, 1110000, 60000),
SPMI_VOLTAGE_RANGE(0, 1380000, 1380000, 2220000, 2220000, 120000),
};
-static struct spmi_voltage_range smps_ranges[] = {
+static const struct spmi_voltage_range smps_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 375000, 375000, 1562500, 1562500, 12500),
SPMI_VOLTAGE_RANGE(1, 1550000, 1575000, 3125000, 3125000, 25000),
};
-static struct spmi_voltage_range ftsmps_ranges[] = {
+static const struct spmi_voltage_range ftsmps_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 0, 350000, 1275000, 1275000, 5000),
SPMI_VOLTAGE_RANGE(1, 0, 1280000, 2040000, 2040000, 10000),
};
-static struct spmi_voltage_range ftsmps2p5_ranges[] = {
+static const struct spmi_voltage_range ftsmps2p5_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 80000, 350000, 1355000, 1355000, 5000),
SPMI_VOLTAGE_RANGE(1, 160000, 1360000, 2200000, 2200000, 10000),
};
-static struct spmi_voltage_range ftsmps426_ranges[] = {
+static const struct spmi_voltage_range ftsmps426_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 0, 320000, 1352000, 1352000, 4000),
};
-static struct spmi_voltage_range boost_ranges[] = {
+static const struct spmi_voltage_range boost_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 4000000, 4000000, 5550000, 5550000, 50000),
};
-static struct spmi_voltage_range boost_byp_ranges[] = {
+static const struct spmi_voltage_range boost_byp_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 2500000, 2500000, 5200000, 5650000, 50000),
};
-static struct spmi_voltage_range ult_lo_smps_ranges[] = {
+static const struct spmi_voltage_range ult_lo_smps_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 375000, 375000, 1562500, 1562500, 12500),
SPMI_VOLTAGE_RANGE(1, 750000, 0, 0, 1525000, 25000),
};
-static struct spmi_voltage_range ult_ho_smps_ranges[] = {
+static const struct spmi_voltage_range ult_ho_smps_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 1550000, 1550000, 2325000, 2325000, 25000),
};
-static struct spmi_voltage_range ult_nldo_ranges[] = {
+static const struct spmi_voltage_range ult_nldo_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 375000, 375000, 1537500, 1537500, 12500),
};
-static struct spmi_voltage_range ult_pldo_ranges[] = {
+static const struct spmi_voltage_range ult_pldo_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 1750000, 1750000, 3337500, 3337500, 12500),
};
-static struct spmi_voltage_range pldo660_ranges[] = {
+static const struct spmi_voltage_range pldo660_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 1504000, 1504000, 3544000, 3544000, 8000),
};
-static struct spmi_voltage_range nldo660_ranges[] = {
+static const struct spmi_voltage_range nldo660_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 320000, 320000, 1304000, 1304000, 8000),
};
-static struct spmi_voltage_range ht_lvpldo_ranges[] = {
+static const struct spmi_voltage_range ht_lvpldo_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 1504000, 1504000, 2000000, 2000000, 8000),
};
-static struct spmi_voltage_range ht_nldo_ranges[] = {
+static const struct spmi_voltage_range ht_nldo_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 312000, 312000, 1304000, 1304000, 8000),
};
-static struct spmi_voltage_range hfs430_ranges[] = {
+static const struct spmi_voltage_range hfs430_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 320000, 320000, 2040000, 2040000, 8000),
};
-static struct spmi_voltage_range ht_p150_ranges[] = {
+static const struct spmi_voltage_range ht_p150_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 1616000, 1616000, 3304000, 3304000, 8000),
};
-static struct spmi_voltage_range ht_p600_ranges[] = {
+static const struct spmi_voltage_range ht_p600_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 1704000, 1704000, 1896000, 1896000, 8000),
};
-static struct spmi_voltage_range nldo_510_ranges[] = {
+static const struct spmi_voltage_range nldo_510_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 320000, 320000, 1304000, 1304000, 8000),
};
-static struct spmi_voltage_range ftsmps510_ranges[] = {
+static const struct spmi_voltage_range ftsmps510_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 300000, 300000, 1372000, 1372000, 4000),
};
@@ -1676,18 +1679,10 @@ static const struct spmi_regulator_mapping supported_regulators[] = {
static void spmi_calculate_num_voltages(struct spmi_voltage_set_points *points)
{
- unsigned int n;
- struct spmi_voltage_range *range = points->range;
-
- for (; range < points->range + points->count; range++) {
- n = 0;
- if (range->set_point_max_uV) {
- n = range->set_point_max_uV - range->set_point_min_uV;
- n = (n / range->step_uV) + 1;
- }
- range->n_voltages = n;
- points->n_voltages += n;
- }
+ const struct spmi_voltage_range *range = points->range;
+
+ for (; range < points->range + points->count; range++)
+ points->n_voltages += range->n_voltages;
}
static int spmi_regulator_match(struct spmi_regulator *vreg, u16 force_type)
diff --git a/drivers/regulator/renesas-usb-vbus-regulator.c b/drivers/regulator/renesas-usb-vbus-regulator.c
index dec7cac5e8d5..9ba791bd72ec 100644
--- a/drivers/regulator/renesas-usb-vbus-regulator.c
+++ b/drivers/regulator/renesas-usb-vbus-regulator.c
@@ -7,12 +7,10 @@
#include <linux/module.h>
#include <linux/err.h>
-#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
-#include <linux/regulator/of_regulator.h>
static const struct regulator_ops rzg2l_usb_vbus_reg_ops = {
.enable = regulator_enable_regmap,
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index 7d82bd1b36df..1e8142479656 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -270,8 +270,8 @@ static const unsigned int rk817_buck1_4_ramp_table[] = {
static int rk806_set_mode_dcdc(struct regulator_dev *rdev, unsigned int mode)
{
- int rid = rdev_get_id(rdev);
- int ctr_bit, reg;
+ unsigned int rid = rdev_get_id(rdev);
+ unsigned int ctr_bit, reg;
reg = RK806_POWER_FPWM_EN0 + rid / 8;
ctr_bit = rid % 8;
diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c
index 6c3b6bfac961..3020839b9ef1 100644
--- a/drivers/regulator/rpi-panel-attiny-regulator.c
+++ b/drivers/regulator/rpi-panel-attiny-regulator.c
@@ -6,12 +6,14 @@
*/
#include <linux/backlight.h>
+#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -93,7 +95,7 @@ static int attiny_lcd_power_enable(struct regulator_dev *rdev)
{
struct attiny_lcd *state = rdev_get_drvdata(rdev);
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
/* Ensure bridge, and tp stay in reset */
attiny_set_port_state(state, REG_PORTC, 0);
@@ -114,8 +116,6 @@ static int attiny_lcd_power_enable(struct regulator_dev *rdev)
msleep(80);
- mutex_unlock(&state->lock);
-
return 0;
}
@@ -123,7 +123,7 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev)
{
struct attiny_lcd *state = rdev_get_drvdata(rdev);
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
regmap_write(rdev->regmap, REG_PWM, 0);
usleep_range(5000, 10000);
@@ -135,8 +135,6 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev)
attiny_set_port_state(state, REG_PORTC, 0);
msleep(30);
- mutex_unlock(&state->lock);
-
return 0;
}
@@ -144,19 +142,17 @@ static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev)
{
struct attiny_lcd *state = rdev_get_drvdata(rdev);
unsigned int data;
- int ret, i;
-
- mutex_lock(&state->lock);
-
- for (i = 0; i < 10; i++) {
- ret = regmap_read(rdev->regmap, REG_PORTC, &data);
- if (!ret)
- break;
- usleep_range(10000, 12000);
+ int ret = 0, i;
+
+ scoped_guard(mutex, &state->lock) {
+ for (i = 0; i < 10; i++) {
+ ret = regmap_read(rdev->regmap, REG_PORTC, &data);
+ if (!ret)
+ break;
+ usleep_range(10000, 12000);
+ }
}
- mutex_unlock(&state->lock);
-
if (ret < 0)
return ret;
@@ -189,7 +185,7 @@ static int attiny_update_status(struct backlight_device *bl)
int brightness = backlight_get_brightness(bl);
int ret, i;
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
for (i = 0; i < 10; i++) {
ret = regmap_write(regmap, REG_PWM, brightness);
@@ -197,8 +193,6 @@ static int attiny_update_status(struct backlight_device *bl)
break;
}
- mutex_unlock(&state->lock);
-
return ret;
}
@@ -211,15 +205,12 @@ static int attiny_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
return GPIO_LINE_DIRECTION_OUT;
}
-static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
+static int attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
{
struct attiny_lcd *state = gpiochip_get_data(gc);
u8 last_val;
- if (off >= NUM_GPIO)
- return;
-
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
last_val = attiny_get_port_state(state, mappings[off].reg);
if (val)
@@ -242,7 +233,7 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
msleep(100);
}
- mutex_unlock(&state->lock);
+ return 0;
}
static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf)
@@ -296,7 +287,10 @@ static int attiny_i2c_probe(struct i2c_client *i2c)
if (!state)
return -ENOMEM;
- mutex_init(&state->lock);
+ ret = devm_mutex_init(&i2c->dev, &state->lock);
+ if (ret)
+ return ret;
+
i2c_set_clientdata(i2c, state);
regmap = devm_regmap_init_i2c(i2c, &attiny_regmap_config);
@@ -304,13 +298,13 @@ static int attiny_i2c_probe(struct i2c_client *i2c)
ret = PTR_ERR(regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
- goto error;
+ return ret;
}
ret = attiny_i2c_read(i2c, REG_ID, &data);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret);
- goto error;
+ return ret;
}
switch (data) {
@@ -319,8 +313,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c)
break;
default:
dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data);
- ret = -ENODEV;
- goto error;
+ return -ENODEV;
}
regmap_write(regmap, REG_POWERON, 0);
@@ -336,8 +329,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c)
rdev = devm_regulator_register(&i2c->dev, &attiny_regulator, &config);
if (IS_ERR(rdev)) {
dev_err(&i2c->dev, "Failed to register ATTINY regulator\n");
- ret = PTR_ERR(rdev);
- goto error;
+ return PTR_ERR(rdev);
}
props.type = BACKLIGHT_RAW;
@@ -348,10 +340,8 @@ static int attiny_i2c_probe(struct i2c_client *i2c)
bl = devm_backlight_device_register(&i2c->dev, dev_name(&i2c->dev),
&i2c->dev, state, &attiny_bl,
&props);
- if (IS_ERR(bl)) {
- ret = PTR_ERR(bl);
- goto error;
- }
+ if (IS_ERR(bl))
+ return PTR_ERR(bl);
bl->props.brightness = 0xff;
@@ -366,26 +356,12 @@ static int attiny_i2c_probe(struct i2c_client *i2c)
state->gc.can_sleep = true;
ret = devm_gpiochip_add_data(&i2c->dev, &state->gc, state);
- if (ret) {
+ if (ret)
dev_err(&i2c->dev, "Failed to create gpiochip: %d\n", ret);
- goto error;
- }
-
- return 0;
-
-error:
- mutex_destroy(&state->lock);
return ret;
}
-static void attiny_i2c_remove(struct i2c_client *client)
-{
- struct attiny_lcd *state = i2c_get_clientdata(client);
-
- mutex_destroy(&state->lock);
-}
-
static const struct of_device_id attiny_dt_ids[] = {
{ .compatible = "raspberrypi,7inch-touchscreen-panel-regulator" },
{},
@@ -399,7 +375,6 @@ static struct i2c_driver attiny_regulator_driver = {
.of_match_table = attiny_dt_ids,
},
.probe = attiny_i2c_probe,
- .remove = attiny_i2c_remove,
};
module_i2c_driver(attiny_regulator_driver);
diff --git a/drivers/regulator/rpi-panel-v2-regulator.c b/drivers/regulator/rpi-panel-v2-regulator.c
new file mode 100644
index 000000000000..30b78aa75ee3
--- /dev/null
+++ b/drivers/regulator/rpi-panel-v2-regulator.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Raspberry Pi Ltd.
+ * Copyright (C) 2025 Marek Vasut
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/regmap.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+
+/* I2C registers of the microcontroller. */
+#define REG_ID 0x01
+#define REG_POWERON 0x02
+#define REG_PWM 0x03
+
+/* Bits for poweron register */
+#define LCD_RESET_BIT BIT(0)
+#define CTP_RESET_BIT BIT(1)
+
+/* Bits for the PWM register */
+#define PWM_BL_ENABLE BIT(7)
+#define PWM_BL_MASK GENMASK(4, 0)
+
+/* Treat LCD_RESET and CTP_RESET as GPIOs */
+#define NUM_GPIO 2
+
+static const struct regmap_config rpi_panel_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_PWM,
+ .can_sleep = true,
+};
+
+static int rpi_panel_v2_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct regmap *regmap = pwmchip_get_drvdata(chip);
+ unsigned int duty;
+
+ if (state->polarity != PWM_POLARITY_NORMAL)
+ return -EINVAL;
+
+ if (!state->enabled)
+ return regmap_write(regmap, REG_PWM, 0);
+
+ duty = pwm_get_relative_duty_cycle(state, PWM_BL_MASK);
+ return regmap_write(regmap, REG_PWM, duty | PWM_BL_ENABLE);
+}
+
+static const struct pwm_ops rpi_panel_v2_pwm_ops = {
+ .apply = rpi_panel_v2_pwm_apply,
+};
+
+/*
+ * I2C driver interface functions
+ */
+static int rpi_panel_v2_i2c_probe(struct i2c_client *i2c)
+{
+ struct gpio_regmap_config gconfig = {
+ .ngpio = NUM_GPIO,
+ .ngpio_per_reg = NUM_GPIO,
+ .parent = &i2c->dev,
+ .reg_set_base = REG_POWERON,
+ };
+ struct regmap *regmap;
+ struct pwm_chip *pc;
+ int ret;
+
+ pc = devm_pwmchip_alloc(&i2c->dev, 1, 0);
+ if (IS_ERR(pc))
+ return PTR_ERR(pc);
+
+ pc->ops = &rpi_panel_v2_pwm_ops;
+
+ regmap = devm_regmap_init_i2c(i2c, &rpi_panel_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(regmap), "Failed to allocate regmap\n");
+
+ pwmchip_set_drvdata(pc, regmap);
+
+ regmap_write(regmap, REG_POWERON, 0);
+
+ gconfig.regmap = regmap;
+ ret = PTR_ERR_OR_ZERO(devm_gpio_regmap_register(&i2c->dev, &gconfig));
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Failed to create gpiochip\n");
+
+ i2c_set_clientdata(i2c, regmap);
+
+ return devm_pwmchip_add(&i2c->dev, pc);
+}
+
+static void rpi_panel_v2_i2c_shutdown(struct i2c_client *client)
+{
+ struct regmap *regmap = i2c_get_clientdata(client);
+
+ regmap_write(regmap, REG_PWM, 0);
+ regmap_write(regmap, REG_POWERON, 0);
+}
+
+static const struct of_device_id rpi_panel_v2_dt_ids[] = {
+ { .compatible = "raspberrypi,touchscreen-panel-regulator-v2" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, rpi_panel_v2_dt_ids);
+
+static struct i2c_driver rpi_panel_v2_regulator_driver = {
+ .driver = {
+ .name = "rpi_touchscreen_v2",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = rpi_panel_v2_dt_ids,
+ },
+ .probe = rpi_panel_v2_i2c_probe,
+ .shutdown = rpi_panel_v2_i2c_shutdown,
+};
+
+module_i2c_driver(rpi_panel_v2_regulator_driver);
+
+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>");
+MODULE_DESCRIPTION("Regulator device driver for Raspberry Pi 7-inch V2 touchscreen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/rt5133-regulator.c b/drivers/regulator/rt5133-regulator.c
new file mode 100644
index 000000000000..129b1f13c880
--- /dev/null
+++ b/drivers/regulator/rt5133-regulator.c
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2025 Richtek Technology Corp.
+// Author: ChiYuan Huang <cy_huang@richtek.com>
+// Author: ShihChia Chang <jeff_chang@richtek.com>
+
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+
+#define RT5133_REG_CHIP_INFO 0x00
+#define RT5133_REG_RST_CTRL 0x06
+#define RT5133_REG_BASE_CTRL 0x09
+#define RT5133_REG_GPIO_CTRL 0x0B
+#define RT5133_REG_BASE_EVT 0x10
+#define RT5133_REG_LDO_PGB_STAT 0x15
+#define RT5133_REG_BASE_MASK 0x16
+#define RT5133_REG_LDO_SHDN 0x19
+#define RT5133_REG_LDO_ON 0x1A
+#define RT5133_REG_LDO_OFF 0x1B
+#define RT5133_REG_LDO1_CTRL1 0x20
+#define RT5133_REG_LDO1_CTRL2 0x21
+#define RT5133_REG_LDO1_CTRL3 0x22
+#define RT5133_REG_LDO2_CTRL1 0x24
+#define RT5133_REG_LDO2_CTRL2 0x25
+#define RT5133_REG_LDO2_CTRL3 0x26
+#define RT5133_REG_LDO3_CTRL1 0x28
+#define RT5133_REG_LDO3_CTRL2 0x29
+#define RT5133_REG_LDO3_CTRL3 0x2A
+#define RT5133_REG_LDO4_CTRL1 0x2C
+#define RT5133_REG_LDO4_CTRL2 0x2D
+#define RT5133_REG_LDO4_CTRL3 0x2E
+#define RT5133_REG_LDO5_CTRL1 0x30
+#define RT5133_REG_LDO5_CTRL2 0x31
+#define RT5133_REG_LDO5_CTRL3 0x32
+#define RT5133_REG_LDO6_CTRL1 0x34
+#define RT5133_REG_LDO6_CTRL2 0x35
+#define RT5133_REG_LDO6_CTRL3 0x36
+#define RT5133_REG_LDO7_CTRL1 0x38
+#define RT5133_REG_LDO7_CTRL2 0x39
+#define RT5133_REG_LDO7_CTRL3 0x3A
+#define RT5133_REG_LDO8_CTRL1 0x3C
+#define RT5133_REG_LDO8_CTRL2 0x3D
+#define RT5133_REG_LDO8_CTRL3 0x3E
+#define RT5133_REG_LDO8_CTRL4 0x3F
+
+#define RT5133_LDO_REG_BASE(_id) (0x20 + ((_id) - 1) * 4)
+
+#define RT5133_VENDOR_ID_MASK GENMASK(7, 4)
+#define RT5133_RESET_CODE 0xB1
+
+#define RT5133_FOFF_BASE_MASK BIT(1)
+#define RT5133_OCSHDN_ALL_MASK BIT(7)
+#define RT5133_OCSHDN_ALL_SHIFT (7)
+#define RT5133_PGBSHDN_ALL_MASK BIT(6)
+#define RT5133_PGBSHDN_ALL_SHIFT (6)
+
+#define RT5133_OCPTSEL_MASK BIT(5)
+#define RT5133_PGBPTSEL_MASK BIT(4)
+#define RT5133_STBTDSEL_MASK GENMASK(1, 0)
+
+#define RT5133_LDO_ENABLE_MASK BIT(7)
+#define RT5133_LDO_VSEL_MASK GENMASK(7, 5)
+#define RT5133_LDO_AD_MASK BIT(2)
+#define RT5133_LDO_SOFT_START_MASK GENMASK(1, 0)
+
+#define RT5133_GPIO_NR 3
+
+#define RT5133_LDO_PGB_EVT_MASK GENMASK(23, 16)
+#define RT5133_LDO_PGB_EVT_SHIFT 16
+#define RT5133_LDO_OC_EVT_MASK GENMASK(15, 8)
+#define RT5133_LDO_OC_EVT_SHIFT 8
+#define RT5133_VREF_EVT_MASK BIT(6)
+#define RT5133_BASE_EVT_MASK GENMASK(7, 0)
+#define RT5133_INTR_CLR_MASK GENMASK(23, 0)
+#define RT5133_INTR_BYTE_NR 3
+
+#define RT5133_MAX_I2C_BLOCK_SIZE 1
+
+#define RT5133_CRC8_POLYNOMIAL 0x7
+
+#define RT5133_I2C_ADDR_LEN 1
+#define RT5133_PREDATA_LEN 2
+#define RT5133_I2C_CRC_LEN 1
+#define RT5133_REG_ADDR_LEN 1
+#define RT5133_I2C_DUMMY_LEN 1
+
+#define I2C_ADDR_XLATE_8BIT(_addr, _rw) ((((_addr) & 0x7F) << 1) | (_rw))
+
+enum {
+ RT5133_REGULATOR_BASE = 0,
+ RT5133_REGULATOR_LDO1,
+ RT5133_REGULATOR_LDO2,
+ RT5133_REGULATOR_LDO3,
+ RT5133_REGULATOR_LDO4,
+ RT5133_REGULATOR_LDO5,
+ RT5133_REGULATOR_LDO6,
+ RT5133_REGULATOR_LDO7,
+ RT5133_REGULATOR_LDO8,
+ RT5133_REGULATOR_MAX
+};
+
+struct chip_data {
+ const struct regulator_desc *regulators;
+ const u8 vendor_id;
+};
+
+struct rt5133_priv {
+ struct device *dev;
+ struct regmap *regmap;
+ struct gpio_desc *enable_gpio;
+ struct regulator_dev *rdev[RT5133_REGULATOR_MAX];
+ struct gpio_chip gc;
+ const struct chip_data *cdata;
+ unsigned int gpio_output_flag;
+ u8 crc8_tbls[CRC8_TABLE_SIZE];
+};
+
+static const unsigned int vout_type1_tables[] = {
+ 1800000, 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000
+};
+
+static const unsigned int vout_type2_tables[] = {
+ 1700000, 1800000, 1900000, 2500000, 2700000, 2800000, 2900000, 3000000
+};
+
+static const unsigned int vout_type3_tables[] = {
+ 900000, 950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1800000
+};
+
+static const unsigned int vout_type4_tables[] = {
+ 855000, 900000, 950000, 1000000, 1040000, 1090000, 1140000, 1710000
+};
+
+static const struct regulator_ops rt5133_regulator_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+};
+
+static const struct regulator_ops rt5133_base_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+#define RT5133_REGULATOR_DESC(_name, _node_name, vtables, _supply) \
+{\
+ .name = #_name,\
+ .id = RT5133_REGULATOR_##_name,\
+ .of_match = of_match_ptr(#_node_name),\
+ .regulators_node = of_match_ptr("regulators"),\
+ .supply_name = _supply,\
+ .type = REGULATOR_VOLTAGE,\
+ .owner = THIS_MODULE,\
+ .ops = &rt5133_regulator_ops,\
+ .n_voltages = ARRAY_SIZE(vtables),\
+ .volt_table = vtables,\
+ .enable_reg = RT5133_REG_##_name##_CTRL1,\
+ .enable_mask = RT5133_LDO_ENABLE_MASK,\
+ .vsel_reg = RT5133_REG_##_name##_CTRL2,\
+ .vsel_mask = RT5133_LDO_VSEL_MASK,\
+ .active_discharge_reg = RT5133_REG_##_name##_CTRL3,\
+ .active_discharge_mask = RT5133_LDO_AD_MASK,\
+}
+
+static const struct regulator_desc rt5133_regulators[] = {
+ /* For digital part, base current control */
+ {
+ .name = "base",
+ .id = RT5133_REGULATOR_BASE,
+ .of_match = of_match_ptr("base"),
+ .regulators_node = of_match_ptr("regulators"),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .ops = &rt5133_base_regulator_ops,
+ .enable_reg = RT5133_REG_BASE_CTRL,
+ .enable_mask = RT5133_FOFF_BASE_MASK,
+ .enable_is_inverted = true,
+ },
+ RT5133_REGULATOR_DESC(LDO1, ldo1, vout_type1_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO2, ldo2, vout_type1_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO3, ldo3, vout_type2_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO4, ldo4, vout_type2_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO5, ldo5, vout_type2_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO6, ldo6, vout_type2_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO7, ldo7, vout_type3_tables, "vin"),
+ RT5133_REGULATOR_DESC(LDO8, ldo8, vout_type3_tables, "vin"),
+};
+
+static const struct regulator_desc rt5133a_regulators[] = {
+ /* For digital part, base current control */
+ {
+ .name = "base",
+ .id = RT5133_REGULATOR_BASE,
+ .of_match = of_match_ptr("base"),
+ .regulators_node = of_match_ptr("regulators"),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .ops = &rt5133_base_regulator_ops,
+ .enable_reg = RT5133_REG_BASE_CTRL,
+ .enable_mask = RT5133_FOFF_BASE_MASK,
+ .enable_is_inverted = true,
+ },
+ RT5133_REGULATOR_DESC(LDO1, ldo1, vout_type1_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO2, ldo2, vout_type1_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO3, ldo3, vout_type2_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO4, ldo4, vout_type2_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO5, ldo5, vout_type2_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO6, ldo6, vout_type2_tables, "base"),
+ RT5133_REGULATOR_DESC(LDO7, ldo7, vout_type3_tables, "vin"),
+ RT5133_REGULATOR_DESC(LDO8, ldo8, vout_type4_tables, "vin"),
+};
+
+static const struct chip_data regulator_data[] = {
+ { rt5133_regulators, 0x70},
+ { rt5133a_regulators, 0x80},
+};
+
+static int rt5133_gpio_direction_output(struct gpio_chip *gpio,
+ unsigned int offset, int value)
+{
+ struct rt5133_priv *priv = gpiochip_get_data(gpio);
+
+ if (offset >= RT5133_GPIO_NR)
+ return -EINVAL;
+
+ return regmap_update_bits(priv->regmap, RT5133_REG_GPIO_CTRL,
+ BIT(7 - offset) | BIT(3 - offset),
+ value ? BIT(7 - offset) | BIT(3 - offset) : 0);
+}
+
+static int rt5133_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rt5133_priv *priv = gpiochip_get_data(chip);
+
+ return !!(priv->gpio_output_flag & BIT(offset));
+}
+
+static int rt5133_get_gpioen_mask(unsigned int offset, unsigned int *mask)
+{
+ if (offset >= RT5133_GPIO_NR)
+ return -EINVAL;
+
+ *mask = (BIT(7 - offset) | BIT(3 - offset));
+
+ return 0;
+}
+
+static int rt5133_gpio_set(struct gpio_chip *chip, unsigned int offset, int set_val)
+{
+ struct rt5133_priv *priv = gpiochip_get_data(chip);
+ unsigned int mask = 0, val = 0, next_flag = priv->gpio_output_flag;
+ int ret = 0;
+
+ ret = rt5133_get_gpioen_mask(offset, &mask);
+ if (ret) {
+ dev_err(priv->dev, "%s get gpion en mask failed, offset(%d)\n", __func__, offset);
+ return ret;
+ }
+
+ val = set_val ? mask : 0;
+
+ if (set_val)
+ next_flag |= BIT(offset);
+ else
+ next_flag &= ~BIT(offset);
+
+ ret = regmap_update_bits(priv->regmap, RT5133_REG_GPIO_CTRL, mask, val);
+ if (ret) {
+ dev_err(priv->dev, "Failed to set gpio [%d] val %d\n", offset,
+ set_val);
+ return ret;
+ }
+
+ priv->gpio_output_flag = next_flag;
+ return 0;
+}
+
+static irqreturn_t rt5133_intr_handler(int irq_number, void *data)
+{
+ struct rt5133_priv *priv = data;
+ u32 intr_evts = 0, handle_evts;
+ int i, ret;
+
+ ret = regmap_bulk_read(priv->regmap, RT5133_REG_BASE_EVT, &intr_evts,
+ RT5133_INTR_BYTE_NR);
+ if (ret) {
+ dev_err(priv->dev, "%s, read event failed\n", __func__);
+ return IRQ_NONE;
+ }
+
+ handle_evts = intr_evts & RT5133_BASE_EVT_MASK;
+ /*
+ * VREF_EVT is a special case, if base off
+ * this event will also be trigger. Skip it
+ */
+ if (handle_evts & ~RT5133_VREF_EVT_MASK)
+ dev_dbg(priv->dev, "base event occurred [0x%02x]\n",
+ handle_evts);
+
+ handle_evts = (intr_evts & RT5133_LDO_OC_EVT_MASK) >>
+ RT5133_LDO_OC_EVT_SHIFT;
+
+ for (i = RT5133_REGULATOR_LDO1; i < RT5133_REGULATOR_MAX && handle_evts; i++) {
+ if (!(handle_evts & BIT(i - 1)))
+ continue;
+ regulator_notifier_call_chain(priv->rdev[i],
+ REGULATOR_EVENT_OVER_CURRENT,
+ &i);
+ }
+
+ handle_evts = (intr_evts & RT5133_LDO_PGB_EVT_MASK) >>
+ RT5133_LDO_PGB_EVT_SHIFT;
+ for (i = RT5133_REGULATOR_LDO1; i < RT5133_REGULATOR_MAX && handle_evts; i++) {
+ if (!(handle_evts & BIT(i - 1)))
+ continue;
+ regulator_notifier_call_chain(priv->rdev[i],
+ REGULATOR_EVENT_FAIL, &i);
+ }
+
+ ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_EVT, &intr_evts,
+ RT5133_INTR_BYTE_NR);
+ if (ret)
+ dev_err(priv->dev, "%s, clear event failed\n", __func__);
+
+ return IRQ_HANDLED;
+}
+
+static int rt5133_enable_interrupts(int irq_no, struct rt5133_priv *priv)
+{
+ u32 mask = RT5133_INTR_CLR_MASK;
+ int ret;
+
+ /* Force to write clear all events */
+ ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_EVT, &mask,
+ RT5133_INTR_BYTE_NR);
+ if (ret) {
+ dev_err(priv->dev, "Failed to clear all interrupts\n");
+ return ret;
+ }
+
+ /* Unmask all interrupts */
+ mask = 0;
+ ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_MASK, &mask,
+ RT5133_INTR_BYTE_NR);
+ if (ret) {
+ dev_err(priv->dev, "Failed to unmask all interrupts\n");
+ return ret;
+ }
+
+ return devm_request_threaded_irq(priv->dev, irq_no, NULL,
+ rt5133_intr_handler, IRQF_ONESHOT,
+ dev_name(priv->dev), priv);
+}
+
+static int rt5133_regmap_hw_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf,
+ size_t val_size)
+{
+ struct rt5133_priv *priv = context;
+ struct i2c_client *client = to_i2c_client(priv->dev);
+ u8 reg = *(u8 *)reg_buf, crc;
+ u8 *buf;
+ int buf_len = RT5133_PREDATA_LEN + val_size + RT5133_I2C_CRC_LEN;
+ int read_len, ret;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ buf[0] = I2C_ADDR_XLATE_8BIT(client->addr, I2C_SMBUS_READ);
+ buf[1] = reg;
+
+ read_len = val_size + RT5133_I2C_CRC_LEN;
+ ret = i2c_smbus_read_i2c_block_data(client, reg, read_len,
+ buf + RT5133_PREDATA_LEN);
+
+ if (ret < 0)
+ goto out_read_err;
+
+ if (ret != read_len) {
+ ret = -EIO;
+ goto out_read_err;
+ }
+
+ crc = crc8(priv->crc8_tbls, buf, RT5133_PREDATA_LEN + val_size, 0);
+ if (crc != buf[RT5133_PREDATA_LEN + val_size]) {
+ ret = -EIO;
+ goto out_read_err;
+ }
+
+ memcpy(val_buf, buf + RT5133_PREDATA_LEN, val_size);
+ dev_dbg(priv->dev, "%s, reg = 0x%02x, data = 0x%02x\n", __func__, reg, *(u8 *)val_buf);
+
+out_read_err:
+ kfree(buf);
+ return (ret < 0) ? ret : 0;
+}
+
+static int rt5133_regmap_hw_write(void *context, const void *data, size_t count)
+{
+ struct rt5133_priv *priv = context;
+ struct i2c_client *client = to_i2c_client(priv->dev);
+ u8 reg = *(u8 *)data, crc;
+ u8 *buf;
+ int buf_len = RT5133_I2C_ADDR_LEN + count + RT5133_I2C_CRC_LEN +
+ RT5133_I2C_DUMMY_LEN;
+ int write_len, ret;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ buf[0] = I2C_ADDR_XLATE_8BIT(client->addr, I2C_SMBUS_WRITE);
+ buf[1] = reg;
+ memcpy(buf + RT5133_PREDATA_LEN, data + RT5133_REG_ADDR_LEN,
+ count - RT5133_REG_ADDR_LEN);
+
+ crc = crc8(priv->crc8_tbls, buf, RT5133_I2C_ADDR_LEN + count, 0);
+ buf[RT5133_I2C_ADDR_LEN + count] = crc;
+
+ write_len = count - RT5133_REG_ADDR_LEN + RT5133_I2C_CRC_LEN +
+ RT5133_I2C_DUMMY_LEN;
+ ret = i2c_smbus_write_i2c_block_data(client, reg, write_len,
+ buf + RT5133_PREDATA_LEN);
+
+ dev_dbg(priv->dev, "%s, reg = 0x%02x, data = 0x%02x\n", __func__, reg,
+ *(u8 *)(buf + RT5133_PREDATA_LEN));
+ kfree(buf);
+ return ret;
+}
+
+static const struct regmap_bus rt5133_regmap_bus = {
+ .read = rt5133_regmap_hw_read,
+ .write = rt5133_regmap_hw_write,
+ /* Due to crc, the block read/write length has the limit */
+ .max_raw_read = RT5133_MAX_I2C_BLOCK_SIZE,
+ .max_raw_write = RT5133_MAX_I2C_BLOCK_SIZE,
+};
+
+static bool rt5133_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT5133_REG_CHIP_INFO:
+ case RT5133_REG_BASE_EVT...RT5133_REG_LDO_PGB_STAT:
+ case RT5133_REG_LDO_ON...RT5133_REG_LDO_OFF:
+ case RT5133_REG_LDO1_CTRL1:
+ case RT5133_REG_LDO2_CTRL1:
+ case RT5133_REG_LDO3_CTRL1:
+ case RT5133_REG_LDO4_CTRL1:
+ case RT5133_REG_LDO5_CTRL1:
+ case RT5133_REG_LDO6_CTRL1:
+ case RT5133_REG_LDO7_CTRL1:
+ case RT5133_REG_LDO8_CTRL1:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config rt5133_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RT5133_REG_LDO8_CTRL4,
+ .cache_type = REGCACHE_FLAT,
+ .num_reg_defaults_raw = RT5133_REG_LDO8_CTRL4 + 1,
+ .volatile_reg = rt5133_is_volatile_reg,
+};
+
+static int rt5133_chip_reset(struct rt5133_priv *priv)
+{
+ int ret;
+
+ ret = regmap_write(priv->regmap, RT5133_REG_RST_CTRL,
+ RT5133_RESET_CODE);
+ if (ret)
+ return ret;
+
+ /* Wait for register reset to take effect */
+ udelay(2);
+
+ return 0;
+}
+
+static int rt5133_validate_vendor_info(struct rt5133_priv *priv)
+{
+ unsigned int val = 0;
+ int i, ret;
+
+ ret = regmap_read(priv->regmap, RT5133_REG_CHIP_INFO, &val);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++) {
+ if ((val & RT5133_VENDOR_ID_MASK) ==
+ regulator_data[i].vendor_id){
+ priv->cdata = &regulator_data[i];
+ break;
+ }
+ }
+ if (!priv->cdata) {
+ dev_err(priv->dev, "Failed to find regulator match version\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int rt5133_parse_dt(struct rt5133_priv *priv)
+{
+ unsigned int val = 0;
+ int ret = 0;
+
+ if (!device_property_read_bool(priv->dev, "richtek,oc-shutdown-all"))
+ val = 0;
+ else
+ val = 1 << RT5133_OCSHDN_ALL_SHIFT;
+ ret = regmap_update_bits(priv->regmap, RT5133_REG_LDO_SHDN,
+ RT5133_OCSHDN_ALL_MASK, val);
+ if (ret)
+ return ret;
+
+ if (!device_property_read_bool(priv->dev, "richtek,pgb-shutdown-all"))
+ val = 0;
+ else
+ val = 1 << RT5133_PGBSHDN_ALL_SHIFT;
+ return regmap_update_bits(priv->regmap, RT5133_REG_LDO_SHDN,
+ RT5133_PGBSHDN_ALL_MASK, val);
+}
+
+static int rt5133_probe(struct i2c_client *i2c)
+{
+ struct rt5133_priv *priv;
+ struct regulator_config config = {0};
+ int i, ret;
+
+ priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &i2c->dev;
+ crc8_populate_msb(priv->crc8_tbls, RT5133_CRC8_POLYNOMIAL);
+
+ priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->enable_gpio))
+ dev_err(&i2c->dev, "Failed to request HWEN gpio, check if default en=high\n");
+
+ priv->regmap = devm_regmap_init(&i2c->dev, &rt5133_regmap_bus, priv,
+ &rt5133_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ dev_err(&i2c->dev, "Failed to register regmap\n");
+ return PTR_ERR(priv->regmap);
+ }
+
+ ret = rt5133_validate_vendor_info(priv);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to check vendor info [%d]\n", ret);
+ return ret;
+ }
+
+ ret = rt5133_chip_reset(priv);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to execute sw reset\n");
+ return ret;
+ }
+
+ config.dev = &i2c->dev;
+ config.driver_data = priv;
+ config.regmap = priv->regmap;
+
+ for (i = 0; i < RT5133_REGULATOR_MAX; i++) {
+ priv->rdev[i] = devm_regulator_register(&i2c->dev,
+ priv->cdata->regulators + i,
+ &config);
+ if (IS_ERR(priv->rdev[i])) {
+ dev_err(&i2c->dev,
+ "Failed to register [%d] regulator\n", i);
+ return PTR_ERR(priv->rdev[i]);
+ }
+ }
+
+ ret = rt5133_parse_dt(priv);
+ if (ret) {
+ dev_err(&i2c->dev, "%s, Failed to parse dt\n", __func__);
+ return ret;
+ }
+
+ priv->gc.label = dev_name(&i2c->dev);
+ priv->gc.parent = &i2c->dev;
+ priv->gc.base = -1;
+ priv->gc.ngpio = RT5133_GPIO_NR;
+ priv->gc.set = rt5133_gpio_set;
+ priv->gc.get = rt5133_gpio_get;
+ priv->gc.direction_output = rt5133_gpio_direction_output;
+ priv->gc.can_sleep = true;
+
+ ret = devm_gpiochip_add_data(&i2c->dev, &priv->gc, priv);
+ if (ret)
+ return ret;
+
+ ret = rt5133_enable_interrupts(i2c->irq, priv);
+ if (ret) {
+ dev_err(&i2c->dev, "enable interrupt failed\n");
+ return ret;
+ }
+
+ i2c_set_clientdata(i2c, priv);
+
+ return ret;
+}
+
+static const struct of_device_id __maybe_unused rt5133_of_match_table[] = {
+ { .compatible = "richtek,rt5133", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rt5133_of_match_table);
+
+static struct i2c_driver rt5133_driver = {
+ .driver = {
+ .name = "rt5133",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = rt5133_of_match_table,
+ },
+ .probe = rt5133_probe,
+};
+module_i2c_driver(rt5133_driver);
+
+MODULE_DESCRIPTION("RT5133 Regulator Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/rt5739.c b/drivers/regulator/rt5739.c
index 91412c905ce6..5fcddd7c2da7 100644
--- a/drivers/regulator/rt5739.c
+++ b/drivers/regulator/rt5739.c
@@ -24,6 +24,8 @@
#define RT5739_REG_NSEL1 0x01
#define RT5739_REG_CNTL1 0x02
#define RT5739_REG_ID1 0x03
+#define RT5739_REG_ID2 0x04
+#define RT5739_REG_MON 0x05
#define RT5739_REG_CNTL2 0x06
#define RT5739_REG_CNTL4 0x08
@@ -236,11 +238,18 @@ static void rt5739_init_regulator_desc(struct regulator_desc *desc,
}
}
+static bool rt5739_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg == RT5739_REG_MON;
+}
+
static const struct regmap_config rt5739_regmap_config = {
.name = "rt5739",
.reg_bits = 8,
.val_bits = 8,
.max_register = RT5739_REG_CNTL4,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = rt5739_volatile_reg,
};
static int rt5739_probe(struct i2c_client *i2c)
diff --git a/drivers/regulator/rt6160-regulator.c b/drivers/regulator/rt6160-regulator.c
index e2a0eee95c61..548ffdf537d3 100644
--- a/drivers/regulator/rt6160-regulator.c
+++ b/drivers/regulator/rt6160-regulator.c
@@ -31,8 +31,11 @@
#define RT6160_PGSTAT_MASK BIT(0)
#define RT6160_VENDOR_ID 0xA0
+#define RT6166_VENDOR_ID 0xB0
#define RT6160_VOUT_MINUV 2025000
#define RT6160_VOUT_MAXUV 5200000
+#define RT6166_VOUT_MINUV 1800000
+#define RT6166_VOUD_MAXUV 4950000
#define RT6160_VOUT_STPUV 25000
#define RT6160_N_VOUTS ((RT6160_VOUT_MAXUV - RT6160_VOUT_MINUV) / RT6160_VOUT_STPUV + 1)
@@ -43,6 +46,7 @@ struct rt6160_priv {
struct gpio_desc *enable_gpio;
struct regmap *regmap;
bool enable_state;
+ uint8_t devid;
};
static const unsigned int rt6160_ramp_tables[] = {
@@ -260,15 +264,26 @@ static int rt6160_probe(struct i2c_client *i2c)
if (ret)
return ret;
- if ((devid & RT6160_VID_MASK) != RT6160_VENDOR_ID) {
+ devid = devid & RT6160_VID_MASK;
+
+ switch (devid) {
+ case RT6166_VENDOR_ID:
+ case RT6160_VENDOR_ID:
+ break;
+ default:
dev_err(&i2c->dev, "VID not correct [0x%02x]\n", devid);
return -ENODEV;
}
+ priv->devid = devid;
+
priv->desc.name = "rt6160-buckboost";
priv->desc.type = REGULATOR_VOLTAGE;
priv->desc.owner = THIS_MODULE;
- priv->desc.min_uV = RT6160_VOUT_MINUV;
+ if (priv->devid == RT6166_VENDOR_ID)
+ priv->desc.min_uV = RT6166_VOUT_MINUV;
+ else
+ priv->desc.min_uV = RT6160_VOUT_MINUV;
priv->desc.uV_step = RT6160_VOUT_STPUV;
if (vsel_active_low)
priv->desc.vsel_reg = RT6160_REG_VSELL;
diff --git a/drivers/regulator/rtq2208-regulator.c b/drivers/regulator/rtq2208-regulator.c
index 5925fa7a9a06..f669a562f036 100644
--- a/drivers/regulator/rtq2208-regulator.c
+++ b/drivers/regulator/rtq2208-regulator.c
@@ -27,6 +27,11 @@
#define RTQ2208_REG_LDO1_CFG 0xB1
#define RTQ2208_REG_LDO2_CFG 0xC1
#define RTQ2208_REG_LDO_DVS_CTRL 0xD0
+#define RTQ2208_REG_HIDDEN_BUCKPH 0x55
+#define RTQ2208_REG_HIDDEN_LDOCFG0 0x8F
+#define RTQ2208_REG_HIDDEN_LDOCFG1 0x96
+#define RTQ2208_REG_HIDDEN0 0xFE
+#define RTQ2208_REG_HIDDEN1 0xFF
/* Mask */
#define RTQ2208_BUCK_NR_MTP_SEL_MASK GENMASK(7, 0)
@@ -45,6 +50,11 @@
#define RTQ2208_LDO1_VOSEL_SD_MASK BIT(5)
#define RTQ2208_LDO2_DISCHG_EN_MASK BIT(6)
#define RTQ2208_LDO2_VOSEL_SD_MASK BIT(7)
+#define RTQ2208_MASK_BUCKPH_GROUP1 GENMASK(6, 4)
+#define RTQ2208_MASK_BUCKPH_GROUP2 GENMASK(2, 0)
+#define RTQ2208_MASK_LDO2_OPT0 BIT(7)
+#define RTQ2208_MASK_LDO2_OPT1 BIT(7)
+#define RTQ2208_MASK_LDO1_FIXED BIT(6)
/* Size */
#define RTQ2208_VOUT_MAXNUM 256
@@ -245,11 +255,6 @@ static const unsigned int rtq2208_ldo_volt_table[] = {
3300000,
};
-static struct of_regulator_match rtq2208_ldo_match[] = {
- {.name = "ldo2", },
- {.name = "ldo1", },
-};
-
static unsigned int rtq2208_of_map_mode(unsigned int mode)
{
switch (mode) {
@@ -344,59 +349,6 @@ static irqreturn_t rtq2208_irq_handler(int irqno, void *devid)
return IRQ_HANDLED;
}
-static int rtq2208_of_get_ldo_dvs_ability(struct device *dev)
-{
- struct device_node *np;
- struct of_regulator_match *match;
- struct regulator_desc *desc;
- struct regulator_init_data *init_data;
- u32 fixed_uV;
- int ret, i;
-
- if (!dev->of_node)
- return -ENODEV;
-
- np = of_get_child_by_name(dev->of_node, "regulators");
- if (!np)
- np = dev->of_node;
-
- ret = of_regulator_match(dev, np, rtq2208_ldo_match, ARRAY_SIZE(rtq2208_ldo_match));
-
- of_node_put(np);
-
- if (ret < 0)
- return ret;
-
- for (i = 0; i < ARRAY_SIZE(rtq2208_ldo_match); i++) {
- match = rtq2208_ldo_match + i;
- init_data = match->init_data;
- desc = (struct regulator_desc *)match->desc;
-
- if (!init_data || !desc)
- continue;
-
- /* specify working fixed voltage if the propery exists */
- ret = of_property_read_u32(match->of_node, "richtek,fixed-microvolt", &fixed_uV);
-
- if (!ret) {
- if (fixed_uV != init_data->constraints.min_uV ||
- fixed_uV != init_data->constraints.max_uV)
- return -EINVAL;
- desc->n_voltages = 1;
- desc->fixed_uV = fixed_uV;
- desc->fixed_uV = init_data->constraints.min_uV;
- desc->ops = &rtq2208_regulator_ldo_fix_ops;
- } else {
- desc->n_voltages = ARRAY_SIZE(rtq2208_ldo_volt_table);
- desc->volt_table = rtq2208_ldo_volt_table;
- desc->ops = &rtq2208_regulator_ldo_adj_ops;
- }
- }
-
- return 0;
-}
-
-
#define BUCK_INFO(_name, _id) \
{ \
.name = _name, \
@@ -424,9 +376,11 @@ static const struct linear_range rtq2208_vout_range[] = {
REGULATOR_LINEAR_RANGE(1310000, 181, 255, 10000),
};
-static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, int mtp_sel, int idx)
+static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, int mtp_sel, int idx,
+ unsigned int ldo1_fixed, unsigned int ldo2_fixed)
{
struct regulator_desc *desc;
+ unsigned int fixed_uV;
static const struct {
char *name;
int base;
@@ -462,7 +416,8 @@ static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, in
rdesc->mode_mask = RTQ2208_BUCK_NRMODE_MASK;
- if (idx >= RTQ2208_BUCK_B && idx <= RTQ2208_BUCK_E) {
+ switch (idx) {
+ case RTQ2208_BUCK_B ... RTQ2208_BUCK_E:
/* init buck desc */
desc->ops = &rtq2208_regulator_buck_ops;
desc->vsel_reg = curr_info->base + VSEL_SHIFT(mtp_sel);
@@ -480,7 +435,19 @@ static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, in
rdesc->suspend_config_reg = BUCK_RG_SHIFT(curr_info->base, 4);
rdesc->suspend_enable_mask = RTQ2208_BUCK_EN_STR_MASK;
rdesc->suspend_mode_mask = RTQ2208_BUCK_STRMODE_MASK;
- } else {
+ break;
+ default:
+ fixed_uV = idx == RTQ2208_LDO2 ? ldo2_fixed : ldo1_fixed;
+ if (fixed_uV) {
+ desc->n_voltages = 1;
+ desc->fixed_uV = fixed_uV;
+ desc->ops = &rtq2208_regulator_ldo_fix_ops;
+ } else {
+ desc->n_voltages = ARRAY_SIZE(rtq2208_ldo_volt_table);
+ desc->volt_table = rtq2208_ldo_volt_table;
+ desc->ops = &rtq2208_regulator_ldo_adj_ops;
+ }
+
/* init ldo desc */
desc->active_discharge_reg = RTQ2208_REG_LDO_DVS_CTRL;
desc->active_discharge_on = curr_info->dis_on;
@@ -490,13 +457,15 @@ static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, in
rdesc->suspend_config_reg = curr_info->base;
rdesc->suspend_enable_mask = RTQ2208_LDO_EN_STR_MASK;
+ break;
}
}
static int rtq2208_parse_regulator_dt_data(int n_regulator, const unsigned int *regulator_idx_table,
- struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX], struct device *dev)
+ struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX], struct device *dev,
+ unsigned int ldo1_fixed, unsigned int ldo2_fixed)
{
- int mtp_sel, i, idx, ret;
+ int mtp_sel, i, idx;
/* get mtp_sel0 or mtp_sel1 */
mtp_sel = device_property_read_bool(dev, "richtek,mtp-sel-high");
@@ -508,43 +477,101 @@ static int rtq2208_parse_regulator_dt_data(int n_regulator, const unsigned int *
if (!rdesc[i])
return -ENOMEM;
- rtq2208_init_regulator_desc(rdesc[i], mtp_sel, idx);
-
- /* init ldo dvs ability */
- if (idx >= RTQ2208_LDO2)
- rtq2208_ldo_match[idx - RTQ2208_LDO2].desc = &rdesc[i]->desc;
+ rtq2208_init_regulator_desc(rdesc[i], mtp_sel, idx, ldo1_fixed, ldo2_fixed);
}
- /* init ldo fixed_uV */
- ret = rtq2208_of_get_ldo_dvs_ability(dev);
- if (ret)
- return dev_err_probe(dev, ret, "Failed to get ldo fixed_uV\n");
-
return 0;
}
-/** different slave address corresponds different used bucks
- * slave address 0x10: BUCK[BCA FGE]
- * slave address 0x20: BUCK[BC FGHE]
- * slave address 0x40: BUCK[C G]
- */
-static int rtq2208_regulator_check(int slave_addr, int *num,
- int *regulator_idx_table, unsigned int *buck_masks)
+static int rtq2208_regulator_check(struct device *dev, int *num, int *regulator_idx_table,
+ unsigned int *buck_masks, unsigned int *ldo1_fixed_uV,
+ unsigned int *ldo2_fixed_uV)
{
- static bool rtq2208_used_table[3][RTQ2208_LDO_MAX] = {
- /* BUCK[BCA FGE], LDO[12] */
- {1, 1, 0, 1, 1, 1, 0, 1, 1, 1},
- /* BUCK[BC FGHE], LDO[12]*/
- {1, 1, 0, 0, 1, 1, 1, 1, 1, 1},
- /* BUCK[C G], LDO[12] */
- {0, 1, 0, 0, 0, 1, 0, 0, 1, 1},
- };
- int i, idx = ffs(slave_addr >> 4) - 1;
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+ bool rtq2208_used_table[RTQ2208_LDO_MAX] = {0};
+ u8 entry_key[] = { 0x69, 0x01 };
+ unsigned int buck_phase, ldo_cfg0, ldo_cfg1;
+ int i, ret;
u8 mask;
+ ret = regmap_raw_write(regmap, RTQ2208_REG_HIDDEN0, entry_key, ARRAY_SIZE(entry_key));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enter hidden page\n");
+
+ ret = regmap_read(regmap, RTQ2208_REG_HIDDEN_BUCKPH, &buck_phase);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read buck phase configuration\n");
+
+ ret = regmap_read(regmap, RTQ2208_REG_HIDDEN_LDOCFG0, &ldo_cfg0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read ldo cfg0\n");
+
+ ret = regmap_read(regmap, RTQ2208_REG_HIDDEN_LDOCFG1, &ldo_cfg1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read ldo cfg1\n");
+
+ ret = regmap_write(regmap, RTQ2208_REG_HIDDEN1, 0x00);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to exit hidden page\n");
+
+ dev_info(dev, "BUCK Phase 0x%x\n", buck_phase);
+ /*
+ * Use buck phase configuration to assign used table mask
+ * GROUP1 GROUP2
+ * 0 -> 2P + 2P BC FG
+ * 1 -> 2P + 1P + 1P BCA FGE
+ * 2 -> 1P + 1P + 1P + 1P BCDA FGHE
+ * 3 -> 3P + 1P BC FG
+ * others -> 4P C G
+ */
+ switch (FIELD_GET(RTQ2208_MASK_BUCKPH_GROUP1, buck_phase)) {
+ case 2:
+ rtq2208_used_table[RTQ2208_BUCK_D] = true;
+ fallthrough;
+ case 1:
+ rtq2208_used_table[RTQ2208_BUCK_A] = true;
+ fallthrough;
+ case 0:
+ case 3:
+ rtq2208_used_table[RTQ2208_BUCK_B] = true;
+ fallthrough;
+ default:
+ rtq2208_used_table[RTQ2208_BUCK_C] = true;
+ break;
+ }
+
+ switch (FIELD_GET(RTQ2208_MASK_BUCKPH_GROUP2, buck_phase)) {
+ case 2:
+ rtq2208_used_table[RTQ2208_BUCK_H] = true;
+ fallthrough;
+ case 1:
+ rtq2208_used_table[RTQ2208_BUCK_E] = true;
+ fallthrough;
+ case 0:
+ case 3:
+ rtq2208_used_table[RTQ2208_BUCK_F] = true;
+ fallthrough;
+ default:
+ rtq2208_used_table[RTQ2208_BUCK_G] = true;
+ break;
+ }
+
+ *ldo1_fixed_uV = FIELD_GET(RTQ2208_MASK_LDO1_FIXED, ldo_cfg1) ? 1200000 : 0;
+
+ if (!FIELD_GET(RTQ2208_MASK_LDO2_OPT0, ldo_cfg0) &&
+ !FIELD_GET(RTQ2208_MASK_LDO2_OPT1, ldo_cfg1))
+ *ldo2_fixed_uV = 0;
+ else if (FIELD_GET(RTQ2208_MASK_LDO2_OPT1, ldo_cfg1))
+ *ldo2_fixed_uV = 900000;
+ else
+ *ldo2_fixed_uV = 1200000;
+
+ /* By default, LDO1 & LDO2 are always used */
+ rtq2208_used_table[RTQ2208_LDO1] = rtq2208_used_table[RTQ2208_LDO2] = true;
+
for (i = 0; i < RTQ2208_LDO_MAX; i++) {
- if (!rtq2208_used_table[idx][i])
+ if (!rtq2208_used_table[i])
continue;
regulator_idx_table[(*num)++] = i;
@@ -559,7 +586,7 @@ static int rtq2208_regulator_check(int slave_addr, int *num,
static const struct regmap_config rtq2208_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = 0xEF,
+ .max_register = 0xFF,
};
static int rtq2208_probe(struct i2c_client *i2c)
@@ -573,6 +600,7 @@ static int rtq2208_probe(struct i2c_client *i2c)
int i, ret = 0, idx, n_regulator = 0;
unsigned int regulator_idx_table[RTQ2208_LDO_MAX],
buck_masks[RTQ2208_BUCK_NUM_IRQ_REGS] = {0x33, 0x33, 0x33, 0x33, 0x33};
+ unsigned int ldo1_fixed_uV, ldo2_fixed_uV;
rdev_map = devm_kzalloc(dev, sizeof(struct rtq2208_rdev_map), GFP_KERNEL);
if (!rdev_map)
@@ -583,7 +611,8 @@ static int rtq2208_probe(struct i2c_client *i2c)
return dev_err_probe(dev, PTR_ERR(regmap), "Failed to allocate regmap\n");
/* get needed regulator */
- ret = rtq2208_regulator_check(i2c->addr, &n_regulator, regulator_idx_table, buck_masks);
+ ret = rtq2208_regulator_check(dev, &n_regulator, regulator_idx_table, buck_masks,
+ &ldo1_fixed_uV, &ldo2_fixed_uV);
if (ret)
return dev_err_probe(dev, ret, "Failed to check used regulators\n");
@@ -593,7 +622,8 @@ static int rtq2208_probe(struct i2c_client *i2c)
cfg.dev = dev;
/* init regulator desc */
- ret = rtq2208_parse_regulator_dt_data(n_regulator, regulator_idx_table, rdesc, dev);
+ ret = rtq2208_parse_regulator_dt_data(n_regulator, regulator_idx_table, rdesc, dev,
+ ldo1_fixed_uV, ldo2_fixed_uV);
if (ret)
return ret;
diff --git a/drivers/regulator/rtq6752-regulator.c b/drivers/regulator/rtq6752-regulator.c
index d35d844eff3b..618904ede72c 100644
--- a/drivers/regulator/rtq6752-regulator.c
+++ b/drivers/regulator/rtq6752-regulator.c
@@ -105,7 +105,7 @@ static int rtq6752_get_error_flags(struct regulator_dev *rdev,
unsigned int *flags)
{
unsigned int val, events = 0;
- const unsigned int fault_mask[] = {
+ static const unsigned int fault_mask[] = {
RTQ6752_PAVDDF_MASK, RTQ6752_NAVDDF_MASK };
int rid = rdev_get_id(rdev), ret;
diff --git a/drivers/regulator/s2dos05-regulator.c b/drivers/regulator/s2dos05-regulator.c
new file mode 100644
index 000000000000..1463585c4565
--- /dev/null
+++ b/drivers/regulator/s2dos05-regulator.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// s2dos05.c - Regulator driver for the Samsung s2dos05
+//
+// Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com>
+
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/regulator/s2dos05.h>
+#include <linux/i2c.h>
+
+struct s2dos05_data {
+ struct regmap *regmap;
+ struct device *dev;
+};
+
+#define _BUCK(macro) S2DOS05_BUCK##macro
+#define _buck_ops(num) s2dos05_ops##num
+#define _LDO(macro) S2DOS05_LDO##macro
+#define _REG(ctrl) S2DOS05_REG##ctrl
+#define _ldo_ops(num) s2dos05_ops##num
+#define _MASK(macro) S2DOS05_ENABLE_MASK##macro
+#define _TIME(macro) S2DOS05_ENABLE_TIME##macro
+
+#define BUCK_DESC(_name, _id, _ops, m, s, v, e, em, t, a) { \
+ .name = _name, \
+ .id = _id, \
+ .ops = _ops, \
+ .of_match = of_match_ptr(_name), \
+ .of_match_full_name = true, \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = m, \
+ .uV_step = s, \
+ .n_voltages = S2DOS05_BUCK_N_VOLTAGES, \
+ .vsel_reg = v, \
+ .vsel_mask = S2DOS05_BUCK_VSEL_MASK, \
+ .enable_reg = e, \
+ .enable_mask = em, \
+ .enable_time = t, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = S2DOS05_BUCK_FD_MASK, \
+ .active_discharge_reg = a, \
+ .active_discharge_mask = S2DOS05_BUCK_FD_MASK \
+}
+
+#define LDO_DESC(_name, _id, _ops, m, s, v, e, em, t, a) { \
+ .name = _name, \
+ .id = _id, \
+ .ops = _ops, \
+ .of_match = of_match_ptr(_name), \
+ .of_match_full_name = true, \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = m, \
+ .uV_step = s, \
+ .n_voltages = S2DOS05_LDO_N_VOLTAGES, \
+ .vsel_reg = v, \
+ .vsel_mask = S2DOS05_LDO_VSEL_MASK, \
+ .enable_reg = e, \
+ .enable_mask = em, \
+ .enable_time = t, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = S2DOS05_LDO_FD_MASK, \
+ .active_discharge_reg = a, \
+ .active_discharge_mask = S2DOS05_LDO_FD_MASK \
+}
+
+static const struct regulator_ops s2dos05_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .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_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+};
+
+static const struct regulator_desc regulators[S2DOS05_REGULATOR_MAX] = {
+ // name, id, ops, min_uv, uV_step, vsel_reg, enable_reg
+ LDO_DESC("ldo1", _LDO(1), &_ldo_ops(), _LDO(_MIN1),
+ _LDO(_STEP1), _REG(_LDO1_CFG),
+ _REG(_EN), _MASK(_L1), _TIME(_LDO), _REG(_LDO1_CFG)),
+ LDO_DESC("ldo2", _LDO(2), &_ldo_ops(), _LDO(_MIN1),
+ _LDO(_STEP1), _REG(_LDO2_CFG),
+ _REG(_EN), _MASK(_L2), _TIME(_LDO), _REG(_LDO2_CFG)),
+ LDO_DESC("ldo3", _LDO(3), &_ldo_ops(), _LDO(_MIN2),
+ _LDO(_STEP1), _REG(_LDO3_CFG),
+ _REG(_EN), _MASK(_L3), _TIME(_LDO), _REG(_LDO3_CFG)),
+ LDO_DESC("ldo4", _LDO(4), &_ldo_ops(), _LDO(_MIN2),
+ _LDO(_STEP1), _REG(_LDO4_CFG),
+ _REG(_EN), _MASK(_L4), _TIME(_LDO), _REG(_LDO4_CFG)),
+ BUCK_DESC("buck", _BUCK(1), &_buck_ops(), _BUCK(_MIN1),
+ _BUCK(_STEP1), _REG(_BUCK_VOUT),
+ _REG(_EN), _MASK(_B1), _TIME(_BUCK), _REG(_BUCK_CFG)),
+};
+
+static int s2dos05_pmic_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct s2dos05_data *s2dos05;
+ struct regulator_config config = { };
+ unsigned int rdev_num = ARRAY_SIZE(regulators);
+
+ s2dos05 = devm_kzalloc(dev, sizeof(*s2dos05), GFP_KERNEL);
+ if (!s2dos05)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, s2dos05);
+
+ s2dos05->regmap = iodev->regmap_pmic;
+ s2dos05->dev = dev;
+ if (!dev->of_node)
+ dev->of_node = dev->parent->of_node;
+
+ config.dev = dev;
+ config.driver_data = s2dos05;
+
+ for (int i = 0; i < rdev_num; i++) {
+ struct regulator_dev *regulator;
+
+ regulator = devm_regulator_register(&pdev->dev,
+ &regulators[i], &config);
+ if (IS_ERR(regulator)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(regulator),
+ "regulator init failed for %d\n", i);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id s2dos05_pmic_id[] = {
+ { "s2dos05-regulator" },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, s2dos05_pmic_id);
+
+static struct platform_driver s2dos05_platform_driver = {
+ .driver = {
+ .name = "s2dos05",
+ },
+ .probe = s2dos05_pmic_probe,
+ .id_table = s2dos05_pmic_id,
+};
+module_platform_driver(s2dos05_platform_driver);
+
+MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>");
+MODULE_DESCRIPTION("Samsung S2DOS05 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 7dcf92af8f15..04ae9c6150bd 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -21,6 +21,7 @@
#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s2mps15.h>
#include <linux/mfd/samsung/s2mpu02.h>
+#include <linux/mfd/samsung/s2mpu05.h>
/* The highest number of possible regulators for supported devices. */
#define S2MPS_REGULATOR_MAX S2MPS13_REGULATOR_MAX
@@ -254,6 +255,9 @@ static int s2mps11_regulator_enable(struct regulator_dev *rdev)
else
val = rdev->desc->enable_mask;
break;
+ case S2MPU05:
+ val = rdev->desc->enable_mask;
+ break;
default:
return -EINVAL;
}
@@ -1118,6 +1122,86 @@ static const struct regulator_desc s2mpu02_regulators[] = {
regulator_desc_s2mpu02_buck7(7),
};
+#define regulator_desc_s2mpu05_ldo_reg(num, min, step, reg) { \
+ .name = "ldo"#num, \
+ .id = S2MPU05_LDO##num, \
+ .ops = &s2mpu02_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = min, \
+ .uV_step = step, \
+ .n_voltages = S2MPU05_LDO_N_VOLTAGES, \
+ .vsel_reg = reg, \
+ .vsel_mask = S2MPU05_LDO_VSEL_MASK, \
+ .enable_reg = reg, \
+ .enable_mask = S2MPU05_ENABLE_MASK, \
+ .enable_time = S2MPU05_ENABLE_TIME_LDO \
+}
+
+#define regulator_desc_s2mpu05_ldo(num, reg, min, step) \
+ regulator_desc_s2mpu05_ldo_reg(num, min, step, S2MPU05_REG_L##num##reg)
+
+#define regulator_desc_s2mpu05_ldo1(num, reg) \
+ regulator_desc_s2mpu05_ldo(num, reg, S2MPU05_LDO_MIN1, S2MPU05_LDO_STEP1)
+
+#define regulator_desc_s2mpu05_ldo2(num, reg) \
+ regulator_desc_s2mpu05_ldo(num, reg, S2MPU05_LDO_MIN1, S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_ldo3(num, reg) \
+ regulator_desc_s2mpu05_ldo(num, reg, S2MPU05_LDO_MIN2, S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_ldo4(num, reg) \
+ regulator_desc_s2mpu05_ldo(num, reg, S2MPU05_LDO_MIN3, S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_buck(num, which) { \
+ .name = "buck"#num, \
+ .id = S2MPU05_BUCK##num, \
+ .ops = &s2mpu02_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPU05_BUCK_MIN##which, \
+ .uV_step = S2MPU05_BUCK_STEP##which, \
+ .n_voltages = S2MPU05_BUCK_N_VOLTAGES, \
+ .vsel_reg = S2MPU05_REG_B##num##CTRL2, \
+ .vsel_mask = S2MPU05_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPU05_REG_B##num##CTRL1, \
+ .enable_mask = S2MPU05_ENABLE_MASK, \
+ .enable_time = S2MPU05_ENABLE_TIME_BUCK##num \
+}
+
+#define regulator_desc_s2mpu05_buck123(num) regulator_desc_s2mpu05_buck(num, 1)
+#define regulator_desc_s2mpu05_buck45(num) regulator_desc_s2mpu05_buck(num, 2)
+
+static const struct regulator_desc s2mpu05_regulators[] = {
+ regulator_desc_s2mpu05_ldo4(1, CTRL),
+ regulator_desc_s2mpu05_ldo3(2, CTRL),
+ regulator_desc_s2mpu05_ldo2(3, CTRL),
+ regulator_desc_s2mpu05_ldo1(4, CTRL),
+ regulator_desc_s2mpu05_ldo1(5, CTRL),
+ regulator_desc_s2mpu05_ldo1(6, CTRL),
+ regulator_desc_s2mpu05_ldo2(7, CTRL),
+ regulator_desc_s2mpu05_ldo3(8, CTRL),
+ regulator_desc_s2mpu05_ldo4(9, CTRL1),
+ regulator_desc_s2mpu05_ldo4(10, CTRL),
+ /* LDOs 11-24 are used for CP. They aren't documented. */
+ regulator_desc_s2mpu05_ldo2(25, CTRL),
+ regulator_desc_s2mpu05_ldo3(26, CTRL),
+ regulator_desc_s2mpu05_ldo2(27, CTRL),
+ regulator_desc_s2mpu05_ldo3(28, CTRL),
+ regulator_desc_s2mpu05_ldo3(29, CTRL),
+ regulator_desc_s2mpu05_ldo2(30, CTRL),
+ regulator_desc_s2mpu05_ldo3(31, CTRL),
+ regulator_desc_s2mpu05_ldo3(32, CTRL),
+ regulator_desc_s2mpu05_ldo3(33, CTRL),
+ regulator_desc_s2mpu05_ldo3(34, CTRL),
+ regulator_desc_s2mpu05_ldo3(35, CTRL),
+ regulator_desc_s2mpu05_buck123(1),
+ regulator_desc_s2mpu05_buck123(2),
+ regulator_desc_s2mpu05_buck123(3),
+ regulator_desc_s2mpu05_buck45(4),
+ regulator_desc_s2mpu05_buck45(5),
+};
+
static int s2mps11_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
@@ -1159,6 +1243,11 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
regulators = s2mpu02_regulators;
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mpu02_regulators));
break;
+ case S2MPU05:
+ rdev_num = ARRAY_SIZE(s2mpu05_regulators);
+ regulators = s2mpu05_regulators;
+ BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mpu05_regulators));
+ break;
default:
dev_err(&pdev->dev, "Invalid device type: %u\n",
s2mps11->dev_type);
@@ -1228,6 +1317,7 @@ static const struct platform_device_id s2mps11_pmic_id[] = {
{ "s2mps14-regulator", S2MPS14X},
{ "s2mps15-regulator", S2MPS15X},
{ "s2mpu02-regulator", S2MPU02},
+ { "s2mpu05-regulator", S2MPU05},
{ },
};
MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
@@ -1245,5 +1335,5 @@ module_platform_driver(s2mps11_pmic_driver);
/* Module information */
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
-MODULE_DESCRIPTION("Samsung S2MPS11/S2MPS14/S2MPS15/S2MPU02 Regulator Driver");
+MODULE_DESCRIPTION("Samsung S2MPS11/14/15/S2MPU02/05 Regulator Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index d25cd81e3f36..fe2631378ccd 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -5,7 +5,7 @@
#include <linux/cleanup.h>
#include <linux/err.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -35,8 +35,8 @@ struct s5m8767_info {
u8 buck2_vol[8];
u8 buck3_vol[8];
u8 buck4_vol[8];
- int buck_gpios[3];
- int buck_ds[3];
+ struct gpio_desc *buck_gpios[3];
+ struct gpio_desc *buck_ds[3];
int buck_gpioindex;
};
@@ -272,9 +272,9 @@ static inline int s5m8767_set_high(struct s5m8767_info *s5m8767)
{
int temp_index = s5m8767->buck_gpioindex;
- gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
- gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
- gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
+ gpiod_set_value(s5m8767->buck_gpios[0], !!(temp_index & BIT(2)));
+ gpiod_set_value(s5m8767->buck_gpios[1], !!(temp_index & BIT(1)));
+ gpiod_set_value(s5m8767->buck_gpios[2], !!(temp_index & BIT(0)));
return 0;
}
@@ -283,9 +283,9 @@ static inline int s5m8767_set_low(struct s5m8767_info *s5m8767)
{
int temp_index = s5m8767->buck_gpioindex;
- gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
- gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
- gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
+ gpiod_set_value(s5m8767->buck_gpios[2], !!(temp_index & BIT(0)));
+ gpiod_set_value(s5m8767->buck_gpios[1], !!(temp_index & BIT(1)));
+ gpiod_set_value(s5m8767->buck_gpios[0], !!(temp_index & BIT(2)));
return 0;
}
@@ -482,42 +482,6 @@ static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767,
#ifdef CONFIG_OF
-static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
- struct sec_platform_data *pdata,
- struct device_node *pmic_np)
-{
- int i, gpio;
-
- for (i = 0; i < 3; i++) {
- gpio = of_get_named_gpio(pmic_np,
- "s5m8767,pmic-buck-dvs-gpios", i);
- if (!gpio_is_valid(gpio)) {
- dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
- return -EINVAL;
- }
- pdata->buck_gpios[i] = gpio;
- }
- return 0;
-}
-
-static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
- struct sec_platform_data *pdata,
- struct device_node *pmic_np)
-{
- int i, gpio;
-
- for (i = 0; i < 3; i++) {
- gpio = of_get_named_gpio(pmic_np,
- "s5m8767,pmic-buck-ds-gpios", i);
- if (!gpio_is_valid(gpio)) {
- dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
- return -EINVAL;
- }
- pdata->buck_ds[i] = gpio;
- }
- return 0;
-}
-
static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
struct sec_platform_data *pdata)
{
@@ -525,7 +489,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
struct device_node *pmic_np, *reg_np;
struct sec_regulator_data *rdata;
struct sec_opmode_data *rmode;
- unsigned int i, dvs_voltage_nr = 8, ret;
+ unsigned int i, dvs_voltage_nr = 8;
pmic_np = iodev->dev->of_node;
if (!pmic_np) {
@@ -635,10 +599,6 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
pdata->buck4_gpiodvs) {
- ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
- if (ret)
- return -EINVAL;
-
if (of_property_read_u32(pmic_np,
"s5m8767,pmic-buck-default-dvs-idx",
&pdata->buck_default_idx)) {
@@ -652,10 +612,6 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
}
}
- ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np);
- if (ret)
- return -EINVAL;
-
pdata->buck2_ramp_enable = of_property_read_bool(pmic_np, "s5m8767,pmic-buck2-ramp-enable");
pdata->buck3_ramp_enable = of_property_read_bool(pmic_np, "s5m8767,pmic-buck3-ramp-enable");
pdata->buck4_ramp_enable = of_property_read_bool(pmic_np, "s5m8767,pmic-buck4-ramp-enable");
@@ -684,6 +640,8 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
struct regulator_config config = { };
struct s5m8767_info *s5m8767;
int i, ret, buck_init;
+ const char *gpiods_names[3] = { "S5M8767 DS2", "S5M8767 DS3", "S5M8767 DS4" };
+ const char *gpiodvs_names[3] = { "S5M8767 SET1", "S5M8767 SET2", "S5M8767 SET3" };
if (!pdata) {
dev_err(pdev->dev.parent, "Platform data not supplied\n");
@@ -731,12 +689,6 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs;
s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs;
s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs;
- s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
- s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
- s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
- s5m8767->buck_ds[0] = pdata->buck_ds[0];
- s5m8767->buck_ds[1] = pdata->buck_ds[1];
- s5m8767->buck_ds[2] = pdata->buck_ds[2];
s5m8767->ramp_delay = pdata->buck_ramp_delay;
s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
@@ -787,58 +739,36 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
pdata->buck4_gpiodvs) {
+ for (i = 0; i < 3; i++) {
+ enum gpiod_flags flags;
- if (!gpio_is_valid(pdata->buck_gpios[0]) ||
- !gpio_is_valid(pdata->buck_gpios[1]) ||
- !gpio_is_valid(pdata->buck_gpios[2])) {
- dev_err(&pdev->dev, "GPIO NOT VALID\n");
- return -EINVAL;
- }
-
- ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0],
- "S5M8767 SET1");
- if (ret)
- return ret;
-
- ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1],
- "S5M8767 SET2");
- if (ret)
- return ret;
-
- ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2],
- "S5M8767 SET3");
- if (ret)
- return ret;
+ if (s5m8767->buck_gpioindex & BIT(2 - i))
+ flags = GPIOD_OUT_HIGH;
+ else
+ flags = GPIOD_OUT_LOW;
+
+ s5m8767->buck_gpios[i] = devm_gpiod_get_index(iodev->dev,
+ "s5m8767,pmic-buck-dvs", i,
+ flags);
+ if (IS_ERR(s5m8767->buck_gpios[i])) {
+ return dev_err_probe(iodev->dev, PTR_ERR(s5m8767->buck_gpios[i]),
+ "invalid gpio[%d]\n", i);
+ }
- /* SET1 GPIO */
- gpio_direction_output(pdata->buck_gpios[0],
- (s5m8767->buck_gpioindex >> 2) & 0x1);
- /* SET2 GPIO */
- gpio_direction_output(pdata->buck_gpios[1],
- (s5m8767->buck_gpioindex >> 1) & 0x1);
- /* SET3 GPIO */
- gpio_direction_output(pdata->buck_gpios[2],
- (s5m8767->buck_gpioindex >> 0) & 0x1);
+ gpiod_set_consumer_name(s5m8767->buck_gpios[i], gpiodvs_names[i]);
+ }
}
- ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2");
- if (ret)
- return ret;
-
- ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3");
- if (ret)
- return ret;
-
- ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4");
- if (ret)
- return ret;
-
- /* DS2 GPIO */
- gpio_direction_output(pdata->buck_ds[0], 0x0);
- /* DS3 GPIO */
- gpio_direction_output(pdata->buck_ds[1], 0x0);
- /* DS4 GPIO */
- gpio_direction_output(pdata->buck_ds[2], 0x0);
+ for (i = 0; i < 3; i++) {
+ s5m8767->buck_ds[i] = devm_gpiod_get_index(iodev->dev,
+ "s5m8767,pmic-buck-ds", i,
+ GPIOD_OUT_LOW);
+ if (IS_ERR(s5m8767->buck_ds[i])) {
+ return dev_err_probe(iodev->dev, PTR_ERR(s5m8767->buck_ds[i]),
+ "can't get GPIO %d\n", i);
+ }
+ gpiod_set_consumer_name(s5m8767->buck_ds[i], gpiods_names[i]);
+ }
regmap_update_bits(s5m8767->iodev->regmap_pmic,
S5M8767_REG_BUCK2CTRL, 1 << 1,
diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
index 9df726f10ad1..6d609c42e479 100644
--- a/drivers/regulator/scmi-regulator.c
+++ b/drivers/regulator/scmi-regulator.c
@@ -257,7 +257,8 @@ static int process_scmi_regulator_of_node(struct scmi_device *sdev,
struct device_node *np,
struct scmi_regulator_info *rinfo)
{
- u32 dom, ret;
+ u32 dom;
+ int ret;
ret = of_property_read_u32(np, "reg", &dom);
if (ret)
diff --git a/drivers/regulator/spacemit-p1.c b/drivers/regulator/spacemit-p1.c
new file mode 100644
index 000000000000..d437e6738ea1
--- /dev/null
+++ b/drivers/regulator/spacemit-p1.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for regulators found in the SpacemiT P1 PMIC
+ *
+ * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved.
+ * Derived from code from SpacemiT.
+ * Copyright (c) 2023, SPACEMIT Co., Ltd
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/linear_range.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+
+#define MOD_NAME "spacemit-p1-regulator"
+
+enum p1_regulator_id {
+ P1_BUCK1,
+ P1_BUCK2,
+ P1_BUCK3,
+ P1_BUCK4,
+ P1_BUCK5,
+ P1_BUCK6,
+
+ P1_ALDO1,
+ P1_ALDO2,
+ P1_ALDO3,
+ P1_ALDO4,
+
+ P1_DLDO1,
+ P1_DLDO2,
+ P1_DLDO3,
+ P1_DLDO4,
+ P1_DLDO5,
+ P1_DLDO6,
+ P1_DLDO7,
+};
+
+static const struct regulator_ops p1_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+/* Selector value 255 can be used to disable the buck converter on sleep */
+static const struct linear_range p1_buck_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 170, 5000),
+ REGULATOR_LINEAR_RANGE(1375000, 171, 254, 25000),
+};
+
+/* Selector value 0 can be used for suspend */
+static const struct linear_range p1_ldo_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 11, 127, 25000),
+};
+
+/* These define the voltage selector field for buck and LDO regulators */
+#define BUCK_MASK GENMASK(7, 0)
+#define LDO_MASK GENMASK(6, 0)
+
+#define P1_ID(_TYPE, _n) P1_ ## _TYPE ## _n
+#define P1_ENABLE_REG(_off, _n) ((_off) + 3 * ((_n) - 1))
+
+#define P1_REG_DESC(_TYPE, _type, _n, _s, _off, _mask, _nv, _ranges) \
+ { \
+ .name = #_type #_n, \
+ .supply_name = _s, \
+ .of_match = of_match_ptr(#_type #_n), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .id = P1_ID(_TYPE, _n), \
+ .n_voltages = _nv, \
+ .ops = &p1_regulator_ops, \
+ .owner = THIS_MODULE, \
+ .linear_ranges = _ranges, \
+ .n_linear_ranges = ARRAY_SIZE(_ranges), \
+ .vsel_reg = P1_ENABLE_REG(_off, _n) + 1, \
+ .vsel_mask = _mask, \
+ .enable_reg = P1_ENABLE_REG(_off, _n), \
+ .enable_mask = BIT(0), \
+ }
+
+#define P1_BUCK_DESC(_n) \
+ P1_REG_DESC(BUCK, buck, _n, "vcc", 0x47, BUCK_MASK, 254, p1_buck_ranges)
+
+#define P1_ALDO_DESC(_n) \
+ P1_REG_DESC(ALDO, aldo, _n, "vcc", 0x5b, LDO_MASK, 117, p1_ldo_ranges)
+
+#define P1_DLDO_DESC(_n) \
+ P1_REG_DESC(DLDO, dldo, _n, "buck5", 0x67, LDO_MASK, 117, p1_ldo_ranges)
+
+static const struct regulator_desc p1_regulator_desc[] = {
+ P1_BUCK_DESC(1),
+ P1_BUCK_DESC(2),
+ P1_BUCK_DESC(3),
+ P1_BUCK_DESC(4),
+ P1_BUCK_DESC(5),
+ P1_BUCK_DESC(6),
+
+ P1_ALDO_DESC(1),
+ P1_ALDO_DESC(2),
+ P1_ALDO_DESC(3),
+ P1_ALDO_DESC(4),
+
+ P1_DLDO_DESC(1),
+ P1_DLDO_DESC(2),
+ P1_DLDO_DESC(3),
+ P1_DLDO_DESC(4),
+ P1_DLDO_DESC(5),
+ P1_DLDO_DESC(6),
+ P1_DLDO_DESC(7),
+};
+
+static int p1_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_config config = { };
+ struct device *dev = &pdev->dev;
+ u32 i;
+
+ /*
+ * The parent device (PMIC) owns the regmap. Since we don't
+ * provide one in the config structure, that one will be used.
+ */
+ config.dev = dev->parent;
+
+ for (i = 0; i < ARRAY_SIZE(p1_regulator_desc); i++) {
+ const struct regulator_desc *desc = &p1_regulator_desc[i];
+ struct regulator_dev *rdev;
+
+ rdev = devm_regulator_register(dev, desc, &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "error registering regulator %s\n",
+ desc->name);
+ }
+
+ return 0;
+}
+
+static struct platform_driver p1_regulator_driver = {
+ .probe = p1_regulator_probe,
+ .driver = {
+ .name = MOD_NAME,
+ },
+};
+
+module_platform_driver(p1_regulator_driver);
+
+MODULE_DESCRIPTION("SpacemiT P1 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MOD_NAME);
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
index a85ea94f0673..9e391206f09d 100644
--- a/drivers/regulator/stm32-vrefbuf.c
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -67,7 +67,6 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
}
- pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
return ret;
@@ -87,7 +86,6 @@ static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
val &= ~STM32_ENVR;
writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
- pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
return 0;
@@ -104,7 +102,6 @@ static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
ret = readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
- pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
return ret;
@@ -125,7 +122,6 @@ static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
- pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
return 0;
@@ -144,7 +140,6 @@ static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
ret = FIELD_GET(STM32_VRS, val);
- pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
return ret;
@@ -218,7 +213,6 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, rdev);
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c
index d1e7ba1fb3e1..551647bc1052 100644
--- a/drivers/regulator/sy7636a-regulator.c
+++ b/drivers/regulator/sy7636a-regulator.c
@@ -12,6 +12,7 @@
#include <linux/mfd/sy7636a.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
@@ -19,6 +20,8 @@
struct sy7636a_data {
struct regmap *regmap;
struct gpio_desc *pgood_gpio;
+ struct gpio_desc *en_gpio;
+ struct gpio_desc *vcom_en_gpio;
};
static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev)
@@ -83,9 +86,11 @@ static int sy7636a_regulator_probe(struct platform_device *pdev)
if (!regmap)
return -EPROBE_DEFER;
- gdp = devm_gpiod_get(pdev->dev.parent, "epd-pwr-good", GPIOD_IN);
+ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+
+ gdp = devm_gpiod_get(&pdev->dev, "epd-pwr-good", GPIOD_IN);
if (IS_ERR(gdp)) {
- dev_err(pdev->dev.parent, "Power good GPIO fault %ld\n", PTR_ERR(gdp));
+ dev_err(&pdev->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp));
return PTR_ERR(gdp);
}
@@ -96,6 +101,30 @@ static int sy7636a_regulator_probe(struct platform_device *pdev)
data->regmap = regmap;
data->pgood_gpio = gdp;
+ ret = devm_regulator_get_enable_optional(&pdev->dev, "vin");
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to get vin regulator\n");
+
+ data->en_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(data->en_gpio))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(data->en_gpio),
+ "failed to get en gpio\n");
+
+ /* Let VCOM just follow the default power on sequence */
+ data->vcom_en_gpio = devm_gpiod_get_optional(&pdev->dev,
+ "vcom-en", GPIOD_OUT_LOW);
+ if (IS_ERR(data->vcom_en_gpio))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(data->vcom_en_gpio),
+ "failed to get vcom-en gpio\n");
+
+ /* if chip was not enabled, give it time to wake up */
+ if (data->en_gpio)
+ usleep_range(2500, 4000);
+
platform_set_drvdata(pdev, data);
ret = regmap_write(regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0);
@@ -105,7 +134,6 @@ static int sy7636a_regulator_probe(struct platform_device *pdev)
}
config.dev = &pdev->dev;
- config.dev->of_node = pdev->dev.parent->of_node;
config.regmap = regmap;
rdev = devm_regulator_register(&pdev->dev, &desc, &config);
diff --git a/drivers/regulator/sy8824x.c b/drivers/regulator/sy8824x.c
index c05b67e26ac8..5bec84db25f1 100644
--- a/drivers/regulator/sy8824x.c
+++ b/drivers/regulator/sy8824x.c
@@ -213,7 +213,10 @@ static const struct of_device_id sy8824_dt_ids[] = {
MODULE_DEVICE_TABLE(of, sy8824_dt_ids);
static const struct i2c_device_id sy8824_id[] = {
- { "sy8824", (kernel_ulong_t)&sy8824c_cfg },
+ { "sy8824c", (kernel_ulong_t)&sy8824c_cfg },
+ { "sy8824e", (kernel_ulong_t)&sy8824e_cfg },
+ { "sy20276", (kernel_ulong_t)&sy20276_cfg },
+ { "sy20278", (kernel_ulong_t)&sy20278_cfg },
{ }
};
MODULE_DEVICE_TABLE(i2c, sy8824_id);
diff --git a/drivers/regulator/sy8827n.c b/drivers/regulator/sy8827n.c
index f11ff38b36c9..0b811514782f 100644
--- a/drivers/regulator/sy8827n.c
+++ b/drivers/regulator/sy8827n.c
@@ -140,7 +140,8 @@ static int sy8827n_i2c_probe(struct i2c_client *client)
return -EINVAL;
}
- di->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+ di->en_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
if (IS_ERR(di->en_gpio))
return PTR_ERR(di->en_gpio);
diff --git a/drivers/regulator/tps6286x-regulator.c b/drivers/regulator/tps6286x-regulator.c
index 75f441f36de7..e29aab06bf79 100644
--- a/drivers/regulator/tps6286x-regulator.c
+++ b/drivers/regulator/tps6286x-regulator.c
@@ -19,13 +19,22 @@
#define TPS6286X_CONTROL_FPWM BIT(4)
#define TPS6286X_CONTROL_SWEN BIT(5)
+#define TPS6286X_STATUS 0x05
+
#define TPS6286X_MIN_MV 400
#define TPS6286X_MAX_MV 1675
#define TPS6286X_STEP_MV 5
+static bool tps6286x_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg == TPS6286X_STATUS;
+}
+
static const struct regmap_config tps6286x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = tps6286x_volatile_reg,
};
static int tps6286x_set_mode(struct regulator_dev *rdev, unsigned int mode)
diff --git a/drivers/regulator/tps6287x-regulator.c b/drivers/regulator/tps6287x-regulator.c
index 97f5ce138548..7b7d3ae39206 100644
--- a/drivers/regulator/tps6287x-regulator.c
+++ b/drivers/regulator/tps6287x-regulator.c
@@ -27,10 +27,17 @@
#define TPS6287X_CTRL3 0x03
#define TPS6287X_STATUS 0x04
+static bool tps6287x_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg == TPS6287X_STATUS;
+}
+
static const struct regmap_config tps6287x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = TPS6287X_STATUS,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = tps6287x_volatile_reg,
};
static const struct linear_range tps6287x_voltage_ranges[] = {
@@ -44,10 +51,35 @@ static const unsigned int tps6287x_voltage_range_sel[] = {
0x0, 0x1, 0x2, 0x3
};
+static const unsigned int tps6287x_voltage_range_prefix[] = {
+ 0x000, 0x100, 0x200, 0x300
+};
+
static const unsigned int tps6287x_ramp_table[] = {
10000, 5000, 1250, 500
};
+struct tps6287x_reg_data {
+ int range;
+};
+
+static int tps6287x_best_range(struct regulator_config *config, const struct regulator_desc *desc)
+{
+ const struct linear_range *r;
+ int i;
+
+ if (!config->init_data->constraints.apply_uV)
+ return -1;
+
+ for (i = 0; i < desc->n_linear_ranges; i++) {
+ r = &desc->linear_ranges[i];
+ if (r->min <= config->init_data->constraints.min_uV &&
+ config->init_data->constraints.max_uV <= linear_range_get_max_value(r))
+ return i;
+ }
+ return -1;
+}
+
static int tps6287x_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
unsigned int val;
@@ -91,6 +123,28 @@ static unsigned int tps6287x_of_map_mode(unsigned int mode)
}
}
+static int tps6287x_map_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct tps6287x_reg_data *data = (struct tps6287x_reg_data *)rdev->reg_data;
+ struct linear_range selected_range;
+ int selector, voltage;
+
+ if (!data || data->range == -1)
+ return regulator_map_voltage_pickable_linear_range(rdev, min_uV, max_uV);
+
+ selected_range = rdev->desc->linear_ranges[data->range];
+ selector = DIV_ROUND_UP(min_uV - selected_range.min, selected_range.step);
+ if (selector < selected_range.min_sel || selector > selected_range.max_sel)
+ return -EINVAL;
+
+ selector |= tps6287x_voltage_range_prefix[data->range];
+ voltage = rdev->desc->ops->list_voltage(rdev, selector);
+ if (voltage < min_uV || voltage > max_uV)
+ return -EINVAL;
+
+ return selector;
+}
+
static const struct regulator_ops tps6287x_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -100,6 +154,7 @@ static const struct regulator_ops tps6287x_regulator_ops = {
.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
.set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
.list_voltage = regulator_list_voltage_pickable_linear_range,
+ .map_voltage = tps6287x_map_voltage,
.set_ramp_delay = regulator_set_ramp_delay_regmap,
};
@@ -130,8 +185,14 @@ static int tps6287x_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct regulator_config config = {};
+ struct tps6287x_reg_data *reg_data;
struct regulator_dev *rdev;
+ reg_data = devm_kzalloc(dev, sizeof(struct tps6287x_reg_data), GFP_KERNEL);
+
+ if (!reg_data)
+ return -ENOMEM;
+
config.regmap = devm_regmap_init_i2c(i2c, &tps6287x_regmap_config);
if (IS_ERR(config.regmap)) {
dev_err(dev, "Failed to init i2c\n");
@@ -143,12 +204,15 @@ static int tps6287x_i2c_probe(struct i2c_client *i2c)
config.init_data = of_get_regulator_init_data(dev, dev->of_node,
&tps6287x_reg);
+ reg_data->range = tps6287x_best_range(&config, &tps6287x_reg);
+
rdev = devm_regulator_register(dev, &tps6287x_reg, &config);
if (IS_ERR(rdev)) {
dev_err(dev, "Failed to register regulator\n");
return PTR_ERR(rdev);
}
+ rdev->reg_data = (void *)reg_data;
dev_dbg(dev, "Probed regulator\n");
return 0;
diff --git a/drivers/regulator/tps65219-regulator.c b/drivers/regulator/tps65219-regulator.c
index b4065356392f..d77ca486879f 100644
--- a/drivers/regulator/tps65219-regulator.c
+++ b/drivers/regulator/tps65219-regulator.c
@@ -1,10 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
//
-// tps65219-regulator.c
-//
-// Regulator driver for TPS65219 PMIC
+// TPS65214/TPS65215/TPS65219 PMIC Regulator Driver
//
// Copyright (C) 2022 BayLibre Incorporated - https://www.baylibre.com/
+// Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
//
// This implementation derived from tps65218 authored by
// "J Keerthy <j-keerthy@ti.com>"
@@ -30,6 +29,11 @@ struct tps65219_regulator_irq_type {
unsigned long event;
};
+static struct tps65219_regulator_irq_type tps65215_regulator_irq_types[] = {
+ { "SENSOR_3_WARM", "SENSOR3", "warm temperature", REGULATOR_EVENT_OVER_TEMP_WARN},
+ { "SENSOR_3_HOT", "SENSOR3", "hot temperature", REGULATOR_EVENT_OVER_TEMP},
+};
+
static struct tps65219_regulator_irq_type tps65219_regulator_irq_types[] = {
{ "LDO3_SCG", "LDO3", "short circuit to ground", REGULATOR_EVENT_REGULATION_OUT },
{ "LDO3_OC", "LDO3", "overcurrent", REGULATOR_EVENT_OVER_CURRENT },
@@ -37,6 +41,16 @@ static struct tps65219_regulator_irq_type tps65219_regulator_irq_types[] = {
{ "LDO4_SCG", "LDO4", "short circuit to ground", REGULATOR_EVENT_REGULATION_OUT },
{ "LDO4_OC", "LDO4", "overcurrent", REGULATOR_EVENT_OVER_CURRENT },
{ "LDO4_UV", "LDO4", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { "LDO3_RV", "LDO3", "residual voltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { "LDO4_RV", "LDO4", "residual voltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { "LDO3_RV_SD", "LDO3", "residual voltage on shutdown", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { "LDO4_RV_SD", "LDO4", "residual voltage on shutdown", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { "SENSOR_3_WARM", "SENSOR3", "warm temperature", REGULATOR_EVENT_OVER_TEMP_WARN},
+ { "SENSOR_3_HOT", "SENSOR3", "hot temperature", REGULATOR_EVENT_OVER_TEMP},
+};
+
+/* All of TPS65214's irq types are the same as common_regulator_irq_types */
+static struct tps65219_regulator_irq_type common_regulator_irq_types[] = {
{ "LDO1_SCG", "LDO1", "short circuit to ground", REGULATOR_EVENT_REGULATION_OUT },
{ "LDO1_OC", "LDO1", "overcurrent", REGULATOR_EVENT_OVER_CURRENT },
{ "LDO1_UV", "LDO1", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
@@ -60,8 +74,6 @@ static struct tps65219_regulator_irq_type tps65219_regulator_irq_types[] = {
{ "BUCK3_RV", "BUCK3", "residual voltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ "LDO1_RV", "LDO1", "residual voltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ "LDO2_RV", "LDO2", "residual voltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
- { "LDO3_RV", "LDO3", "residual voltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
- { "LDO4_RV", "LDO4", "residual voltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ "BUCK1_RV_SD", "BUCK1", "residual voltage on shutdown",
REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ "BUCK2_RV_SD", "BUCK2", "residual voltage on shutdown",
@@ -70,13 +82,9 @@ static struct tps65219_regulator_irq_type tps65219_regulator_irq_types[] = {
REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ "LDO1_RV_SD", "LDO1", "residual voltage on shutdown", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ "LDO2_RV_SD", "LDO2", "residual voltage on shutdown", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
- { "LDO3_RV_SD", "LDO3", "residual voltage on shutdown", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
- { "LDO4_RV_SD", "LDO4", "residual voltage on shutdown", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
- { "SENSOR_3_WARM", "SENSOR3", "warm temperature", REGULATOR_EVENT_OVER_TEMP_WARN},
{ "SENSOR_2_WARM", "SENSOR2", "warm temperature", REGULATOR_EVENT_OVER_TEMP_WARN },
{ "SENSOR_1_WARM", "SENSOR1", "warm temperature", REGULATOR_EVENT_OVER_TEMP_WARN },
{ "SENSOR_0_WARM", "SENSOR0", "warm temperature", REGULATOR_EVENT_OVER_TEMP_WARN },
- { "SENSOR_3_HOT", "SENSOR3", "hot temperature", REGULATOR_EVENT_OVER_TEMP},
{ "SENSOR_2_HOT", "SENSOR2", "hot temperature", REGULATOR_EVENT_OVER_TEMP },
{ "SENSOR_1_HOT", "SENSOR1", "hot temperature", REGULATOR_EVENT_OVER_TEMP },
{ "SENSOR_0_HOT", "SENSOR0", "hot temperature", REGULATOR_EVENT_OVER_TEMP },
@@ -125,12 +133,28 @@ static const struct linear_range bucks_ranges[] = {
REGULATOR_LINEAR_RANGE(3400000, 0x34, 0x3f, 0),
};
-static const struct linear_range ldos_1_2_ranges[] = {
+static const struct linear_range ldo_1_range[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x0, 0x37, 50000),
+ REGULATOR_LINEAR_RANGE(3400000, 0x38, 0x3f, 0),
+};
+
+static const struct linear_range tps65214_ldo_1_2_range[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2, 0),
+ REGULATOR_LINEAR_RANGE(650000, 0x3, 0x37, 50000),
+ REGULATOR_LINEAR_RANGE(3300000, 0x38, 0x3F, 0),
+};
+
+static const struct linear_range tps65215_ldo_2_range[] = {
+ REGULATOR_LINEAR_RANGE(1200000, 0x0, 0xC, 50000),
+ REGULATOR_LINEAR_RANGE(3300000, 0x36, 0x3F, 0),
+};
+
+static const struct linear_range tps65219_ldo_2_range[] = {
REGULATOR_LINEAR_RANGE(600000, 0x0, 0x37, 50000),
REGULATOR_LINEAR_RANGE(3400000, 0x38, 0x3f, 0),
};
-static const struct linear_range ldos_3_4_ranges[] = {
+static const struct linear_range tps65219_ldos_3_4_range[] = {
REGULATOR_LINEAR_RANGE(1200000, 0x0, 0xC, 0),
REGULATOR_LINEAR_RANGE(1250000, 0xD, 0x35, 50000),
REGULATOR_LINEAR_RANGE(3300000, 0x36, 0x3F, 0),
@@ -174,7 +198,7 @@ static unsigned int tps65219_get_mode(struct regulator_dev *dev)
}
/* Operations permitted on BUCK1/2/3 */
-static const struct regulator_ops tps65219_bucks_ops = {
+static const struct regulator_ops bucks_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -189,7 +213,7 @@ static const struct regulator_ops tps65219_bucks_ops = {
};
/* Operations permitted on LDO1/2 */
-static const struct regulator_ops tps65219_ldos_1_2_ops = {
+static const struct regulator_ops ldos_1_2_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -204,7 +228,7 @@ static const struct regulator_ops tps65219_ldos_1_2_ops = {
};
/* Operations permitted on LDO3/4 */
-static const struct regulator_ops tps65219_ldos_3_4_ops = {
+static const struct regulator_ops ldos_3_4_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -216,55 +240,98 @@ static const struct regulator_ops tps65219_ldos_3_4_ops = {
.map_voltage = regulator_map_voltage_linear_range,
};
-static const struct regulator_desc regulators[] = {
+static const struct regulator_desc common_regs[] = {
TPS65219_REGULATOR("BUCK1", "buck1", TPS65219_BUCK_1,
- REGULATOR_VOLTAGE, tps65219_bucks_ops, 64,
+ REGULATOR_VOLTAGE, bucks_ops, 64,
TPS65219_REG_BUCK1_VOUT,
TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
TPS65219_REG_ENABLE_CTRL,
TPS65219_ENABLE_BUCK1_EN_MASK, 0, 0, bucks_ranges,
3, 4000, 0, NULL, 0, 0),
TPS65219_REGULATOR("BUCK2", "buck2", TPS65219_BUCK_2,
- REGULATOR_VOLTAGE, tps65219_bucks_ops, 64,
+ REGULATOR_VOLTAGE, bucks_ops, 64,
TPS65219_REG_BUCK2_VOUT,
TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
TPS65219_REG_ENABLE_CTRL,
TPS65219_ENABLE_BUCK2_EN_MASK, 0, 0, bucks_ranges,
3, 4000, 0, NULL, 0, 0),
TPS65219_REGULATOR("BUCK3", "buck3", TPS65219_BUCK_3,
- REGULATOR_VOLTAGE, tps65219_bucks_ops, 64,
+ REGULATOR_VOLTAGE, bucks_ops, 64,
TPS65219_REG_BUCK3_VOUT,
TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
TPS65219_REG_ENABLE_CTRL,
TPS65219_ENABLE_BUCK3_EN_MASK, 0, 0, bucks_ranges,
3, 0, 0, NULL, 0, 0),
+};
+
+static const struct regulator_desc tps65214_regs[] = {
+ // TPS65214's LDO3 pin maps to TPS65219's LDO3 pin
+ TPS65219_REGULATOR("LDO1", "ldo1", TPS65214_LDO_1,
+ REGULATOR_VOLTAGE, ldos_3_4_ops, 64,
+ TPS65214_REG_LDO1_VOUT,
+ TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
+ TPS65219_REG_ENABLE_CTRL,
+ TPS65219_ENABLE_LDO3_EN_MASK, 0, 0, tps65214_ldo_1_2_range,
+ 3, 0, 0, NULL, 0, 0),
+ TPS65219_REGULATOR("LDO2", "ldo2", TPS65214_LDO_2,
+ REGULATOR_VOLTAGE, ldos_3_4_ops, 64,
+ TPS65214_REG_LDO2_VOUT,
+ TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
+ TPS65219_REG_ENABLE_CTRL,
+ TPS65219_ENABLE_LDO2_EN_MASK, 0, 0, tps65214_ldo_1_2_range,
+ 3, 0, 0, NULL, 0, 0),
+};
+
+static const struct regulator_desc tps65215_regs[] = {
+ /*
+ * TPS65215's LDO1 is the same as TPS65219's LDO1. LDO1 is
+ * configurable as load switch and bypass-mode.
+ * TPS65215's LDO2 is the same as TPS65219's LDO3
+ */
+ TPS65219_REGULATOR("LDO1", "ldo1", TPS65219_LDO_1,
+ REGULATOR_VOLTAGE, ldos_1_2_ops, 64,
+ TPS65219_REG_LDO1_VOUT,
+ TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
+ TPS65219_REG_ENABLE_CTRL,
+ TPS65219_ENABLE_LDO1_EN_MASK, 0, 0, ldo_1_range,
+ 2, 0, 0, NULL, 0, TPS65219_LDOS_BYP_CONFIG_MASK),
+ TPS65219_REGULATOR("LDO2", "ldo2", TPS65215_LDO_2,
+ REGULATOR_VOLTAGE, ldos_3_4_ops, 64,
+ TPS65215_REG_LDO2_VOUT,
+ TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
+ TPS65219_REG_ENABLE_CTRL,
+ TPS65215_ENABLE_LDO2_EN_MASK, 0, 0, tps65215_ldo_2_range,
+ 2, 0, 0, NULL, 0, 0),
+};
+
+static const struct regulator_desc tps65219_regs[] = {
TPS65219_REGULATOR("LDO1", "ldo1", TPS65219_LDO_1,
- REGULATOR_VOLTAGE, tps65219_ldos_1_2_ops, 64,
+ REGULATOR_VOLTAGE, ldos_1_2_ops, 64,
TPS65219_REG_LDO1_VOUT,
TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
TPS65219_REG_ENABLE_CTRL,
- TPS65219_ENABLE_LDO1_EN_MASK, 0, 0, ldos_1_2_ranges,
+ TPS65219_ENABLE_LDO1_EN_MASK, 0, 0, ldo_1_range,
2, 0, 0, NULL, 0, TPS65219_LDOS_BYP_CONFIG_MASK),
TPS65219_REGULATOR("LDO2", "ldo2", TPS65219_LDO_2,
- REGULATOR_VOLTAGE, tps65219_ldos_1_2_ops, 64,
+ REGULATOR_VOLTAGE, ldos_1_2_ops, 64,
TPS65219_REG_LDO2_VOUT,
TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
TPS65219_REG_ENABLE_CTRL,
- TPS65219_ENABLE_LDO2_EN_MASK, 0, 0, ldos_1_2_ranges,
+ TPS65219_ENABLE_LDO2_EN_MASK, 0, 0, tps65219_ldo_2_range,
2, 0, 0, NULL, 0, TPS65219_LDOS_BYP_CONFIG_MASK),
TPS65219_REGULATOR("LDO3", "ldo3", TPS65219_LDO_3,
- REGULATOR_VOLTAGE, tps65219_ldos_3_4_ops, 64,
+ REGULATOR_VOLTAGE, ldos_3_4_ops, 64,
TPS65219_REG_LDO3_VOUT,
TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
TPS65219_REG_ENABLE_CTRL,
- TPS65219_ENABLE_LDO3_EN_MASK, 0, 0, ldos_3_4_ranges,
+ TPS65219_ENABLE_LDO3_EN_MASK, 0, 0, tps65219_ldos_3_4_range,
3, 0, 0, NULL, 0, 0),
TPS65219_REGULATOR("LDO4", "ldo4", TPS65219_LDO_4,
- REGULATOR_VOLTAGE, tps65219_ldos_3_4_ops, 64,
+ REGULATOR_VOLTAGE, ldos_3_4_ops, 64,
TPS65219_REG_LDO4_VOUT,
TPS65219_BUCKS_LDOS_VOUT_VSET_MASK,
TPS65219_REG_ENABLE_CTRL,
- TPS65219_ENABLE_LDO4_EN_MASK, 0, 0, ldos_3_4_ranges,
+ TPS65219_ENABLE_LDO4_EN_MASK, 0, 0, tps65219_ldos_3_4_range,
3, 0, 0, NULL, 0, 0),
};
@@ -287,99 +354,148 @@ static irqreturn_t tps65219_regulator_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int tps65219_get_rdev_by_name(const char *regulator_name,
- struct regulator_dev *rdevtbl[7],
- struct regulator_dev **dev)
-{
- int i;
+struct tps65219_chip_data {
+ size_t rdesc_size;
+ size_t common_rdesc_size;
+ size_t dev_irq_size;
+ size_t common_irq_size;
+ const struct regulator_desc *rdesc;
+ const struct regulator_desc *common_rdesc;
+ struct tps65219_regulator_irq_type *irq_types;
+ struct tps65219_regulator_irq_type *common_irq_types;
+};
- for (i = 0; i < ARRAY_SIZE(regulators); i++) {
- if (strcmp(regulator_name, regulators[i].name) == 0) {
- *dev = rdevtbl[i];
- return 0;
- }
- }
- return -EINVAL;
-}
+static struct tps65219_chip_data chip_info_table[] = {
+ [TPS65214] = {
+ .rdesc = tps65214_regs,
+ .rdesc_size = ARRAY_SIZE(tps65214_regs),
+ .common_rdesc = common_regs,
+ .common_rdesc_size = ARRAY_SIZE(common_regs),
+ .irq_types = NULL,
+ .dev_irq_size = 0,
+ .common_irq_types = common_regulator_irq_types,
+ .common_irq_size = ARRAY_SIZE(common_regulator_irq_types),
+ },
+ [TPS65215] = {
+ .rdesc = tps65215_regs,
+ .rdesc_size = ARRAY_SIZE(tps65215_regs),
+ .common_rdesc = common_regs,
+ .common_rdesc_size = ARRAY_SIZE(common_regs),
+ .irq_types = tps65215_regulator_irq_types,
+ .dev_irq_size = ARRAY_SIZE(tps65215_regulator_irq_types),
+ .common_irq_types = common_regulator_irq_types,
+ .common_irq_size = ARRAY_SIZE(common_regulator_irq_types),
+ },
+ [TPS65219] = {
+ .rdesc = tps65219_regs,
+ .rdesc_size = ARRAY_SIZE(tps65219_regs),
+ .common_rdesc = common_regs,
+ .common_rdesc_size = ARRAY_SIZE(common_regs),
+ .irq_types = tps65219_regulator_irq_types,
+ .dev_irq_size = ARRAY_SIZE(tps65219_regulator_irq_types),
+ .common_irq_types = common_regulator_irq_types,
+ .common_irq_size = ARRAY_SIZE(common_regulator_irq_types),
+ },
+};
static int tps65219_regulator_probe(struct platform_device *pdev)
{
- struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct tps65219_regulator_irq_data *irq_data;
+ struct tps65219_regulator_irq_type *irq_type;
+ struct tps65219_chip_data *pmic;
struct regulator_dev *rdev;
- struct regulator_config config = { };
- int i;
int error;
int irq;
- struct tps65219_regulator_irq_data *irq_data;
- struct tps65219_regulator_irq_type *irq_type;
- struct regulator_dev *rdevtbl[7];
+ int i;
+
+ struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ enum pmic_id chip = platform_get_device_id(pdev)->driver_data;
+
+ pmic = &chip_info_table[chip];
config.dev = tps->dev;
config.driver_data = tps;
config.regmap = tps->regmap;
- for (i = 0; i < ARRAY_SIZE(regulators); i++) {
- dev_dbg(tps->dev, "%s regul i= %d START", __func__, i);
- rdev = devm_regulator_register(&pdev->dev, &regulators[i],
+ for (i = 0; i < pmic->common_rdesc_size; i++) {
+ rdev = devm_regulator_register(&pdev->dev, &pmic->common_rdesc[i],
&config);
- if (IS_ERR(rdev)) {
- dev_err(tps->dev, "failed to register %s regulator\n",
- regulators[i].name);
- return PTR_ERR(rdev);
- }
- rdevtbl[i] = rdev;
- dev_dbg(tps->dev, "%s regul i= %d COMPLETED", __func__, i);
+ if (IS_ERR(rdev))
+ return dev_err_probe(tps->dev, PTR_ERR(rdev),
+ "Failed to register %s regulator\n",
+ pmic->common_rdesc[i].name);
}
- irq_data = devm_kmalloc(tps->dev,
- ARRAY_SIZE(tps65219_regulator_irq_types) *
- sizeof(struct tps65219_regulator_irq_data),
- GFP_KERNEL);
- if (!irq_data)
- return -ENOMEM;
-
- for (i = 0; i < ARRAY_SIZE(tps65219_regulator_irq_types); ++i) {
- irq_type = &tps65219_regulator_irq_types[i];
+ for (i = 0; i < pmic->rdesc_size; i++) {
+ rdev = devm_regulator_register(&pdev->dev, &pmic->rdesc[i],
+ &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(tps->dev, PTR_ERR(rdev),
+ "Failed to register %s regulator\n",
+ pmic->rdesc[i].name);
+ }
+ for (i = 0; i < pmic->common_irq_size; ++i) {
+ irq_type = &pmic->common_irq_types[i];
irq = platform_get_irq_byname(pdev, irq_type->irq_name);
if (irq < 0)
return -EINVAL;
- irq_data[i].dev = tps->dev;
- irq_data[i].type = irq_type;
+ irq_data = devm_kmalloc(tps->dev, sizeof(*irq_data), GFP_KERNEL);
+ if (!irq_data)
+ return -ENOMEM;
+
+ irq_data->dev = tps->dev;
+ irq_data->type = irq_type;
+ error = devm_request_threaded_irq(tps->dev, irq, NULL,
+ tps65219_regulator_irq_handler,
+ IRQF_ONESHOT,
+ irq_type->irq_name,
+ irq_data);
+ if (error)
+ return dev_err_probe(tps->dev, error,
+ "Failed to request %s IRQ %d\n",
+ irq_type->irq_name, irq);
+ }
- tps65219_get_rdev_by_name(irq_type->regulator_name, rdevtbl, &rdev);
- if (IS_ERR(rdev)) {
- dev_err(tps->dev, "Failed to get rdev for %s\n",
- irq_type->regulator_name);
+ for (i = 0; i < pmic->dev_irq_size; ++i) {
+ irq_type = &pmic->irq_types[i];
+ irq = platform_get_irq_byname(pdev, irq_type->irq_name);
+ if (irq < 0)
return -EINVAL;
- }
- irq_data[i].rdev = rdev;
+ irq_data = devm_kmalloc(tps->dev, sizeof(*irq_data), GFP_KERNEL);
+ if (!irq_data)
+ return -ENOMEM;
+
+ irq_data->dev = tps->dev;
+ irq_data->type = irq_type;
error = devm_request_threaded_irq(tps->dev, irq, NULL,
tps65219_regulator_irq_handler,
IRQF_ONESHOT,
irq_type->irq_name,
- &irq_data[i]);
- if (error) {
- dev_err(tps->dev, "failed to request %s IRQ %d: %d\n",
- irq_type->irq_name, irq, error);
- return error;
- }
+ irq_data);
+ if (error)
+ return dev_err_probe(tps->dev, error,
+ "Failed to request %s IRQ %d\n",
+ irq_type->irq_name, irq);
}
return 0;
}
static const struct platform_device_id tps65219_regulator_id_table[] = {
- { "tps65219-regulator", },
+ { "tps65214-regulator", TPS65214 },
+ { "tps65215-regulator", TPS65215 },
+ { "tps65219-regulator", TPS65219 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65219_regulator_id_table);
static struct platform_driver tps65219_regulator_driver = {
.driver = {
- .name = "tps65219-pmic",
+ .name = "tps65219-regulator",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = tps65219_regulator_probe,
@@ -389,6 +505,5 @@ static struct platform_driver tps65219_regulator_driver = {
module_platform_driver(tps65219_regulator_driver);
MODULE_AUTHOR("Jerome Neanne <j-neanne@baylibre.com>");
-MODULE_DESCRIPTION("TPS65219 voltage regulator driver");
-MODULE_ALIAS("platform:tps65219-pmic");
+MODULE_DESCRIPTION("TPS65214/TPS65215/TPS65219 Regulator driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 3fee7e38c68b..6beb51293e8e 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -598,7 +598,6 @@ static int pmic_probe(struct spi_device *spi)
spi_set_drvdata(spi, hw);
- memset(hw, 0, sizeof(struct tps6524x));
hw->dev = dev;
hw->spi = spi;
mutex_init(&hw->lock);
diff --git a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c
index ac53792e3fed..645e83462c64 100644
--- a/drivers/regulator/tps6594-regulator.c
+++ b/drivers/regulator/tps6594-regulator.c
@@ -21,10 +21,6 @@
#define BUCK_NB 5
#define LDO_NB 4
#define MULTI_PHASE_NB 4
-/* TPS6593 and LP8764 supports OV, UV, SC, ILIM */
-#define REGS_INT_NB 4
-/* TPS65224 supports OV or UV */
-#define TPS65224_REGS_INT_NB 1
enum tps6594_regulator_id {
/* DCDC's */
@@ -56,7 +52,7 @@ struct tps6594_regulator_irq_type {
unsigned long event;
};
-static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = {
{ TPS6594_IRQ_NAME_VCCA_OV, "VCCA", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_VCCA_UV, "VCCA", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_VMON1_OV, "VMON1", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
@@ -69,7 +65,7 @@ static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = {
REGULATOR_EVENT_OVER_VOLTAGE_WARN },
};
-static struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = {
{ TPS65224_IRQ_NAME_VCCA_UVOV, "VCCA", "voltage out of range",
REGULATOR_EVENT_REGULATION_OUT },
{ TPS65224_IRQ_NAME_VMON1_UVOV, "VMON1", "voltage out of range",
@@ -80,13 +76,13 @@ static struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = {
struct tps6594_regulator_irq_data {
struct device *dev;
- struct tps6594_regulator_irq_type *type;
+ const struct tps6594_regulator_irq_type *type;
struct regulator_dev *rdev;
};
struct tps6594_ext_regulator_irq_data {
struct device *dev;
- struct tps6594_regulator_irq_type *type;
+ const struct tps6594_regulator_irq_type *type;
};
#define TPS6594_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
@@ -192,7 +188,7 @@ static const struct regulator_ops tps6594_ldos_4_ops = {
.map_voltage = regulator_map_voltage_linear_range,
};
-static const struct regulator_desc buck_regs[] = {
+static const struct regulator_desc tps6594_buck_regs[] = {
TPS6594_REGULATOR("BUCK1", "buck1", TPS6594_BUCK_1,
REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
TPS6594_REG_BUCKX_VOUT_1(0),
@@ -262,7 +258,7 @@ static const struct regulator_desc tps65224_buck_regs[] = {
4, 0, 0, NULL, 0, 0),
};
-static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = {
{ TPS6594_IRQ_NAME_BUCK1_OV, "BUCK1", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_BUCK1_UV, "BUCK1", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_BUCK1_SC, "BUCK1", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -270,7 +266,7 @@ static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = {
{ TPS6594_IRQ_NAME_BUCK2_OV, "BUCK2", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_BUCK2_UV, "BUCK2", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_BUCK2_SC, "BUCK2", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -278,7 +274,7 @@ static struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = {
{ TPS6594_IRQ_NAME_BUCK3_OV, "BUCK3", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_BUCK3_UV, "BUCK3", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_BUCK3_SC, "BUCK3", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -286,7 +282,7 @@ static struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = {
{ TPS6594_IRQ_NAME_BUCK4_OV, "BUCK4", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_BUCK4_UV, "BUCK4", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_BUCK4_SC, "BUCK4", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -294,7 +290,7 @@ static struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = {
{ TPS6594_IRQ_NAME_BUCK5_OV, "BUCK5", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_BUCK5_UV, "BUCK5", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_BUCK5_SC, "BUCK5", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -302,7 +298,7 @@ static struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = {
{ TPS6594_IRQ_NAME_LDO1_OV, "LDO1", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_LDO1_UV, "LDO1", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_LDO1_SC, "LDO1", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -310,7 +306,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = {
{ TPS6594_IRQ_NAME_LDO2_OV, "LDO2", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_LDO2_UV, "LDO2", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_LDO2_SC, "LDO2", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -318,7 +314,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = {
{ TPS6594_IRQ_NAME_LDO3_OV, "LDO3", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_LDO3_UV, "LDO3", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_LDO3_SC, "LDO3", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -326,7 +322,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = {
{ TPS6594_IRQ_NAME_LDO4_OV, "LDO4", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
{ TPS6594_IRQ_NAME_LDO4_UV, "LDO4", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
{ TPS6594_IRQ_NAME_LDO4_SC, "LDO4", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
@@ -334,42 +330,42 @@ static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = {
REGULATOR_EVENT_OVER_CURRENT },
};
-static struct tps6594_regulator_irq_type tps65224_buck1_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps65224_buck1_irq_types[] = {
{ TPS65224_IRQ_NAME_BUCK1_UVOV, "BUCK1", "voltage out of range",
REGULATOR_EVENT_REGULATION_OUT },
};
-static struct tps6594_regulator_irq_type tps65224_buck2_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps65224_buck2_irq_types[] = {
{ TPS65224_IRQ_NAME_BUCK2_UVOV, "BUCK2", "voltage out of range",
REGULATOR_EVENT_REGULATION_OUT },
};
-static struct tps6594_regulator_irq_type tps65224_buck3_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps65224_buck3_irq_types[] = {
{ TPS65224_IRQ_NAME_BUCK3_UVOV, "BUCK3", "voltage out of range",
REGULATOR_EVENT_REGULATION_OUT },
};
-static struct tps6594_regulator_irq_type tps65224_buck4_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps65224_buck4_irq_types[] = {
{ TPS65224_IRQ_NAME_BUCK4_UVOV, "BUCK4", "voltage out of range",
REGULATOR_EVENT_REGULATION_OUT },
};
-static struct tps6594_regulator_irq_type tps65224_ldo1_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps65224_ldo1_irq_types[] = {
{ TPS65224_IRQ_NAME_LDO1_UVOV, "LDO1", "voltage out of range",
REGULATOR_EVENT_REGULATION_OUT },
};
-static struct tps6594_regulator_irq_type tps65224_ldo2_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps65224_ldo2_irq_types[] = {
{ TPS65224_IRQ_NAME_LDO2_UVOV, "LDO2", "voltage out of range",
REGULATOR_EVENT_REGULATION_OUT },
};
-static struct tps6594_regulator_irq_type tps65224_ldo3_irq_types[] = {
+static const struct tps6594_regulator_irq_type tps65224_ldo3_irq_types[] = {
{ TPS65224_IRQ_NAME_LDO3_UVOV, "LDO3", "voltage out of range",
REGULATOR_EVENT_REGULATION_OUT },
};
-static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = {
+static const struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = {
tps6594_buck1_irq_types,
tps6594_buck2_irq_types,
tps6594_buck3_irq_types,
@@ -377,21 +373,21 @@ static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = {
tps6594_buck5_irq_types,
};
-static struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = {
+static const struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = {
tps6594_ldo1_irq_types,
tps6594_ldo2_irq_types,
tps6594_ldo3_irq_types,
tps6594_ldo4_irq_types,
};
-static struct tps6594_regulator_irq_type *tps65224_bucks_irq_types[] = {
+static const struct tps6594_regulator_irq_type *tps65224_bucks_irq_types[] = {
tps65224_buck1_irq_types,
tps65224_buck2_irq_types,
tps65224_buck3_irq_types,
tps65224_buck4_irq_types,
};
-static struct tps6594_regulator_irq_type *tps65224_ldos_irq_types[] = {
+static const struct tps6594_regulator_irq_type *tps65224_ldos_irq_types[] = {
tps65224_ldo1_irq_types,
tps65224_ldo2_irq_types,
tps65224_ldo3_irq_types,
@@ -516,11 +512,11 @@ static irqreturn_t tps6594_regulator_irq_handler(int irq, void *data)
static int tps6594_request_reg_irqs(struct platform_device *pdev,
struct regulator_dev *rdev,
struct tps6594_regulator_irq_data *irq_data,
- struct tps6594_regulator_irq_type *regs_irq_types,
+ const struct tps6594_regulator_irq_type *regs_irq_types,
size_t interrupt_cnt,
int *irq_idx)
{
- struct tps6594_regulator_irq_type *irq_type;
+ const struct tps6594_regulator_irq_type *irq_type;
struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
size_t j;
int irq;
@@ -549,6 +545,70 @@ static int tps6594_request_reg_irqs(struct platform_device *pdev,
return 0;
}
+struct tps6594_regulator_desc {
+ const struct regulator_desc *multi_phase_regs;
+ unsigned int num_multi_phase_regs;
+
+ const struct regulator_desc *buck_regs;
+ int num_buck_regs;
+
+ const struct regulator_desc *ldo_regs;
+ int num_ldo_regs;
+
+ const struct tps6594_regulator_irq_type **bucks_irq_types;
+ const struct tps6594_regulator_irq_type **ldos_irq_types;
+ int num_irq_types;
+
+ const struct tps6594_regulator_irq_type *ext_irq_types;
+ int num_ext_irqs;
+};
+
+static const struct tps6594_regulator_desc tps65224_reg_desc = {
+ .multi_phase_regs = tps65224_multi_regs,
+ .num_multi_phase_regs = ARRAY_SIZE(tps65224_multi_regs),
+ .buck_regs = tps65224_buck_regs,
+ .num_buck_regs = ARRAY_SIZE(tps65224_buck_regs),
+ .ldo_regs = tps65224_ldo_regs,
+ .num_ldo_regs = ARRAY_SIZE(tps65224_ldo_regs),
+ .bucks_irq_types = tps65224_bucks_irq_types,
+ .ldos_irq_types = tps65224_ldos_irq_types,
+ .num_irq_types = 1, /* OV or UV */
+ .ext_irq_types = tps65224_ext_regulator_irq_types,
+ .num_ext_irqs = ARRAY_SIZE(tps65224_ext_regulator_irq_types),
+};
+
+static const struct tps6594_regulator_desc tps652g1_reg_desc = {
+ .ldo_regs = tps65224_ldo_regs,
+ .num_ldo_regs = ARRAY_SIZE(tps65224_ldo_regs),
+ .buck_regs = tps65224_buck_regs,
+ .num_buck_regs = ARRAY_SIZE(tps65224_buck_regs),
+};
+
+static const struct tps6594_regulator_desc tps6594_reg_desc = {
+ .multi_phase_regs = tps6594_multi_regs,
+ .num_multi_phase_regs = ARRAY_SIZE(tps6594_multi_regs),
+ .buck_regs = tps6594_buck_regs,
+ .num_buck_regs = ARRAY_SIZE(tps6594_buck_regs),
+ .ldo_regs = tps6594_ldo_regs,
+ .num_ldo_regs = ARRAY_SIZE(tps6594_ldo_regs),
+ .bucks_irq_types = tps6594_bucks_irq_types,
+ .ldos_irq_types = tps6594_ldos_irq_types,
+ .num_irq_types = 4, /* OV, UV, SC and ILIM */
+ .ext_irq_types = tps6594_ext_regulator_irq_types,
+ .num_ext_irqs = 2, /* only VCCA OV and UV */
+};
+
+static const struct tps6594_regulator_desc lp8764_reg_desc = {
+ .multi_phase_regs = tps6594_multi_regs,
+ .num_multi_phase_regs = ARRAY_SIZE(tps6594_multi_regs),
+ .buck_regs = tps6594_buck_regs,
+ .num_buck_regs = ARRAY_SIZE(tps6594_buck_regs),
+ .bucks_irq_types = tps6594_bucks_irq_types,
+ .num_irq_types = 4, /* OV, UV, SC and ILIM */
+ .ext_irq_types = tps6594_ext_regulator_irq_types,
+ .num_ext_irqs = ARRAY_SIZE(tps6594_ext_regulator_irq_types),
+};
+
static int tps6594_regulator_probe(struct platform_device *pdev)
{
struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
@@ -558,41 +618,35 @@ static int tps6594_regulator_probe(struct platform_device *pdev)
struct regulator_config config = {};
struct tps6594_regulator_irq_data *irq_data;
struct tps6594_ext_regulator_irq_data *irq_ext_reg_data;
- struct tps6594_regulator_irq_type *irq_type;
- struct tps6594_regulator_irq_type *irq_types;
+ const struct tps6594_regulator_irq_type *irq_type;
bool buck_configured[BUCK_NB] = { false };
bool buck_multi[MULTI_PHASE_NB] = { false };
+ const struct tps6594_regulator_desc *desc;
+ const struct regulator_desc *multi_regs;
- static const char *npname;
+ const char *npname;
int error, i, irq, multi;
int irq_idx = 0;
int buck_idx = 0;
- int nr_ldo;
- int nr_buck;
- int nr_types;
- unsigned int irq_count;
- unsigned int multi_phase_cnt;
size_t reg_irq_nb;
- struct tps6594_regulator_irq_type **bucks_irq_types;
- const struct regulator_desc *multi_regs;
- struct tps6594_regulator_irq_type **ldos_irq_types;
- const struct regulator_desc *ldo_regs;
- size_t interrupt_count;
-
- if (tps->chip_id == TPS65224) {
- bucks_irq_types = tps65224_bucks_irq_types;
- interrupt_count = ARRAY_SIZE(tps65224_buck1_irq_types);
- multi_regs = tps65224_multi_regs;
- ldos_irq_types = tps65224_ldos_irq_types;
- ldo_regs = tps65224_ldo_regs;
- multi_phase_cnt = ARRAY_SIZE(tps65224_multi_regs);
- } else {
- bucks_irq_types = tps6594_bucks_irq_types;
- interrupt_count = ARRAY_SIZE(tps6594_buck1_irq_types);
- multi_regs = tps6594_multi_regs;
- ldos_irq_types = tps6594_ldos_irq_types;
- ldo_regs = tps6594_ldo_regs;
- multi_phase_cnt = ARRAY_SIZE(tps6594_multi_regs);
+
+ switch (tps->chip_id) {
+ case TPS65224:
+ desc = &tps65224_reg_desc;
+ break;
+ case TPS652G1:
+ desc = &tps652g1_reg_desc;
+ break;
+ case TPS6594:
+ case TPS6593:
+ desc = &tps6594_reg_desc;
+ break;
+ case LP8764:
+ desc = &lp8764_reg_desc;
+ break;
+ default:
+ dev_err(tps->dev, "unknown chip_id %lu\n", tps->chip_id);
+ return -EINVAL;
}
enum {
@@ -614,13 +668,14 @@ static int tps6594_regulator_probe(struct platform_device *pdev)
* In case of Multiphase configuration, value should be defined for
* buck_configured to avoid creating bucks for every buck in multiphase
*/
- for (multi = 0; multi < multi_phase_cnt; multi++) {
- np = of_find_node_by_name(tps->dev->of_node, multi_regs[multi].supply_name);
+ for (multi = 0; multi < desc->num_multi_phase_regs; multi++) {
+ multi_regs = &desc->multi_phase_regs[multi];
+ np = of_find_node_by_name(tps->dev->of_node, multi_regs->supply_name);
npname = of_node_full_name(np);
np_pmic_parent = of_get_parent(of_get_parent(np));
if (of_node_cmp(of_node_full_name(np_pmic_parent), tps->dev->of_node->full_name))
continue;
- if (strcmp(npname, multi_regs[multi].supply_name) == 0) {
+ if (strcmp(npname, multi_regs->supply_name) == 0) {
switch (multi) {
case MULTI_BUCK12:
buck_multi[0] = true;
@@ -653,123 +708,106 @@ static int tps6594_regulator_probe(struct platform_device *pdev)
}
}
- if (tps->chip_id == TPS65224) {
- nr_buck = ARRAY_SIZE(tps65224_buck_regs);
- nr_ldo = ARRAY_SIZE(tps65224_ldo_regs);
- nr_types = TPS65224_REGS_INT_NB;
- } else {
- nr_buck = ARRAY_SIZE(buck_regs);
- nr_ldo = (tps->chip_id == LP8764) ? 0 : ARRAY_SIZE(tps6594_ldo_regs);
- nr_types = REGS_INT_NB;
- }
-
- reg_irq_nb = nr_types * (nr_buck + nr_ldo);
+ reg_irq_nb = desc->num_irq_types * (desc->num_buck_regs + desc->num_ldo_regs);
irq_data = devm_kmalloc_array(tps->dev, reg_irq_nb,
sizeof(struct tps6594_regulator_irq_data), GFP_KERNEL);
if (!irq_data)
return -ENOMEM;
- for (i = 0; i < multi_phase_cnt; i++) {
+ for (i = 0; i < desc->num_multi_phase_regs; i++) {
if (!buck_multi[i])
continue;
- rdev = devm_regulator_register(&pdev->dev, &multi_regs[i], &config);
+ rdev = devm_regulator_register(&pdev->dev, &desc->multi_phase_regs[i],
+ &config);
if (IS_ERR(rdev))
return dev_err_probe(tps->dev, PTR_ERR(rdev),
"failed to register %s regulator\n",
pdev->name);
+ if (!desc->num_irq_types)
+ continue;
+
/* config multiphase buck12+buck34 */
if (i == MULTI_BUCK12_34)
buck_idx = 2;
error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
- bucks_irq_types[buck_idx],
- interrupt_count, &irq_idx);
+ desc->bucks_irq_types[buck_idx],
+ desc->num_irq_types, &irq_idx);
if (error)
return error;
error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
- bucks_irq_types[buck_idx + 1],
- interrupt_count, &irq_idx);
+ desc->bucks_irq_types[buck_idx + 1],
+ desc->num_irq_types, &irq_idx);
if (error)
return error;
if (i == MULTI_BUCK123 || i == MULTI_BUCK1234) {
error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
- tps6594_bucks_irq_types[buck_idx + 2],
- interrupt_count,
+ desc->bucks_irq_types[buck_idx + 2],
+ desc->num_irq_types,
&irq_idx);
if (error)
return error;
}
if (i == MULTI_BUCK1234) {
error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
- tps6594_bucks_irq_types[buck_idx + 3],
- interrupt_count,
+ desc->bucks_irq_types[buck_idx + 3],
+ desc->num_irq_types,
&irq_idx);
if (error)
return error;
}
}
- for (i = 0; i < nr_buck; i++) {
+ for (i = 0; i < desc->num_buck_regs; i++) {
if (buck_configured[i])
continue;
- const struct regulator_desc *buck_cfg = (tps->chip_id == TPS65224) ?
- tps65224_buck_regs : buck_regs;
-
- rdev = devm_regulator_register(&pdev->dev, &buck_cfg[i], &config);
+ rdev = devm_regulator_register(&pdev->dev, &desc->buck_regs[i], &config);
if (IS_ERR(rdev))
return dev_err_probe(tps->dev, PTR_ERR(rdev),
"failed to register %s regulator\n", pdev->name);
+ if (!desc->num_irq_types)
+ continue;
+
error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
- bucks_irq_types[i], interrupt_count, &irq_idx);
+ desc->bucks_irq_types[i],
+ desc->num_irq_types, &irq_idx);
if (error)
return error;
}
- /* LP8764 doesn't have LDO */
- if (tps->chip_id != LP8764) {
- for (i = 0; i < nr_ldo; i++) {
- rdev = devm_regulator_register(&pdev->dev, &ldo_regs[i], &config);
- if (IS_ERR(rdev))
- return dev_err_probe(tps->dev, PTR_ERR(rdev),
- "failed to register %s regulator\n",
- pdev->name);
+ for (i = 0; i < desc->num_ldo_regs; i++) {
+ rdev = devm_regulator_register(&pdev->dev, &desc->ldo_regs[i], &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(tps->dev, PTR_ERR(rdev),
+ "failed to register %s regulator\n",
+ pdev->name);
- error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
- ldos_irq_types[i], interrupt_count,
- &irq_idx);
- if (error)
- return error;
- }
- }
+ if (!desc->num_irq_types)
+ continue;
- if (tps->chip_id == TPS65224) {
- irq_types = tps65224_ext_regulator_irq_types;
- irq_count = ARRAY_SIZE(tps65224_ext_regulator_irq_types);
- } else {
- irq_types = tps6594_ext_regulator_irq_types;
- if (tps->chip_id == LP8764)
- irq_count = ARRAY_SIZE(tps6594_ext_regulator_irq_types);
- else
- /* TPS6593 supports only VCCA OV and UV */
- irq_count = 2;
+ error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
+ desc->ldos_irq_types[i],
+ desc->num_irq_types, &irq_idx);
+ if (error)
+ return error;
}
irq_ext_reg_data = devm_kmalloc_array(tps->dev,
- irq_count,
+ desc->num_ext_irqs,
sizeof(struct tps6594_ext_regulator_irq_data),
GFP_KERNEL);
if (!irq_ext_reg_data)
return -ENOMEM;
- for (i = 0; i < irq_count; ++i) {
- irq_type = &irq_types[i];
+ for (i = 0; i < desc->num_ext_irqs; ++i) {
+ irq_type = &desc->ext_irq_types[i];
irq = platform_get_irq_byname(pdev, irq_type->irq_name);
if (irq < 0)
return -EINVAL;
@@ -787,6 +825,7 @@ static int tps6594_regulator_probe(struct platform_device *pdev)
"failed to request %s IRQ %d\n",
irq_type->irq_name, irq);
}
+
return 0;
}