aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/power/regulator
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/power/regulator')
-rw-r--r--roms/u-boot/drivers/power/regulator/Kconfig373
-rw-r--r--roms/u-boot/drivers/power/regulator/Makefile34
-rw-r--r--roms/u-boot/drivers/power/regulator/act8846.c154
-rw-r--r--roms/u-boot/drivers/power/regulator/anatop_regulator.c278
-rw-r--r--roms/u-boot/drivers/power/regulator/as3722_regulator.c163
-rw-r--r--roms/u-boot/drivers/power/regulator/bd71837.c470
-rw-r--r--roms/u-boot/drivers/power/regulator/da9063.c389
-rw-r--r--roms/u-boot/drivers/power/regulator/fan53555.c245
-rw-r--r--roms/u-boot/drivers/power/regulator/fixed.c93
-rw-r--r--roms/u-boot/drivers/power/regulator/gpio-regulator.c159
-rw-r--r--roms/u-boot/drivers/power/regulator/lp873x_regulator.c354
-rw-r--r--roms/u-boot/drivers/power/regulator/lp87565_regulator.c197
-rw-r--r--roms/u-boot/drivers/power/regulator/max77686.c816
-rw-r--r--roms/u-boot/drivers/power/regulator/palmas_regulator.c490
-rw-r--r--roms/u-boot/drivers/power/regulator/pbias_regulator.c352
-rw-r--r--roms/u-boot/drivers/power/regulator/pfuze100.c576
-rw-r--r--roms/u-boot/drivers/power/regulator/pwm_regulator.c160
-rw-r--r--roms/u-boot/drivers/power/regulator/regulator-uclass.c542
-rw-r--r--roms/u-boot/drivers/power/regulator/regulator_common.c91
-rw-r--r--roms/u-boot/drivers/power/regulator/regulator_common.h26
-rw-r--r--roms/u-boot/drivers/power/regulator/rk8xx.c1158
-rw-r--r--roms/u-boot/drivers/power/regulator/s2mps11_regulator.c608
-rw-r--r--roms/u-boot/drivers/power/regulator/s5m8767.c266
-rw-r--r--roms/u-boot/drivers/power/regulator/sandbox.c352
-rw-r--r--roms/u-boot/drivers/power/regulator/scmi_regulator.c195
-rw-r--r--roms/u-boot/drivers/power/regulator/stm32-vrefbuf.c171
-rw-r--r--roms/u-boot/drivers/power/regulator/stpmic1.c674
-rw-r--r--roms/u-boot/drivers/power/regulator/tps62360_regulator.c124
-rw-r--r--roms/u-boot/drivers/power/regulator/tps65090_regulator.c139
-rw-r--r--roms/u-boot/drivers/power/regulator/tps65910_regulator.c459
-rw-r--r--roms/u-boot/drivers/power/regulator/tps65941_regulator.c409
31 files changed, 10517 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/power/regulator/Kconfig b/roms/u-boot/drivers/power/regulator/Kconfig
new file mode 100644
index 000000000..17942e299
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/Kconfig
@@ -0,0 +1,373 @@
+config DM_REGULATOR
+ bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)"
+ depends on DM
+ ---help---
+ This config enables the driver model regulator support.
+ UCLASS_REGULATOR - designed to provide a common API for basic regulator's
+ functions, like get/set Voltage or Current value, enable state, etc...
+ Note:
+ When enabling this, please read the description, found in the files:
+ - 'include/power/pmic.h'
+ - 'include/power/regulator.h'
+ - 'drivers/power/pmic/pmic-uclass.c'
+ - 'drivers/power/pmic/regulator-uclass.c'
+ It's important to call the device_bind() with the proper node offset,
+ when binding the regulator devices. The pmic_bind_childs() can be used
+ for this purpose if PMIC I/O driver is implemented or dm_scan_fdt_dev()
+ otherwise. Detailed information can be found in the header file.
+
+config SPL_DM_REGULATOR
+ bool "Enable regulators for SPL"
+ depends on DM_REGULATOR && SPL_POWER_SUPPORT
+ ---help---
+ Regulators are seldom needed in SPL. Even if they are accessed, some
+ code space can be saved by accessing the PMIC registers directly.
+ Enable this option if you need regulators in SPL and can cope with
+ the extra code size.
+
+config REGULATOR_ACT8846
+ bool "Enable driver for ACT8846 regulator"
+ depends on DM_REGULATOR && PMIC_ACT8846
+ ---help---
+ Enable support for the regulator functions of the ACT8846 PMIC. The
+ driver implements get/set api for the various BUCKS and LDOS supported
+ by the PMIC device. This driver is controlled by a device tree node
+ which includes voltage limits.
+
+config REGULATOR_AS3722
+ bool "Enable driver for AS7322 regulator"
+ depends on DM_REGULATOR && PMIC_AS3722
+ help
+ Enable support for the regulator functions of the AS3722. The
+ driver implements enable/disable for step-down bucks and LDOs,
+ but does not yet support change voltages. Currently this must be
+ done using direct register writes to the PMIC.
+
+config DM_REGULATOR_BD71837
+ bool "Enable Driver Model for ROHM BD71837/BD71847 regulators"
+ depends on DM_REGULATOR && DM_PMIC_BD71837
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for regulators on ROHM BD71837 and BD71847 PMICs.
+ BD71837 contains 8 bucks and 7 LDOS. BD71847 is reduced version
+ containing 6 bucks and 6 LDOs. The driver implements get/set api for
+ value and enable.
+
+config SPL_DM_REGULATOR_BD71837
+ bool "Enable Driver Model for ROHM BD71837/BD71847 regulators in SPL"
+ depends on DM_REGULATOR_BD71837
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for regulators on ROHM BD71837 and BD71847 in SPL.
+
+config DM_REGULATOR_DA9063
+ bool "Enable Driver Model for REGULATOR DA9063"
+ depends on DM_REGULATOR && DM_PMIC_DA9063
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for REGULATOR DA9063.
+ The driver implements get/set api for value, enable and mode for all
+ regulators. It also implements the get/set api for current for the
+ buck regulators.
+
+config SPL_DM_REGULATOR_DA9063
+ bool "Enable Driver Model for REGULATOR DA9063 in SPL"
+ depends on DM_REGULATOR && DM_PMIC_DA9063 && SPL
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for REGULATOR DA9063.
+ The driver implements get/set api for value, enable and mode for all
+ regulators. It also implements the get/set api for current for the
+ buck regulators.
+
+config DM_REGULATOR_PFUZE100
+ bool "Enable Driver Model for REGULATOR PFUZE100"
+ depends on DM_REGULATOR && DM_PMIC_PFUZE100
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for REGULATOR PFUZE100. The driver implements get/set api for:
+ value, enable and mode.
+
+config REGULATOR_PWM
+ bool "Enable driver for PWM regulators"
+ depends on DM_REGULATOR
+ ---help---
+ Enable support for the PWM regulator functions which voltage are
+ controlled by PWM duty ratio. Some of Rockchip board using this kind
+ of regulator. The driver implements get/set api for the various BUCKS.
+ This driver is controlled by a device tree node
+ which includes voltage limits.
+
+config SPL_REGULATOR_PWM
+ bool "Enable Driver for PWM regulators in SPL"
+ depends on REGULATOR_PWM
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for PWM regulators in SPL.
+
+config DM_REGULATOR_MAX77686
+ bool "Enable Driver Model for REGULATOR MAX77686"
+ depends on DM_REGULATOR && DM_PMIC_MAX77686
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for REGULATOR MAX77686. The driver implements get/set api for:
+ value, enable and mode.
+
+config DM_REGULATOR_FAN53555
+ bool "Enable Driver Model for REGULATOR FAN53555"
+ depends on DM_PMIC_FAN53555
+ help
+ This config enables implementation of driver-model regulator
+ uclass features for the FAN53555 regulator. The FAN53555 is
+ a (family of) single-output regulators that supports
+ transitioning between two different output voltages based on
+ an voltage selection pin.
+
+ The driver implements a get/set api for the voltage of the
+ 'normal mode' voltage only. Switching to 'suspend mode'
+ (i.e. the alternate voltage), disabling output via software,
+ or switching the mode is not supported by this driver (at
+ this time).
+
+config DM_REGULATOR_COMMON
+ bool
+ depends on DM_REGULATOR
+
+config SPL_DM_REGULATOR_COMMON
+ bool
+ depends on DM_REGULATOR
+
+config DM_REGULATOR_FIXED
+ bool "Enable Driver Model for REGULATOR Fixed value"
+ depends on DM_REGULATOR
+ select DM_REGULATOR_COMMON
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for fixed value regulators. The driver implements get/set api
+ for enable and get only for voltage value.
+
+config SPL_DM_REGULATOR_FIXED
+ bool "Enable Driver Model for REGULATOR Fixed value in SPL"
+ depends on DM_REGULATOR_FIXED
+ select SPL_DM_REGULATOR_COMMON
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for fixed value regulators in SPL.
+
+config DM_REGULATOR_GPIO
+ bool "Enable Driver Model for GPIO REGULATOR"
+ depends on DM_REGULATOR && DM_GPIO
+ select DM_REGULATOR_COMMON
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for gpio regulators. The driver implements get/set for
+ voltage value.
+
+config SPL_DM_REGULATOR_GPIO
+ bool "Enable Driver Model for GPIO REGULATOR in SPL"
+ depends on DM_REGULATOR_GPIO && SPL_GPIO_SUPPORT
+ select SPL_DM_REGULATOR_COMMON
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for gpio regulators in SPL.
+
+config REGULATOR_RK8XX
+ bool "Enable driver for RK8XX regulators"
+ depends on DM_REGULATOR && PMIC_RK8XX
+ ---help---
+ Enable support for the regulator functions of the RK8XX PMIC. The
+ driver implements get/set api for the various BUCKS and LDOs supported
+ by the PMIC device. This driver is controlled by a device tree node
+ which includes voltage limits.
+
+config DM_REGULATOR_S2MPS11
+ bool "Enable driver for S2MPS11 regulator"
+ depends on DM_REGULATOR && PMIC_S2MPS11
+ ---help---
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR S2MPS11.
+ The driver implements get/set api for: value and enable.
+
+config REGULATOR_S5M8767
+ bool "Enable support for S5M8767 regulator"
+ depends on DM_REGULATOR && PMIC_S5M8767
+ ---help---
+ This enables the regulator features of the S5M8767, allowing voltages
+ to be set, etc. The driver is not fully complete but supports most
+ common requirements, including all LDOs and BUCKs. This allows many
+ supplies to be set automatically using the device tree values.
+
+config DM_REGULATOR_SANDBOX
+ bool "Enable Driver Model for Sandbox PMIC regulator"
+ depends on DM_REGULATOR && DM_PMIC_SANDBOX
+ ---help---
+ Enable the regulator driver for emulated Sandbox PMIC.
+ The emulated PMIC device depends on two drivers:
+ - sandbox PMIC I/O driver - implements dm pmic operations
+ - sandbox PMIC regulator driver - implements dm regulator operations
+ - sandbox PMIC i2c emul driver - emulates the PMIC's I2C transmission
+
+ The regulator driver provides uclass operations for sandbox PMIC's
+ regulators. The driver implements get/set api for: voltage, current,
+ operation mode and enable state.
+ The driver supports LDO and BUCK regulators.
+
+ The Sandbox PMIC info:
+ * I/O interface:
+ - I2C chip address: 0x40
+ - first register address: 0x0
+ - register count: 0x10
+ * Adjustable outputs:
+ - 2x LDO
+ - 2x BUCK
+ - Each, with a different operating conditions (header).
+ * Reset values:
+ - set by i2c emul driver's probe() (defaults in header)
+
+ A detailed information can be found in header: '<power/sandbox_pmic.h>'
+ Binding info: 'doc/device-tree-bindings/pmic/max77686.txt'
+
+config REGULATOR_TPS65090
+ bool "Enable driver for TPS65090 PMIC regulators"
+ depends on PMIC_TPS65090
+ ---help---
+ The TPS65090 provides several FETs (Field-effect Transistors,
+ effectively switches) which are supported by this driver as
+ regulators, one for each FET. The standard regulator interface is
+ supported, but it is only possible to turn the regulators on or off.
+ There is no voltage/current control.
+
+config DM_REGULATOR_PALMAS
+ bool "Enable driver for PALMAS PMIC regulators"
+ depends on PMIC_PALMAS
+ ---help---
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR PALMAS and the family of PALMAS PMICs.
+ The driver implements get/set api for: value and enable.
+
+config DM_REGULATOR_PBIAS
+ bool "Enable driver for PBIAS regulator"
+ depends on DM_REGULATOR
+ select REGMAP
+ select SYSCON
+ ---help---
+ This enables implementation of driver-model regulator uclass
+ features for pseudo-regulator PBIAS found in the OMAP SOCs.
+ This pseudo-regulator is used to provide a BIAS voltage to MMC1
+ signal pads and must be configured properly during a voltage switch.
+ Voltage switching is required by some operating modes of SDcards and
+ eMMC.
+
+config DM_REGULATOR_LP873X
+ bool "Enable driver for LP873X PMIC regulators"
+ depends on PMIC_LP873X
+ ---help---
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR LP873X and the family of LP873X PMICs.
+ The driver implements get/set api for: value and enable.
+
+config DM_REGULATOR_LP87565
+ bool "Enable driver for LP87565 PMIC regulators"
+ depends on PMIC_LP87565
+ ---help---
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR LP87565 and the family of LP87565 PMICs.
+ LP87565 series of PMICs have 4 single phase BUCKs that can also
+ be configured in multi phase modes. The driver implements
+ get/set api for value and enable.
+
+config DM_REGULATOR_STM32_VREFBUF
+ bool "Enable driver for STMicroelectronics STM32 VREFBUF"
+ depends on DM_REGULATOR && (STM32H7 || ARCH_STM32MP)
+ help
+ This driver supports STMicroelectronics STM32 VREFBUF (voltage
+ reference buffer) which can be used as voltage reference for
+ internal ADCs, DACs and also for external components through
+ dedicated Vref+ pin.
+
+config DM_REGULATOR_TPS65910
+ bool "Enable driver for TPS65910 PMIC regulators"
+ depends on DM_PMIC_TPS65910
+ ---help---
+ The TPS65910 PMIC provides 4 SMPSs and 8 LDOs. This driver supports all
+ regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements
+ the get/set api for value and enable.
+
+config DM_REGULATOR_TPS62360
+ bool "Enable driver for TPS6236x Power Regulator"
+ depends on DM_REGULATOR
+ help
+ The TPS6236X DC/DC step down converter provides a single output
+ power line peaking at 3A current. This driver supports all four
+ variants of the chip (TPS62360, TPS62361, TPS62362, TPS62363). It
+ implements the get/set api for value only, as the power line is
+ always on.
+
+config DM_REGULATOR_STPMIC1
+ bool "Enable driver for STPMIC1 regulators"
+ depends on DM_REGULATOR && PMIC_STPMIC1
+ ---help---
+ Enable support for the regulator functions of the STPMIC1 PMIC. The
+ driver implements get/set api for the various BUCKS and LDOs supported
+ by the PMIC device. This driver is controlled by a device tree node
+ which includes voltage limits.
+
+config DM_REGULATOR_ANATOP
+ bool "Enable driver for ANATOP regulators"
+ depends on DM_REGULATOR
+ select REGMAP
+ select SYSCON
+ help
+ Enable support for the Freescale i.MX on-chip ANATOP LDO
+ regulators. It is recommended that this option be enabled on
+ i.MX6 platform.
+
+config SPL_DM_REGULATOR_STPMIC1
+ bool "Enable driver for STPMIC1 regulators in SPL"
+ depends on SPL_DM_REGULATOR && PMIC_STPMIC1
+ help
+ Enable support for the regulator functions of the STPMIC1 PMIC in SPL.
+
+config SPL_DM_REGULATOR_PALMAS
+ bool "Enable driver for PALMAS PMIC regulators"
+ depends on SPL_PMIC_PALMAS
+ help
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR PALMAS and the family of PALMAS PMICs.
+ The driver implements get/set api for: value and enable in SPL.
+
+config SPL_DM_REGULATOR_LP87565
+ bool "Enable driver for LP87565 PMIC regulators"
+ depends on SPL_PMIC_LP87565
+ help
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR LP87565 and the family of LP87565 PMICs.
+ LP87565 series of PMICs have 4 single phase BUCKs that can also
+ be configured in multi phase modes. The driver implements
+ get/set api for value and enable in SPL.
+
+config SPL_DM_REGULATOR_LP873X
+ bool "Enable driver for LP873X PMIC regulators"
+ depends on SPL_PMIC_LP873X
+ help
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR LP873X and the family of LP873X PMICs.
+ The driver implements get/set api for: value and enable in SPL.
+
+config DM_REGULATOR_TPS65941
+ bool "Enable driver for TPS65941 PMIC regulators"
+ depends on PMIC_TPS65941
+ help
+ This enables implementation of driver-model regulator uclass
+ features for REGULATOR TPS65941 and the family of TPS65941 PMICs.
+ TPS65941 series of PMICs have 5 single phase BUCKs that can also
+ be configured in multi phase modes & 4 LDOs. The driver implements
+ get/set api for value and enable.
+
+config DM_REGULATOR_SCMI
+ bool "Enable driver for SCMI voltage domain regulators"
+ depends on DM_REGULATOR
+ select SCMI_AGENT
+ help
+ Enable this option if you want to support regulators exposed through
+ the SCMI voltage domain protocol by a SCMI server.
diff --git a/roms/u-boot/drivers/power/regulator/Makefile b/roms/u-boot/drivers/power/regulator/Makefile
new file mode 100644
index 000000000..677134c82
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/Makefile
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2015 Samsung Electronics
+# Przemyslaw Marczak <p.marczak@samsung.com>
+#
+
+obj-$(CONFIG_$(SPL_)DM_REGULATOR) += regulator-uclass.o
+obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
+obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_DA9063) += da9063.o
+obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_BD71837) += bd71837.o
+obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
+obj-$(CONFIG_REGULATOR_RK8XX) += rk8xx.o
+obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o
+obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
+obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
+obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
+obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o
+obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
+obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_ANATOP) += anatop_regulator.o
diff --git a/roms/u-boot/drivers/power/regulator/act8846.c b/roms/u-boot/drivers/power/regulator/act8846.c
new file mode 100644
index 000000000..bdce97365
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/act8846.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * Based on Rockchip's drivers/power/pmic/pmic_act8846.c:
+ * Copyright (C) 2012 rockchips
+ * zyw <zyw@rock-chips.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <power/act8846_pmic.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+static const u16 voltage_map[] = {
+ 600, 625, 650, 675, 700, 725, 750, 775,
+ 800, 825, 850, 875, 900, 925, 950, 975,
+ 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+ 1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+ 1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+ 2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+ 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+ 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+enum {
+ REG_SYS0,
+ REG_SYS1,
+ REG1_VOL = 0x10,
+ REG1_CTL = 0X11,
+ REG2_VOL0 = 0x20,
+ REG2_VOL1,
+ REG2_CTL,
+ REG3_VOL0 = 0x30,
+ REG3_VOL1,
+ REG3_CTL,
+ REG4_VOL0 = 0x40,
+ REG4_VOL1,
+ REG4_CTL,
+ REG5_VOL = 0x50,
+ REG5_CTL,
+ REG6_VOL = 0X58,
+ REG6_CTL,
+ REG7_VOL = 0x60,
+ REG7_CTL,
+ REG8_VOL = 0x68,
+ REG8_CTL,
+ REG9_VOL = 0x70,
+ REG9_CTL,
+ REG10_VOL = 0x80,
+ REG10_CTL,
+ REG11_VOL = 0x90,
+ REG11_CTL,
+ REG12_VOL = 0xa0,
+ REG12_CTL,
+ REG13 = 0xb1,
+};
+
+static const u8 addr_vol[] = {
+ 0, REG1_VOL, REG2_VOL0, REG3_VOL0, REG4_VOL0,
+ REG5_VOL, REG6_VOL, REG7_VOL, REG8_VOL, REG9_VOL,
+ REG10_VOL, REG11_VOL, REG12_VOL,
+};
+
+static const u8 addr_ctl[] = {
+ 0, REG1_CTL, REG2_CTL, REG3_CTL, REG4_CTL,
+ REG5_CTL, REG6_CTL, REG7_CTL, REG8_CTL, REG9_CTL,
+ REG10_CTL, REG11_CTL, REG12_CTL,
+};
+
+static int check_volt_table(const u16 *volt_table, int uvolt)
+{
+ int i;
+
+ for (i = VOL_MIN_IDX; i < VOL_MAX_IDX; i++) {
+ if (uvolt <= (volt_table[i] * 1000))
+ return i;
+ }
+ return -EINVAL;
+}
+
+static int reg_get_value(struct udevice *dev)
+{
+ int reg = dev->driver_data;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, addr_vol[reg]);
+ if (ret < 0)
+ return ret;
+
+ return voltage_map[ret & LDO_VOL_MASK] * 1000;
+}
+
+static int reg_set_value(struct udevice *dev, int uvolt)
+{
+ int reg = dev->driver_data;
+ int val;
+
+ val = check_volt_table(voltage_map, uvolt);
+ if (val < 0)
+ return val;
+
+ return pmic_clrsetbits(dev->parent, addr_vol[reg], LDO_VOL_MASK, val);
+}
+
+static int reg_set_enable(struct udevice *dev, bool enable)
+{
+ int reg = dev->driver_data;
+
+ return pmic_clrsetbits(dev->parent, addr_ctl[reg], LDO_EN_MASK,
+ enable ? LDO_EN_MASK : 0);
+}
+
+static int reg_get_enable(struct udevice *dev)
+{
+ int reg = dev->driver_data;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, addr_ctl[reg]);
+ if (ret < 0)
+ return ret;
+
+ return ret & LDO_EN_MASK ? true : false;
+}
+
+static int act8846_reg_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int reg = dev->driver_data;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = reg <= 4 ? REGULATOR_TYPE_BUCK : REGULATOR_TYPE_LDO;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops act8846_reg_ops = {
+ .get_value = reg_get_value,
+ .set_value = reg_set_value,
+ .get_enable = reg_get_enable,
+ .set_enable = reg_set_enable,
+};
+
+U_BOOT_DRIVER(act8846_buck) = {
+ .name = "act8846_reg",
+ .id = UCLASS_REGULATOR,
+ .ops = &act8846_reg_ops,
+ .probe = act8846_reg_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/anatop_regulator.c b/roms/u-boot/drivers/power/regulator/anatop_regulator.c
new file mode 100644
index 000000000..096a1565d
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/anatop_regulator.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2021 Linaro
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
+#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
+
+#define LDO_POWER_GATE 0x00
+#define LDO_FET_FULL_ON 0x1f
+
+#define BIT_WIDTH_MAX 32
+
+#define ANATOP_REGULATOR_STEP 25000
+#define MIN_DROPOUT_UV 125000
+
+struct anatop_regulator {
+ const char *name;
+ struct regmap *regmap;
+ struct udevice *supply;
+ u32 control_reg;
+ u32 vol_bit_shift;
+ u32 vol_bit_width;
+ u32 min_bit_val;
+ u32 min_voltage;
+ u32 max_voltage;
+ u32 delay_reg;
+ u32 delay_bit_shift;
+ u32 delay_bit_width;
+};
+
+static u32 anatop_get_bits(struct udevice *dev, u32 addr, int bit_shift,
+ int bit_width)
+{
+ const struct anatop_regulator *anatop_reg = dev_get_plat(dev);
+ int err;
+ u32 val, mask;
+
+ if (bit_width == BIT_WIDTH_MAX)
+ mask = ~0;
+ else
+ mask = (1 << bit_width) - 1;
+
+ err = regmap_read(anatop_reg->regmap, addr, &val);
+ if (err) {
+ dev_dbg(dev, "cannot read reg (%d)\n", err);
+ return err;
+ }
+
+ val = (val >> bit_shift) & mask;
+
+ return val;
+}
+
+static int anatop_set_bits(struct udevice *dev, u32 addr, int bit_shift,
+ int bit_width, u32 data)
+{
+ const struct anatop_regulator *anatop_reg = dev_get_plat(dev);
+ int err;
+ u32 val, mask;
+
+ if (bit_width == 32)
+ mask = ~0;
+ else
+ mask = (1 << bit_width) - 1;
+
+ err = regmap_read(anatop_reg->regmap, addr, &val);
+ if (err) {
+ dev_dbg(dev, "cannot read reg (%d)\n", err);
+ return err;
+ }
+ val = val & ~(mask << bit_shift);
+ err = regmap_write(anatop_reg->regmap,
+ addr, (data << bit_shift) | val);
+ if (err) {
+ dev_dbg(dev, "cannot write reg (%d)\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int anatop_get_voltage(struct udevice *dev)
+{
+ const struct anatop_regulator *anatop_reg = dev_get_plat(dev);
+ u32 sel;
+ u32 val;
+
+ if (!anatop_reg->control_reg)
+ return -ENOSYS;
+
+ val = anatop_get_bits(dev,
+ anatop_reg->control_reg,
+ anatop_reg->vol_bit_shift,
+ anatop_reg->vol_bit_width);
+
+ sel = val - anatop_reg->min_bit_val;
+
+ return sel * ANATOP_REGULATOR_STEP + anatop_reg->min_voltage;
+}
+
+static int anatop_set_voltage(struct udevice *dev, int uV)
+{
+ const struct anatop_regulator *anatop_reg = dev_get_plat(dev);
+ u32 val;
+ u32 sel;
+ int ret;
+
+ dev_dbg(dev, "uv %d, min %d, max %d\n", uV, anatop_reg->min_voltage,
+ anatop_reg->max_voltage);
+
+ if (uV < anatop_reg->min_voltage)
+ return -EINVAL;
+
+ if (!anatop_reg->control_reg)
+ return -ENOSYS;
+
+ sel = DIV_ROUND_UP(uV - anatop_reg->min_voltage,
+ ANATOP_REGULATOR_STEP);
+ if (sel * ANATOP_REGULATOR_STEP + anatop_reg->min_voltage >
+ anatop_reg->max_voltage)
+ return -EINVAL;
+ val = anatop_reg->min_bit_val + sel;
+ dev_dbg(dev, "calculated val %d\n", val);
+
+ if (anatop_reg->supply) {
+ ret = regulator_set_value(anatop_reg->supply,
+ uV + MIN_DROPOUT_UV);
+ if (ret)
+ return ret;
+ }
+
+ ret = anatop_set_bits(dev,
+ anatop_reg->control_reg,
+ anatop_reg->vol_bit_shift,
+ anatop_reg->vol_bit_width,
+ val);
+
+ return ret;
+}
+
+static const struct dm_regulator_ops anatop_regulator_ops = {
+ .set_value = anatop_set_voltage,
+ .get_value = anatop_get_voltage,
+};
+
+static int anatop_regulator_probe(struct udevice *dev)
+{
+ struct anatop_regulator *anatop_reg;
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct udevice *syscon;
+ int ret = 0;
+ u32 val;
+
+ anatop_reg = dev_get_plat(dev);
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ anatop_reg->name = ofnode_read_string(dev_ofnode(dev),
+ "regulator-name");
+ if (!anatop_reg->name)
+ return log_msg_ret("regulator-name", -EINVAL);
+
+ ret = device_get_supply_regulator(dev, "vin-supply",
+ &anatop_reg->supply);
+ if (ret != -ENODEV) {
+ if (ret)
+ return log_msg_ret("get vin-supply", ret);
+
+ ret = regulator_set_enable(anatop_reg->supply, true);
+ if (ret)
+ return ret;
+ }
+
+ ret = dev_read_u32(dev,
+ "anatop-reg-offset",
+ &anatop_reg->control_reg);
+ if (ret)
+ return log_msg_ret("anatop-reg-offset", ret);
+
+ ret = dev_read_u32(dev,
+ "anatop-vol-bit-width",
+ &anatop_reg->vol_bit_width);
+ if (ret)
+ return log_msg_ret("anatop-vol-bit-width", ret);
+
+ ret = dev_read_u32(dev,
+ "anatop-vol-bit-shift",
+ &anatop_reg->vol_bit_shift);
+ if (ret)
+ return log_msg_ret("anatop-vol-bit-shift", ret);
+
+ ret = dev_read_u32(dev,
+ "anatop-min-bit-val",
+ &anatop_reg->min_bit_val);
+ if (ret)
+ return log_msg_ret("anatop-min-bit-val", ret);
+
+ ret = dev_read_u32(dev,
+ "anatop-min-voltage",
+ &anatop_reg->min_voltage);
+ if (ret)
+ return log_msg_ret("anatop-min-voltage", ret);
+
+ ret = dev_read_u32(dev,
+ "anatop-max-voltage",
+ &anatop_reg->max_voltage);
+ if (ret)
+ return log_msg_ret("anatop-max-voltage", ret);
+
+ /* read LDO ramp up setting, only for core reg */
+ dev_read_u32(dev, "anatop-delay-reg-offset",
+ &anatop_reg->delay_reg);
+ dev_read_u32(dev, "anatop-delay-bit-width",
+ &anatop_reg->delay_bit_width);
+ dev_read_u32(dev, "anatop-delay-bit-shift",
+ &anatop_reg->delay_bit_shift);
+
+ syscon = dev_get_parent(dev);
+ if (!syscon) {
+ dev_dbg(dev, "unable to find syscon device\n");
+ return -ENOENT;
+ }
+
+ anatop_reg->regmap = syscon_get_regmap(syscon);
+ if (IS_ERR(anatop_reg->regmap)) {
+ dev_dbg(dev, "unable to find regmap (%ld)\n",
+ PTR_ERR(anatop_reg->regmap));
+ return -ENOENT;
+ }
+
+ /* check whether need to care about LDO ramp up speed */
+ if (anatop_reg->delay_bit_width) {
+ /*
+ * the delay for LDO ramp up time is
+ * based on the register setting, we need
+ * to calculate how many steps LDO need to
+ * ramp up, and how much delay needed. (us)
+ */
+ val = anatop_get_bits(dev,
+ anatop_reg->delay_reg,
+ anatop_reg->delay_bit_shift,
+ anatop_reg->delay_bit_width);
+ uc_pdata->ramp_delay = (LDO_RAMP_UP_UNIT_IN_CYCLES << val)
+ / LDO_RAMP_UP_FREQ_IN_MHZ + 1;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id of_anatop_regulator_match_tbl[] = {
+ { .compatible = "fsl,anatop-regulator", },
+ { /* end */ }
+};
+
+U_BOOT_DRIVER(anatop_regulator) = {
+ .name = "anatop_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &anatop_regulator_ops,
+ .of_match = of_anatop_regulator_match_tbl,
+ .plat_auto = sizeof(struct anatop_regulator),
+ .probe = anatop_regulator_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/as3722_regulator.c b/roms/u-boot/drivers/power/regulator/as3722_regulator.c
new file mode 100644
index 000000000..ec0776b44
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/as3722_regulator.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * Placeholder regulator driver for as3722.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <power/as3722.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define AS3722_LDO_CONTROL0_MAX_INDEX 7
+
+static int stepdown_get_value(struct udevice *dev)
+{
+ return -ENOSYS;
+}
+
+static int stepdown_set_value(struct udevice *dev, int uvolt)
+{
+ return -ENOSYS;
+}
+
+static int stepdown_set_enable(struct udevice *dev, bool enable)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ int sd = dev->driver_data;
+ int ret;
+
+ ret = pmic_clrsetbits(pmic, AS3722_SD_CONTROL, 0, 1 << sd);
+ if (ret < 0) {
+ debug("%s: failed to write SD control register: %d", __func__,
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stepdown_get_enable(struct udevice *dev)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ int sd = dev->driver_data;
+ int ret;
+
+ ret = pmic_reg_read(pmic, AS3722_SD_CONTROL);
+ if (ret < 0) {
+ debug("%s: failed to read SD control register: %d", __func__,
+ ret);
+ return ret;
+ }
+
+ return ret & (1 << sd) ? true : false;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ return -ENOSYS;
+}
+
+static int ldo_set_value(struct udevice *dev, int uvolt)
+{
+ return -ENOSYS;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ u8 ctrl_reg = AS3722_LDO_CONTROL0;
+ int ldo = dev->driver_data;
+ int ret;
+
+ if (ldo > AS3722_LDO_CONTROL0_MAX_INDEX) {
+ ctrl_reg = AS3722_LDO_CONTROL1;
+ ldo -= 8;
+ }
+
+ ret = pmic_clrsetbits(pmic, ctrl_reg, !enable << ldo, enable << ldo);
+ if (ret < 0) {
+ debug("%s: failed to write LDO control register: %d", __func__,
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ u8 ctrl_reg = AS3722_LDO_CONTROL0;
+ int ldo = dev->driver_data;
+ int ret;
+
+ if (ldo > AS3722_LDO_CONTROL0_MAX_INDEX) {
+ ctrl_reg = AS3722_LDO_CONTROL1;
+ ldo -= 8;
+ }
+
+ ret = pmic_reg_read(pmic, ctrl_reg);
+ if (ret < 0) {
+ debug("%s: failed to read SD control register: %d", __func__,
+ ret);
+ return ret;
+ }
+
+ return ret & (1 << ldo) ? true : false;
+}
+
+static int as3722_stepdown_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ return 0;
+}
+
+static int as3722_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops as3722_stepdown_ops = {
+ .get_value = stepdown_get_value,
+ .set_value = stepdown_set_value,
+ .get_enable = stepdown_get_enable,
+ .set_enable = stepdown_set_enable,
+};
+
+static const struct dm_regulator_ops as3722_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+};
+
+U_BOOT_DRIVER(as3722_stepdown) = {
+ .name = "as3722_stepdown",
+ .id = UCLASS_REGULATOR,
+ .ops = &as3722_stepdown_ops,
+ .probe = as3722_stepdown_probe,
+};
+
+U_BOOT_DRIVER(as3722_ldo) = {
+ .name = "as3722_ldo",
+ .id = UCLASS_REGULATOR,
+ .ops = &as3722_ldo_ops,
+ .probe = as3722_ldo_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/bd71837.c b/roms/u-boot/drivers/power/regulator/bd71837.c
new file mode 100644
index 000000000..74011d629
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/bd71837.c
@@ -0,0 +1,470 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 ROHM Semiconductors
+ *
+ * ROHM BD71837 regulator driver
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <linux/bitops.h>
+#include <power/bd71837.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define HW_STATE_CONTROL 0
+#define DEBUG
+
+/**
+ * struct bd71837_vrange - describe linear range of voltages
+ *
+ * @min_volt: smallest voltage in range
+ * @step: how much voltage changes at each selector step
+ * @min_sel: smallest selector in the range
+ * @max_sel: maximum selector in the range
+ * @rangeval: register value used to select this range if selectible
+ * ranges are supported
+ */
+struct bd71837_vrange {
+ unsigned int min_volt;
+ unsigned int step;
+ u8 min_sel;
+ u8 max_sel;
+ u8 rangeval;
+};
+
+/**
+ * struct bd71837_plat - describe regulator control registers
+ *
+ * @name: name of the regulator. Used for matching the dt-entry
+ * @enable_reg: register address used to enable/disable regulator
+ * @enablemask: register mask used to enable/disable regulator
+ * @volt_reg: register address used to configure regulator voltage
+ * @volt_mask: register mask used to configure regulator voltage
+ * @ranges: pointer to ranges of regulator voltages and matching register
+ * values
+ * @numranges: number of voltage ranges pointed by ranges
+ * @rangemask: mask for selecting used ranges if multiple ranges are supported
+ * @sel_mask: bit to toggle in order to transfer the register control to SW
+ * @dvs: whether the voltage can be changed when regulator is enabled
+ */
+struct bd71837_plat {
+ const char *name;
+ u8 enable_reg;
+ u8 enablemask;
+ u8 volt_reg;
+ u8 volt_mask;
+ struct bd71837_vrange *ranges;
+ unsigned int numranges;
+ u8 rangemask;
+ u8 sel_mask;
+ bool dvs;
+};
+
+#define BD_RANGE(_min, _vstep, _sel_low, _sel_hi, _range_sel) \
+{ \
+ .min_volt = (_min), .step = (_vstep), .min_sel = (_sel_low), \
+ .max_sel = (_sel_hi), .rangeval = (_range_sel) \
+}
+
+#define BD_DATA(_name, enreg, enmask, vreg, vmask, _range, rmask, _dvs, sel) \
+{ \
+ .name = (_name), .enable_reg = (enreg), .enablemask = (enmask), \
+ .volt_reg = (vreg), .volt_mask = (vmask), .ranges = (_range), \
+ .numranges = ARRAY_SIZE(_range), .rangemask = (rmask), .dvs = (_dvs), \
+ .sel_mask = (sel) \
+}
+
+static struct bd71837_vrange dvs_buck_vranges[] = {
+ BD_RANGE(700000, 10000, 0, 0x3c, 0),
+ BD_RANGE(1300000, 0, 0x3d, 0x3f, 0),
+};
+
+static struct bd71837_vrange bd71847_buck3_vranges[] = {
+ BD_RANGE(700000, 100000, 0x00, 0x03, 0),
+ BD_RANGE(1050000, 50000, 0x04, 0x05, 0),
+ BD_RANGE(1200000, 150000, 0x06, 0x07, 0),
+ BD_RANGE(550000, 50000, 0x0, 0x7, 0x40),
+ BD_RANGE(675000, 100000, 0x0, 0x3, 0x80),
+ BD_RANGE(1025000, 50000, 0x4, 0x5, 0x80),
+ BD_RANGE(1175000, 150000, 0x6, 0x7, 0x80),
+};
+
+static struct bd71837_vrange bd71847_buck4_vranges[] = {
+ BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+ BD_RANGE(2600000, 100000, 0x00, 0x03, 40),
+};
+
+static struct bd71837_vrange bd71837_buck5_vranges[] = {
+ BD_RANGE(700000, 100000, 0, 0x3, 0),
+ BD_RANGE(1050000, 50000, 0x04, 0x05, 0),
+ BD_RANGE(1200000, 150000, 0x06, 0x07, 0),
+ BD_RANGE(675000, 100000, 0x0, 0x3, 0x80),
+ BD_RANGE(1025000, 50000, 0x04, 0x05, 0x80),
+ BD_RANGE(1175000, 150000, 0x06, 0x07, 0x80),
+};
+
+static struct bd71837_vrange bd71837_buck6_vranges[] = {
+ BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+};
+
+static struct bd71837_vrange nodvs_buck3_vranges[] = {
+ BD_RANGE(1605000, 90000, 0, 1, 0),
+ BD_RANGE(1755000, 45000, 2, 4, 0),
+ BD_RANGE(1905000, 45000, 5, 7, 0),
+};
+
+static struct bd71837_vrange nodvs_buck4_vranges[] = {
+ BD_RANGE(800000, 10000, 0x00, 0x3C, 0),
+};
+
+static struct bd71837_vrange ldo1_vranges[] = {
+ BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+ BD_RANGE(1600000, 100000, 0x00, 0x03, 0x20),
+};
+
+static struct bd71837_vrange ldo2_vranges[] = {
+ BD_RANGE(900000, 0, 0, 0, 0),
+ BD_RANGE(800000, 0, 1, 1, 0),
+};
+
+static struct bd71837_vrange ldo3_vranges[] = {
+ BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+static struct bd71837_vrange ldo4_vranges[] = {
+ BD_RANGE(900000, 100000, 0x00, 0x09, 0),
+};
+
+static struct bd71837_vrange bd71837_ldo5_vranges[] = {
+ BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+static struct bd71837_vrange bd71847_ldo5_vranges[] = {
+ BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+ BD_RANGE(800000, 100000, 0x00, 0x0f, 0x20),
+};
+
+static struct bd71837_vrange ldo6_vranges[] = {
+ BD_RANGE(900000, 100000, 0x00, 0x09, 0),
+};
+
+static struct bd71837_vrange ldo7_vranges[] = {
+ BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+/*
+ * We use enable mask 'HW_STATE_CONTROL' to indicate that this regulator
+ * must not be enabled or disabled by SW. The typical use-case for BD71837
+ * is powering NXP i.MX8. In this use-case we (for now) only allow control
+ * for BUCK3 and BUCK4 which are not boot critical.
+ */
+static struct bd71837_plat bd71837_reg_data[] = {
+/* Bucks 1-4 which support dynamic voltage scaling */
+ BD_DATA("BUCK1", BD718XX_BUCK1_CTRL, HW_STATE_CONTROL,
+ BD718XX_BUCK1_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK2", BD718XX_BUCK2_CTRL, HW_STATE_CONTROL,
+ BD718XX_BUCK2_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK3", BD71837_BUCK3_CTRL, BD718XX_BUCK_EN,
+ BD71837_BUCK3_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK4", BD71837_BUCK4_CTRL, BD718XX_BUCK_EN,
+ BD71837_BUCK4_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+/* Bucks 5-8 which do not support dynamic voltage scaling */
+ BD_DATA("BUCK5", BD718XX_1ST_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_1ST_NODVS_BUCK_VOLT, BD718XX_1ST_NODVS_BUCK_MASK,
+ bd71837_buck5_vranges, 0x80, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK6", BD718XX_2ND_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_2ND_NODVS_BUCK_VOLT, BD71837_BUCK6_MASK,
+ bd71837_buck6_vranges, 0, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK7", BD718XX_3RD_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_3RD_NODVS_BUCK_VOLT, BD718XX_3RD_NODVS_BUCK_MASK,
+ nodvs_buck3_vranges, 0, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK8", BD718XX_4TH_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_4TH_NODVS_BUCK_VOLT, BD718XX_4TH_NODVS_BUCK_MASK,
+ nodvs_buck4_vranges, 0, false, BD718XX_BUCK_SEL),
+/* LDOs */
+ BD_DATA("LDO1", BD718XX_LDO1_VOLT, HW_STATE_CONTROL, BD718XX_LDO1_VOLT,
+ BD718XX_LDO1_MASK, ldo1_vranges, 0x20, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO2", BD718XX_LDO2_VOLT, HW_STATE_CONTROL, BD718XX_LDO2_VOLT,
+ BD718XX_LDO2_MASK, ldo2_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO3", BD718XX_LDO3_VOLT, HW_STATE_CONTROL, BD718XX_LDO3_VOLT,
+ BD718XX_LDO3_MASK, ldo3_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO4", BD718XX_LDO4_VOLT, HW_STATE_CONTROL, BD718XX_LDO4_VOLT,
+ BD718XX_LDO4_MASK, ldo4_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO5", BD718XX_LDO5_VOLT, HW_STATE_CONTROL, BD718XX_LDO5_VOLT,
+ BD71837_LDO5_MASK, bd71837_ldo5_vranges, 0, false,
+ BD718XX_LDO_SEL),
+ BD_DATA("LDO6", BD718XX_LDO6_VOLT, HW_STATE_CONTROL, BD718XX_LDO6_VOLT,
+ BD718XX_LDO6_MASK, ldo6_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO7", BD71837_LDO7_VOLT, HW_STATE_CONTROL, BD71837_LDO7_VOLT,
+ BD71837_LDO7_MASK, ldo7_vranges, 0, false, BD718XX_LDO_SEL),
+};
+
+static struct bd71837_plat bd71847_reg_data[] = {
+/* Bucks 1 and 2 which support dynamic voltage scaling */
+ BD_DATA("BUCK1", BD718XX_BUCK1_CTRL, HW_STATE_CONTROL,
+ BD718XX_BUCK1_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK2", BD718XX_BUCK2_CTRL, HW_STATE_CONTROL,
+ BD718XX_BUCK2_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+/* Bucks 3-6 which do not support dynamic voltage scaling */
+ BD_DATA("BUCK3", BD718XX_1ST_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_1ST_NODVS_BUCK_VOLT, BD718XX_1ST_NODVS_BUCK_MASK,
+ bd71847_buck3_vranges, 0xc0, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK4", BD718XX_2ND_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_2ND_NODVS_BUCK_VOLT, BD71837_BUCK6_MASK,
+ bd71847_buck4_vranges, 0x40, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK5", BD718XX_3RD_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_3RD_NODVS_BUCK_VOLT, BD718XX_3RD_NODVS_BUCK_MASK,
+ nodvs_buck3_vranges, 0, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK6", BD718XX_4TH_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_4TH_NODVS_BUCK_VOLT, BD718XX_4TH_NODVS_BUCK_MASK,
+ nodvs_buck4_vranges, 0, false, BD718XX_BUCK_SEL),
+/* LDOs */
+ BD_DATA("LDO1", BD718XX_LDO1_VOLT, HW_STATE_CONTROL, BD718XX_LDO1_VOLT,
+ BD718XX_LDO1_MASK, ldo1_vranges, 0x20, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO2", BD718XX_LDO2_VOLT, HW_STATE_CONTROL, BD718XX_LDO2_VOLT,
+ BD718XX_LDO2_MASK, ldo2_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO3", BD718XX_LDO3_VOLT, HW_STATE_CONTROL, BD718XX_LDO3_VOLT,
+ BD718XX_LDO3_MASK, ldo3_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO4", BD718XX_LDO4_VOLT, HW_STATE_CONTROL, BD718XX_LDO4_VOLT,
+ BD718XX_LDO4_MASK, ldo4_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO5", BD718XX_LDO5_VOLT, HW_STATE_CONTROL, BD718XX_LDO5_VOLT,
+ BD71847_LDO5_MASK, bd71847_ldo5_vranges, 0x20, false,
+ BD718XX_LDO_SEL),
+ BD_DATA("LDO6", BD718XX_LDO6_VOLT, HW_STATE_CONTROL, BD718XX_LDO6_VOLT,
+ BD718XX_LDO6_MASK, ldo6_vranges, 0, false, BD718XX_LDO_SEL),
+};
+
+static int vrange_find_value(struct bd71837_vrange *r, unsigned int sel,
+ unsigned int *val)
+{
+ if (!val || sel < r->min_sel || sel > r->max_sel)
+ return -EINVAL;
+
+ *val = r->min_volt + r->step * (sel - r->min_sel);
+ return 0;
+}
+
+static int vrange_find_selector(struct bd71837_vrange *r, int val,
+ unsigned int *sel)
+{
+ int ret = -EINVAL;
+ int num_vals = r->max_sel - r->min_sel + 1;
+
+ if (val >= r->min_volt &&
+ val <= r->min_volt + r->step * (num_vals - 1)) {
+ if (r->step) {
+ *sel = r->min_sel + ((val - r->min_volt) / r->step);
+ ret = 0;
+ } else {
+ *sel = r->min_sel;
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int bd71837_get_enable(struct udevice *dev)
+{
+ int val;
+ struct bd71837_plat *plat = dev_get_plat(dev);
+
+ /*
+ * boot critical regulators on bd71837 must not be controlled by sw
+ * due to the 'feature' which leaves power rails down if bd71837 is
+ * reseted to snvs state. hence we can't get the state here.
+ *
+ * if we are alive it means we probably are on run state and
+ * if the regulator can't be controlled we can assume it is
+ * enabled.
+ */
+ if (plat->enablemask == HW_STATE_CONTROL)
+ return 1;
+
+ val = pmic_reg_read(dev->parent, plat->enable_reg);
+ if (val < 0)
+ return val;
+
+ return (val & plat->enablemask);
+}
+
+static int bd71837_set_enable(struct udevice *dev, bool enable)
+{
+ int val = 0;
+ struct bd71837_plat *plat = dev_get_plat(dev);
+
+ /*
+ * boot critical regulators on bd71837 must not be controlled by sw
+ * due to the 'feature' which leaves power rails down if bd71837 is
+ * reseted to snvs state. Hence we can't set the state here.
+ */
+ if (plat->enablemask == HW_STATE_CONTROL)
+ return -EINVAL;
+
+ if (enable)
+ val = plat->enablemask;
+
+ return pmic_clrsetbits(dev->parent, plat->enable_reg, plat->enablemask,
+ val);
+}
+
+static int bd71837_set_value(struct udevice *dev, int uvolt)
+{
+ unsigned int sel;
+ unsigned int range;
+ int i;
+ int found = 0;
+ struct bd71837_plat *plat = dev_get_plat(dev);
+
+ /*
+ * An under/overshooting may occur if voltage is changed for other
+ * regulators but buck 1,2,3 or 4 when regulator is enabled. Prevent
+ * change to protect the HW
+ */
+ if (!plat->dvs)
+ if (bd71837_get_enable(dev)) {
+ pr_err("Only DVS bucks can be changed when enabled\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < plat->numranges; i++) {
+ struct bd71837_vrange *r = &plat->ranges[i];
+
+ found = !vrange_find_selector(r, uvolt, &sel);
+ if (found) {
+ unsigned int tmp;
+
+ /*
+ * We require exactly the requested value to be
+ * supported - this can be changed later if needed
+ */
+ range = r->rangeval;
+ found = !vrange_find_value(r, sel, &tmp);
+ if (found && tmp == uvolt)
+ break;
+ found = 0;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ sel <<= ffs(plat->volt_mask) - 1;
+
+ if (plat->rangemask)
+ sel |= range;
+
+ return pmic_clrsetbits(dev->parent, plat->volt_reg, plat->volt_mask |
+ plat->rangemask, sel);
+}
+
+static int bd71837_get_value(struct udevice *dev)
+{
+ unsigned int reg, range;
+ unsigned int tmp;
+ struct bd71837_plat *plat = dev_get_plat(dev);
+ int i;
+
+ reg = pmic_reg_read(dev->parent, plat->volt_reg);
+ if (((int)reg) < 0)
+ return reg;
+
+ range = reg & plat->rangemask;
+
+ reg &= plat->volt_mask;
+ reg >>= ffs(plat->volt_mask) - 1;
+
+ for (i = 0; i < plat->numranges; i++) {
+ struct bd71837_vrange *r = &plat->ranges[i];
+
+ if (plat->rangemask && ((plat->rangemask & range) !=
+ r->rangeval))
+ continue;
+
+ if (!vrange_find_value(r, reg, &tmp))
+ return tmp;
+ }
+
+ pr_err("Unknown voltage value read from pmic\n");
+
+ return -EINVAL;
+}
+
+static int bd71837_regulator_probe(struct udevice *dev)
+{
+ struct bd71837_plat *plat = dev_get_plat(dev);
+ int i, ret;
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int type;
+ struct bd71837_plat *init_data;
+ int data_amnt;
+
+ type = dev_get_driver_data(dev_get_parent(dev));
+
+ switch (type) {
+ case ROHM_CHIP_TYPE_BD71837:
+ init_data = bd71837_reg_data;
+ data_amnt = ARRAY_SIZE(bd71837_reg_data);
+ break;
+ case ROHM_CHIP_TYPE_BD71847:
+ init_data = bd71847_reg_data;
+ data_amnt = ARRAY_SIZE(bd71847_reg_data);
+ break;
+ default:
+ debug("Unknown PMIC type\n");
+ init_data = NULL;
+ data_amnt = 0;
+ break;
+ }
+
+ for (i = 0; i < data_amnt; i++) {
+ if (!strcmp(dev->name, init_data[i].name)) {
+ *plat = init_data[i];
+ if (plat->enablemask != HW_STATE_CONTROL) {
+ /*
+ * Take the regulator under SW control. Ensure
+ * the initial state matches dt flags and then
+ * write the SEL bit
+ */
+ uc_pdata = dev_get_uclass_plat(dev);
+ ret = bd71837_set_enable(dev,
+ !!(uc_pdata->boot_on ||
+ uc_pdata->always_on));
+ if (ret)
+ return ret;
+
+ return pmic_clrsetbits(dev->parent,
+ plat->enable_reg,
+ plat->sel_mask,
+ plat->sel_mask);
+ }
+ return 0;
+ }
+ }
+
+ pr_err("Unknown regulator '%s'\n", dev->name);
+
+ return -ENOENT;
+}
+
+static const struct dm_regulator_ops bd71837_regulator_ops = {
+ .get_value = bd71837_get_value,
+ .set_value = bd71837_set_value,
+ .get_enable = bd71837_get_enable,
+ .set_enable = bd71837_set_enable,
+};
+
+U_BOOT_DRIVER(bd71837_regulator) = {
+ .name = BD718XX_REGULATOR_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &bd71837_regulator_ops,
+ .probe = bd71837_regulator_probe,
+ .plat_auto = sizeof(struct bd71837_plat),
+};
diff --git a/roms/u-boot/drivers/power/regulator/da9063.c b/roms/u-boot/drivers/power/regulator/da9063.c
new file mode 100644
index 000000000..8df1abcf7
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/da9063.c
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Flowbird
+ * Martin Fuzzey <martin.fuzzey@flowbird.group>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <linux/bitops.h>
+#include <power/da9063_pmic.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define DA9063_BUCK_EN 0x01
+#define DA9063_LDO_EN 0x01
+#define DA9063_VBUCK_MASK 0x7F
+#define DA9063_BUCK_SL 0x80
+#define DA9063_LDO_SL 0x80
+
+#define DA9063_VLDO1_MASK 0x3F
+#define DA9063_VLDO2_MASK 0x3F
+#define DA9063_VLDO3_MASK 0x7F
+#define DA9063_VLDO4_MASK 0x7F
+#define DA9063_VLDO5_MASK 0x3F
+#define DA9063_VLDO6_MASK 0x3F
+#define DA9063_VLDO7_MASK 0x3F
+#define DA9063_VLDO8_MASK 0x3F
+#define DA9063_VLDO9_MASK 0x3F
+#define DA9063_VLDO10_MASK 0x3F
+#define DA9063_VLDO11_MASK 0x3F
+
+#define DA9063_BUCK_MODE_MASK 0xC0
+#define DA9063_BUCK_MODE_MANUAL 0x00
+#define DA9063_BUCK_MODE_SLEEP 0x40
+#define DA9063_BUCK_MODE_SYNC 0x80
+#define DA9063_BUCK_MODE_AUTO 0xC0
+
+#define DA9063_BIO_ILIM_MASK 0x0F
+#define DA9063_BMEM_ILIM_MASK 0xF0
+#define DA9063_BPRO_ILIM_MASK 0x0F
+#define DA9063_BPERI_ILIM_MASK 0xF0
+#define DA9063_BCORE1_ILIM_MASK 0x0F
+#define DA9063_BCORE2_ILIM_MASK 0xF0
+
+struct da9063_reg_info {
+ uint min_uV;
+ uint step_uV;
+ uint max_uV;
+ uint min_uA;
+ uint step_uA;
+ uint max_uA;
+ uint en_reg;
+ uint vsel_reg;
+ uint mode_reg;
+ uint ilim_reg;
+ u8 en_mask;
+ u8 vsel_mask;
+ u8 ilim_mask;
+ const char *dt_node_name;
+ const int *current_limits;
+};
+
+struct da9063_priv {
+ const struct da9063_reg_info *reg_info;
+};
+
+static struct dm_regulator_mode da9063_ldo_modes[] = {
+ { .id = DA9063_LDOMODE_SLEEP,
+ .register_value = DA9063_LDO_SL, .name = "SLEEP" },
+ { .id = DA9063_LDOMODE_NORMAL,
+ .register_value = 0, .name = "NORMAL" },
+};
+
+#define DA9063_LDO(regl_name, min_mV, step_mV, max_mV) \
+ .min_uV = (min_mV) * 1000, \
+ .step_uV = (step_mV) * 1000, \
+ .max_uV = (max_mV) * 1000, \
+ .en_reg = DA9063_REG_##regl_name##_CONT, \
+ .en_mask = DA9063_LDO_EN, \
+ .vsel_reg = DA9063_REG_V##regl_name##_A, \
+ .vsel_mask = DA9063_V##regl_name##_MASK, \
+ .mode_reg = DA9063_REG_V##regl_name##_A \
+
+/* This array is directly indexed so must stay in numerical order */
+static const struct da9063_reg_info da9063_ldo_info[] = {
+ { DA9063_LDO(LDO1, 600, 20, 1860) },
+ { DA9063_LDO(LDO2, 600, 20, 1860) },
+ { DA9063_LDO(LDO3, 900, 20, 3440) },
+ { DA9063_LDO(LDO4, 900, 20, 3440) },
+ { DA9063_LDO(LDO5, 900, 50, 3600) },
+ { DA9063_LDO(LDO6, 900, 50, 3600) },
+ { DA9063_LDO(LDO7, 900, 50, 3600) },
+ { DA9063_LDO(LDO8, 900, 50, 3600) },
+ { DA9063_LDO(LDO9, 950, 50, 3600) },
+ { DA9063_LDO(LDO10, 900, 50, 3600) },
+ { DA9063_LDO(LDO11, 900, 50, 3600) },
+};
+
+static struct dm_regulator_mode da9063_buck_modes[] = {
+ { .id = DA9063_BUCKMODE_SLEEP,
+ .register_value = DA9063_BUCK_MODE_SLEEP, .name = "SLEEP" },
+ { .id = DA9063_BUCKMODE_SYNC,
+ .register_value = DA9063_BUCK_MODE_SYNC, .name = "SYNC" },
+ { .id = DA9063_BUCKMODE_AUTO,
+ .register_value = DA9063_BUCK_MODE_AUTO, .name = "AUTO" },
+};
+
+#define DA9063_BUCK(regl_name, dt_name, \
+ min_mV, step_mV, max_mV, \
+ min_mA, step_mA, max_mA, _ilim_reg) \
+ .dt_node_name = dt_name, \
+ .min_uV = (min_mV) * 1000, \
+ .step_uV = (step_mV) * 1000, \
+ .max_uV = (max_mV) * 1000, \
+ .min_uA = (min_mA) * 1000, \
+ .step_uA = (step_mA) * 1000, \
+ .max_uA = (max_mA) * 1000, \
+ .en_reg = DA9063_REG_##regl_name##_CONT, \
+ .en_mask = DA9063_BUCK_EN, \
+ .vsel_reg = DA9063_REG_V##regl_name##_A, \
+ .vsel_mask = DA9063_VBUCK_MASK, \
+ .mode_reg = DA9063_REG_##regl_name##_CFG, \
+ .ilim_reg = DA9063_REG_BUCK_ILIM_##_ilim_reg, \
+ .ilim_mask = DA9063_##regl_name##_ILIM_MASK
+
+static const struct da9063_reg_info da9063_buck_info[] = {
+ /* mV mA */
+ { DA9063_BUCK(BCORE1, "bcore1", 300, 10, 1570, 500, 100, 2000, C) },
+ { DA9063_BUCK(BCORE2, "bcore2", 300, 10, 1570, 500, 100, 2000, C) },
+ { DA9063_BUCK(BPRO, "bpro", 530, 10, 1800, 500, 100, 2000, B) },
+ { DA9063_BUCK(BMEM, "bmem", 800, 20, 3340, 1500, 100, 3000, A) },
+ { DA9063_BUCK(BIO, "bio", 800, 20, 3340, 1500, 100, 3000, A) },
+ { DA9063_BUCK(BPERI, "bperi", 800, 20, 3340, 1500, 100, 3000, B) },
+};
+
+static int da9063_get_enable(struct udevice *dev)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, info->en_reg);
+ if (ret < 0)
+ return ret;
+
+ return ret & info->en_mask ? true : false;
+}
+
+static int da9063_set_enable(struct udevice *dev, bool enable)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+
+ return pmic_clrsetbits(dev->parent, info->en_reg,
+ info->en_mask, enable ? info->en_mask : 0);
+}
+
+static int da9063_get_voltage(struct udevice *dev)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, info->vsel_reg);
+ if (ret < 0)
+ return ret;
+
+ return info->min_uV + (ret & info->vsel_mask) * info->step_uV;
+}
+
+static int da9063_set_voltage(struct udevice *dev, int uV)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ uint sel;
+
+ if (uV < info->min_uV || uV > info->max_uV)
+ return -EINVAL;
+
+ sel = (uV - info->min_uV) / info->step_uV;
+
+ return pmic_clrsetbits(dev->parent, info->vsel_reg,
+ info->vsel_mask, sel);
+}
+
+static const struct dm_regulator_mode
+ *da9063_find_mode_by_id(int id,
+ const struct dm_regulator_mode *modes,
+ uint mode_count)
+{
+ for (; mode_count; mode_count--) {
+ if (modes->id == id)
+ return modes;
+ modes++;
+ }
+ return NULL;
+}
+
+static int ldo_get_mode(struct udevice *dev)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ int val;
+
+ val = pmic_reg_read(dev->parent, info->mode_reg);
+ if (val < 0)
+ return val;
+
+ if (val & DA9063_LDO_SL)
+ return DA9063_LDOMODE_SLEEP;
+ else
+ return DA9063_LDOMODE_NORMAL;
+}
+
+static int ldo_set_mode(struct udevice *dev, int mode_id)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ const struct dm_regulator_mode *mode;
+
+ mode = da9063_find_mode_by_id(mode_id,
+ da9063_ldo_modes,
+ ARRAY_SIZE(da9063_ldo_modes));
+ if (!mode)
+ return -EINVAL;
+
+ return pmic_clrsetbits(dev->parent, info->mode_reg,
+ DA9063_LDO_SL, mode->register_value);
+}
+
+static int buck_get_mode(struct udevice *dev)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ int i;
+ int val;
+
+ val = pmic_reg_read(dev->parent, info->mode_reg);
+ if (val < 0)
+ return val;
+
+ val &= DA9063_BUCK_MODE_MASK;
+ if (val == DA9063_BUCK_MODE_MANUAL) {
+ val = pmic_reg_read(dev->parent, info->vsel_reg);
+ if (val < 0)
+ return val;
+
+ if (val & DA9063_BUCK_SL)
+ return DA9063_BUCKMODE_SLEEP;
+ else
+ return DA9063_BUCKMODE_SYNC;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(da9063_buck_modes); i++) {
+ if (da9063_buck_modes[i].register_value == val)
+ return da9063_buck_modes[i].id;
+ }
+
+ return -EINVAL;
+}
+
+static int buck_set_mode(struct udevice *dev, int mode_id)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ const struct dm_regulator_mode *mode;
+
+ mode = da9063_find_mode_by_id(mode_id,
+ da9063_buck_modes,
+ ARRAY_SIZE(da9063_buck_modes));
+ if (!mode)
+ return -EINVAL;
+
+ return pmic_clrsetbits(dev->parent, info->mode_reg,
+ DA9063_BUCK_MODE_MASK, mode->register_value);
+}
+
+static int buck_get_current_limit(struct udevice *dev)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ int val;
+
+ val = pmic_reg_read(dev->parent, info->ilim_reg);
+ if (val < 0)
+ return val;
+
+ val &= info->ilim_mask;
+ val >>= (ffs(info->ilim_mask) - 1);
+
+ return info->min_uA + val * info->step_uA;
+}
+
+static int buck_set_current_limit(struct udevice *dev, int uA)
+{
+ const struct da9063_priv *priv = dev_get_priv(dev);
+ const struct da9063_reg_info *info = priv->reg_info;
+ int val;
+
+ if (uA < info->min_uA || uA > info->max_uA)
+ return -EINVAL;
+
+ val = (uA - info->min_uA) / info->step_uA;
+ val <<= (ffs(info->ilim_mask) - 1);
+
+ return pmic_clrsetbits(dev->parent, info->ilim_reg,
+ info->ilim_mask, val);
+}
+
+static int da9063_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct da9063_priv *priv = dev_get_priv(dev);
+
+ /* LDOs are named numerically in DT so can directly index */
+ if (dev->driver_data < 1 ||
+ dev->driver_data > ARRAY_SIZE(da9063_ldo_info))
+ return -EINVAL;
+ priv->reg_info = &da9063_ldo_info[dev->driver_data - 1];
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode = da9063_ldo_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(da9063_ldo_modes);
+
+ return 0;
+}
+
+static int da9063_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct da9063_priv *priv = dev_get_priv(dev);
+ int i;
+
+ /* Bucks have names rather than numbers so need to match with DT */
+ for (i = 0; i < ARRAY_SIZE(da9063_buck_info); i++) {
+ const struct da9063_reg_info *info = &da9063_buck_info[i];
+
+ if (!strcmp(info->dt_node_name, dev->name)) {
+ priv->reg_info = info;
+ break;
+ }
+ }
+ if (!priv->reg_info)
+ return -ENODEV;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode = da9063_buck_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(da9063_buck_modes);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops da9063_ldo_ops = {
+ .get_value = da9063_get_voltage,
+ .set_value = da9063_set_voltage,
+ .get_enable = da9063_get_enable,
+ .set_enable = da9063_set_enable,
+ .get_mode = ldo_get_mode,
+ .set_mode = ldo_set_mode,
+};
+
+U_BOOT_DRIVER(da9063_ldo) = {
+ .name = DA9063_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &da9063_ldo_ops,
+ .probe = da9063_ldo_probe,
+ .priv_auto = sizeof(struct da9063_priv),
+};
+
+static const struct dm_regulator_ops da9063_buck_ops = {
+ .get_value = da9063_get_voltage,
+ .set_value = da9063_set_voltage,
+ .get_enable = da9063_get_enable,
+ .set_enable = da9063_set_enable,
+ .get_mode = buck_get_mode,
+ .set_mode = buck_set_mode,
+ .get_current = buck_get_current_limit,
+ .set_current = buck_set_current_limit,
+};
+
+U_BOOT_DRIVER(da9063_buck) = {
+ .name = DA9063_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &da9063_buck_ops,
+ .probe = da9063_buck_probe,
+ .priv_auto = sizeof(struct da9063_priv),
+};
diff --git a/roms/u-boot/drivers/power/regulator/fan53555.c b/roms/u-boot/drivers/power/regulator/fan53555.c
new file mode 100644
index 000000000..9d8a235b7
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/fan53555.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) 2018 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <bitfield.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+#include <power/fan53555.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+/**
+ * struct ic_types - definition of fan53555-family devices
+ *
+ * @die_id: Identifies the DIE_ID (lower nibble of the ID1 register)
+ * @die_rev: Identifies the DIE_REV (lower nibble of the ID2 register)
+ * @vsel_min: starting voltage (step 0) in uV
+ * @vsel_step: increment of the voltage in uV
+ *
+ * The voltage ramp (i.e. minimum voltage and step) is selected from the
+ * combination of 2 nibbles: DIE_ID and DIE_REV.
+ *
+ * See http://www.onsemi.com/pub/Collateral/FAN53555-D.pdf for details.
+ */
+static const struct {
+ unsigned int vendor;
+ u8 die_id;
+ u8 die_rev;
+ bool check_rev;
+ u32 vsel_min;
+ u32 vsel_step;
+} ic_types[] = {
+ /* Option 00 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x0, 0x3, true, 600000, 10000 },
+ /* Option 13 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x0, 0xf, true, 800000, 10000 },
+ /* Option 23 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x0, 0xc, true, 600000, 12500 },
+ /* Option 01 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x1, 0x3, true, 600000, 10000 },
+ /* Option 03 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x3, 0x3, true, 600000, 10000 },
+ /* Option 04 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x4, 0xf, true, 603000, 12826 },
+ /* Option 05 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x5, 0x3, true, 600000, 10000 },
+ /* Option 08 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x8, 0x1, true, 600000, 10000 },
+ /* Option 08 */
+ { FAN53555_VENDOR_FAIRCHILD, 0x8, 0xf, true, 600000, 10000 },
+ /* Option 09 */
+ { FAN53555_VENDOR_FAIRCHILD, 0xc, 0xf, true, 603000, 12826 },
+ /* SYL82X */
+ { FAN53555_VENDOR_SILERGY, 0x8, 0x0, false, 712500, 12500 },
+ /* SYL83X */
+ { FAN53555_VENDOR_SILERGY, 0x9, 0x0, false, 712500, 12500 },
+};
+
+/* I2C-accessible byte-sized registers */
+enum {
+ /* Voltage setting */
+ FAN53555_VSEL0 = 0x00,
+ FAN53555_VSEL1,
+ /* Control register */
+ FAN53555_CONTROL,
+ /* IC Type */
+ FAN53555_ID1,
+ /* IC mask version */
+ FAN53555_ID2,
+ /* Monitor register */
+ FAN53555_MONITOR,
+};
+
+struct fan53555_plat {
+ /* Voltage setting register */
+ unsigned int vol_reg;
+ unsigned int sleep_reg;
+
+};
+
+struct fan53555_priv {
+ /* IC Vendor */
+ unsigned int vendor;
+ /* IC Type and Rev */
+ unsigned int die_id;
+ unsigned int die_rev;
+ /* Voltage range and step(linear) */
+ unsigned int vsel_min;
+ unsigned int vsel_step;
+ /* Voltage slew rate limiting */
+ unsigned int slew_rate;
+ /* Sleep voltage cache */
+ unsigned int sleep_vol_cache;
+};
+
+static int fan53555_regulator_of_to_plat(struct udevice *dev)
+{
+ struct fan53555_plat *dev_pdata = dev_get_plat(dev);
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 sleep_vsel;
+
+ /* This is a buck regulator */
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ sleep_vsel = dev_read_u32_default(dev, "fcs,suspend-voltage-selector",
+ FAN53555_VSEL1);
+
+ /*
+ * Depending on the device-tree settings, the 'normal mode'
+ * voltage is either controlled by VSEL0 or VSEL1.
+ */
+ switch (sleep_vsel) {
+ case FAN53555_VSEL0:
+ dev_pdata->sleep_reg = FAN53555_VSEL0;
+ dev_pdata->vol_reg = FAN53555_VSEL1;
+ break;
+ case FAN53555_VSEL1:
+ dev_pdata->sleep_reg = FAN53555_VSEL1;
+ dev_pdata->vol_reg = FAN53555_VSEL0;
+ break;
+ default:
+ pr_err("%s: invalid vsel id %d\n", dev->name, sleep_vsel);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fan53555_regulator_get_value(struct udevice *dev)
+{
+ struct fan53555_plat *pdata = dev_get_plat(dev);
+ struct fan53555_priv *priv = dev_get_priv(dev);
+ int reg;
+ int voltage;
+
+ /* We only support a single voltage selector (i.e. 'normal' mode). */
+ reg = pmic_reg_read(dev->parent, pdata->vol_reg);
+ if (reg < 0)
+ return reg;
+ voltage = priv->vsel_min + (reg & 0x3f) * priv->vsel_step;
+
+ debug("%s: %d uV\n", __func__, voltage);
+ return voltage;
+}
+
+static int fan53555_regulator_set_value(struct udevice *dev, int uV)
+{
+ struct fan53555_plat *pdata = dev_get_plat(dev);
+ struct fan53555_priv *priv = dev_get_priv(dev);
+ u8 vol;
+
+ vol = (uV - priv->vsel_min) / priv->vsel_step;
+ debug("%s: uV=%d; writing volume %d: %02x\n",
+ __func__, uV, pdata->vol_reg, vol);
+
+ return pmic_clrsetbits(dev->parent, pdata->vol_reg, GENMASK(6, 0), vol);
+}
+
+static int fan53555_voltages_setup(struct udevice *dev)
+{
+ struct fan53555_priv *priv = dev_get_priv(dev);
+ int i;
+
+ /* Init voltage range and step */
+ for (i = 0; i < ARRAY_SIZE(ic_types); ++i) {
+ if (ic_types[i].vendor != priv->vendor)
+ continue;
+
+ if (ic_types[i].die_id != priv->die_id)
+ continue;
+
+ if (ic_types[i].check_rev &&
+ ic_types[i].die_rev != priv->die_rev)
+ continue;
+
+ priv->vsel_min = ic_types[i].vsel_min;
+ priv->vsel_step = ic_types[i].vsel_step;
+
+ return 0;
+ }
+
+ pr_err("%s: %s: die id %d rev %d not supported!\n",
+ dev->name, __func__, priv->die_id, priv->die_rev);
+ return -EINVAL;
+}
+
+enum {
+ DIE_ID_SHIFT = 0,
+ DIE_ID_WIDTH = 4,
+ DIE_REV_SHIFT = 0,
+ DIE_REV_WIDTH = 4,
+};
+
+static int fan53555_probe(struct udevice *dev)
+{
+ struct fan53555_priv *priv = dev_get_priv(dev);
+ int ID1, ID2;
+
+ debug("%s\n", __func__);
+
+ /* read chip ID1 and ID2 (two registers, starting at ID1) */
+ ID1 = pmic_reg_read(dev->parent, FAN53555_ID1);
+ if (ID1 < 0)
+ return ID1;
+
+ ID2 = pmic_reg_read(dev->parent, FAN53555_ID2);
+ if (ID2 < 0)
+ return ID2;
+
+ /* extract vendor, die_id and die_rev */
+ priv->vendor = dev->driver_data;
+ priv->die_id = ID1 & GENMASK(3, 0);
+ priv->die_rev = ID2 & GENMASK(3, 0);
+
+ if (fan53555_voltages_setup(dev) < 0)
+ return -ENODATA;
+
+ debug("%s: FAN53555 option %d rev %d detected\n",
+ __func__, priv->die_id, priv->die_rev);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops fan53555_regulator_ops = {
+ .get_value = fan53555_regulator_get_value,
+ .set_value = fan53555_regulator_set_value,
+};
+
+U_BOOT_DRIVER(fan53555_regulator) = {
+ .name = "fan53555_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &fan53555_regulator_ops,
+ .of_to_plat = fan53555_regulator_of_to_plat,
+ .plat_auto = sizeof(struct fan53555_plat),
+ .priv_auto = sizeof(struct fan53555_priv),
+ .probe = fan53555_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/fixed.c b/roms/u-boot/drivers/power/regulator/fixed.c
new file mode 100644
index 000000000..d3e0fb672
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/fixed.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ *
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#include "regulator_common.h"
+
+static int fixed_regulator_of_to_plat(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct regulator_common_plat *dev_pdata;
+
+ dev_pdata = dev_get_plat(dev);
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata)
+ return -ENXIO;
+
+ uc_pdata->type = REGULATOR_TYPE_FIXED;
+
+ return regulator_common_of_to_plat(dev, dev_pdata, "gpio");
+}
+
+static int fixed_regulator_get_value(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata)
+ return -ENXIO;
+
+ if (uc_pdata->min_uV != uc_pdata->max_uV) {
+ debug("Invalid constraints for: %s\n", uc_pdata->name);
+ return -EINVAL;
+ }
+
+ return uc_pdata->min_uV;
+}
+
+static int fixed_regulator_get_current(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata)
+ return -ENXIO;
+
+ if (uc_pdata->min_uA != uc_pdata->max_uA) {
+ debug("Invalid constraints for: %s\n", uc_pdata->name);
+ return -EINVAL;
+ }
+
+ return uc_pdata->min_uA;
+}
+
+static int fixed_regulator_get_enable(struct udevice *dev)
+{
+ return regulator_common_get_enable(dev, dev_get_plat(dev));
+}
+
+static int fixed_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ return regulator_common_set_enable(dev, dev_get_plat(dev), enable);
+}
+
+static const struct dm_regulator_ops fixed_regulator_ops = {
+ .get_value = fixed_regulator_get_value,
+ .get_current = fixed_regulator_get_current,
+ .get_enable = fixed_regulator_get_enable,
+ .set_enable = fixed_regulator_set_enable,
+};
+
+static const struct udevice_id fixed_regulator_ids[] = {
+ { .compatible = "regulator-fixed" },
+ { },
+};
+
+U_BOOT_DRIVER(regulator_fixed) = {
+ .name = "regulator_fixed",
+ .id = UCLASS_REGULATOR,
+ .ops = &fixed_regulator_ops,
+ .of_match = fixed_regulator_ids,
+ .of_to_plat = fixed_regulator_of_to_plat,
+ .plat_auto = sizeof(struct regulator_common_plat),
+};
diff --git a/roms/u-boot/drivers/power/regulator/gpio-regulator.c b/roms/u-boot/drivers/power/regulator/gpio-regulator.c
new file mode 100644
index 000000000..e5e08a33d
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/gpio-regulator.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
+ * Keerthy <j-keerthy@ti.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/gpio.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#include "regulator_common.h"
+
+#define GPIO_REGULATOR_MAX_STATES 2
+
+struct gpio_regulator_plat {
+ struct regulator_common_plat common;
+ struct gpio_desc gpio; /* GPIO for regulator voltage control */
+ int states[GPIO_REGULATOR_MAX_STATES];
+ int voltages[GPIO_REGULATOR_MAX_STATES];
+};
+
+static int gpio_regulator_of_to_plat(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct gpio_regulator_plat *dev_pdata;
+ struct gpio_desc *gpio;
+ int ret, count, i, j;
+ u32 states_array[GPIO_REGULATOR_MAX_STATES * 2];
+
+ dev_pdata = dev_get_plat(dev);
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata)
+ return -ENXIO;
+
+ /* Set type to gpio */
+ uc_pdata->type = REGULATOR_TYPE_GPIO;
+
+ /*
+ * Get gpio regulator gpio desc
+ * Assuming one GPIO per regulator.
+ * Can be extended later to multiple GPIOs
+ * per gpio-regulator. As of now no instance with multiple
+ * gpios is presnt
+ */
+ gpio = &dev_pdata->gpio;
+ ret = gpio_request_by_name(dev, "gpios", 0, gpio, GPIOD_IS_OUT);
+ if (ret)
+ debug("regulator gpio - not found! Error: %d", ret);
+
+ ret = dev_read_size(dev, "states");
+ if (ret < 0)
+ return ret;
+
+ count = ret / sizeof(states_array[0]);
+ if (count > ARRAY_SIZE(states_array)) {
+ debug("regulator gpio - to many states (%d > %d)",
+ count / 2, GPIO_REGULATOR_MAX_STATES);
+ count = ARRAY_SIZE(states_array);
+ }
+
+ ret = dev_read_u32_array(dev, "states", states_array, count);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0, j = 0; i < count; i += 2) {
+ dev_pdata->voltages[j] = states_array[i];
+ dev_pdata->states[j] = states_array[i + 1];
+ j++;
+ }
+
+ return regulator_common_of_to_plat(dev, &dev_pdata->common, "enable-gpios");
+}
+
+static int gpio_regulator_get_value(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct gpio_regulator_plat *dev_pdata = dev_get_plat(dev);
+ int enable;
+
+ if (!dev_pdata->gpio.dev)
+ return -ENOSYS;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (uc_pdata->min_uV > uc_pdata->max_uV) {
+ debug("Invalid constraints for: %s\n", uc_pdata->name);
+ return -EINVAL;
+ }
+
+ enable = dm_gpio_get_value(&dev_pdata->gpio);
+ if (enable == dev_pdata->states[0])
+ return dev_pdata->voltages[0];
+ else
+ return dev_pdata->voltages[1];
+}
+
+static int gpio_regulator_set_value(struct udevice *dev, int uV)
+{
+ struct gpio_regulator_plat *dev_pdata = dev_get_plat(dev);
+ int ret;
+ bool enable;
+
+ if (!dev_pdata->gpio.dev)
+ return -ENOSYS;
+
+ if (uV == dev_pdata->voltages[0])
+ enable = dev_pdata->states[0];
+ else if (uV == dev_pdata->voltages[1])
+ enable = dev_pdata->states[1];
+ else
+ return -EINVAL;
+
+ ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
+ if (ret) {
+ pr_err("Can't set regulator : %s gpio to: %d\n", dev->name,
+ enable);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int gpio_regulator_get_enable(struct udevice *dev)
+{
+ struct gpio_regulator_plat *dev_pdata = dev_get_plat(dev);
+ return regulator_common_get_enable(dev, &dev_pdata->common);
+}
+
+static int gpio_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ struct gpio_regulator_plat *dev_pdata = dev_get_plat(dev);
+ return regulator_common_set_enable(dev, &dev_pdata->common, enable);
+}
+
+static const struct dm_regulator_ops gpio_regulator_ops = {
+ .get_value = gpio_regulator_get_value,
+ .set_value = gpio_regulator_set_value,
+ .get_enable = gpio_regulator_get_enable,
+ .set_enable = gpio_regulator_set_enable,
+};
+
+static const struct udevice_id gpio_regulator_ids[] = {
+ { .compatible = "regulator-gpio" },
+ { },
+};
+
+U_BOOT_DRIVER(gpio_regulator) = {
+ .name = "gpio regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &gpio_regulator_ops,
+ .of_match = gpio_regulator_ids,
+ .of_to_plat = gpio_regulator_of_to_plat,
+ .plat_auto = sizeof(struct gpio_regulator_plat),
+};
diff --git a/roms/u-boot/drivers/power/regulator/lp873x_regulator.c b/roms/u-boot/drivers/power/regulator/lp873x_regulator.c
new file mode 100644
index 000000000..ec1037d7a
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/lp873x_regulator.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Keerthy <j-keerthy@ti.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/lp873x.h>
+
+static const char lp873x_buck_ctrl[LP873X_BUCK_NUM] = {0x2, 0x4};
+static const char lp873x_buck_volt[LP873X_BUCK_NUM] = {0x6, 0x7};
+static const char lp873x_ldo_ctrl[LP873X_LDO_NUM] = {0x8, 0x9};
+static const char lp873x_ldo_volt[LP873X_LDO_NUM] = {0xA, 0xB};
+
+static int lp873x_buck_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= LP873X_BUCK_MODE_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= LP873X_BUCK_MODE_MASK;
+ else
+ ret &= ~(LP873X_BUCK_MODE_MASK);
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int lp873x_buck_volt2hex(int uV)
+{
+ if (uV > LP873X_BUCK_VOLT_MAX)
+ return -EINVAL;
+ else if (uV > 1400000)
+ return (uV - 1420000) / 20000 + 0x9E;
+ else if (uV > 730000)
+ return (uV - 735000) / 5000 + 0x18;
+ else if (uV >= 700000)
+ return (uV - 700000) / 10000 + 0x1;
+ else
+ return -EINVAL;
+}
+
+static int lp873x_buck_hex2volt(int hex)
+{
+ if (hex > LP873X_BUCK_VOLT_MAX_HEX)
+ return -EINVAL;
+ else if (hex > 0x9D)
+ return 1400000 + (hex - 0x9D) * 20000;
+ else if (hex > 0x17)
+ return 730000 + (hex - 0x17) * 5000;
+ else if (hex >= 0x14)
+ return 700000 + (hex - 0x14) * 10000;
+ else
+ return -EINVAL;
+}
+
+static int lp873x_buck_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= LP873X_BUCK_VOLT_MASK;
+ ret = lp873x_buck_hex2volt(ret);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+
+ return 0;
+ }
+
+ hex = lp873x_buck_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= 0x0;
+ ret |= hex;
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+
+ return ret;
+}
+
+static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= LP873X_LDO_MODE_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= LP873X_LDO_MODE_MASK;
+ else
+ ret &= ~(LP873X_LDO_MODE_MASK);
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int lp873x_ldo_volt2hex(int uV)
+{
+ if (uV > LP873X_LDO_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - 800000) / 100000;
+}
+
+static int lp873x_ldo_hex2volt(int hex)
+{
+ if (hex > LP873X_LDO_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (!hex)
+ return 0;
+
+ return (hex * 100000) + 800000;
+}
+
+static int lp873x_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= LP873X_LDO_VOLT_MASK;
+ ret = lp873x_ldo_hex2volt(ret);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+ return 0;
+ }
+
+ hex = lp873x_ldo_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= ~LP873X_LDO_VOLT_MASK;
+ ret |= hex;
+ if (*uV > 1650000)
+ ret |= 0x80;
+ ret = pmic_reg_write(dev->parent, adr, ret);
+
+ return ret;
+}
+
+static int lp873x_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+
+ int idx = dev->driver_data;
+ if (idx >= LP873X_LDO_NUM) {
+ printf("Wrong ID for regulator\n");
+ return -1;
+ }
+
+ uc_pdata->ctrl_reg = lp873x_ldo_ctrl[idx];
+ uc_pdata->volt_reg = lp873x_ldo_volt[idx];
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = lp873x_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return lp873x_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = lp873x_ldo_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ return lp873x_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int lp873x_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int idx;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ idx = dev->driver_data;
+ if (idx >= LP873X_BUCK_NUM) {
+ printf("Wrong ID for regulator\n");
+ return -1;
+ }
+
+ uc_pdata->ctrl_reg = lp873x_buck_ctrl[idx];
+ uc_pdata->volt_reg = lp873x_buck_volt[idx];
+
+ return 0;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = lp873x_buck_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int buck_set_value(struct udevice *dev, int uV)
+{
+ return lp873x_buck_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+
+ ret = lp873x_buck_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ return lp873x_buck_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops lp873x_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+};
+
+U_BOOT_DRIVER(lp873x_ldo) = {
+ .name = LP873X_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &lp873x_ldo_ops,
+ .probe = lp873x_ldo_probe,
+};
+
+static const struct dm_regulator_ops lp873x_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+};
+
+U_BOOT_DRIVER(lp873x_buck) = {
+ .name = LP873X_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &lp873x_buck_ops,
+ .probe = lp873x_buck_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/lp87565_regulator.c b/roms/u-boot/drivers/power/regulator/lp87565_regulator.c
new file mode 100644
index 000000000..7214dc1b8
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/lp87565_regulator.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Keerthy <j-keerthy@ti.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/lp87565.h>
+
+static const char lp87565_buck_ctrl1[LP87565_BUCK_NUM] = {0x2, 0x4, 0x6, 0x8, 0x2, 0x6};
+static const char lp87565_buck_vout[LP87565_BUCK_NUM] = {0xA, 0xC, 0xE, 0x10, 0xA, 0xE };
+
+static int lp87565_buck_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= LP87565_BUCK_MODE_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= LP87565_BUCK_MODE_MASK;
+ else
+ ret &= ~LP87565_BUCK_MODE_MASK;
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int lp87565_buck_volt2val(int uV)
+{
+ if (uV > LP87565_BUCK_VOLT_MAX)
+ return -EINVAL;
+ else if (uV > 1400000)
+ return (uV - 1420000) / 20000 + 0x9E;
+ else if (uV > 730000)
+ return (uV - 735000) / 5000 + 0x18;
+ else if (uV >= 500000)
+ return (uV - 500000) / 10000;
+ else
+ return -EINVAL;
+}
+
+static int lp87565_buck_val2volt(int val)
+{
+ if (val > LP87565_BUCK_VOLT_MAX_HEX)
+ return -EINVAL;
+ else if (val > 0x9D)
+ return 1400000 + (val - 0x9D) * 20000;
+ else if (val > 0x17)
+ return 730000 + (val - 0x17) * 5000;
+ else if (val >= 0x0)
+ return 500000 + val * 10000;
+ else
+ return -EINVAL;
+}
+
+static int lp87565_buck_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= LP87565_BUCK_VOLT_MASK;
+ ret = lp87565_buck_val2volt(ret);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+
+ return 0;
+ }
+
+ hex = lp87565_buck_volt2val(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= 0x0;
+ ret = hex;
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+
+ return ret;
+}
+
+static int lp87565_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int idx;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ idx = dev->driver_data;
+ if (idx == 0 || idx == 1 || idx == 2 || idx == 3) {
+ debug("Single phase regulator\n");
+ } else if (idx == 23) {
+ idx = 5;
+ } else if (idx == 10) {
+ idx = 4;
+ } else {
+ printf("Wrong ID for regulator\n");
+ return -EINVAL;
+ }
+
+ uc_pdata->ctrl_reg = lp87565_buck_ctrl1[idx];
+ uc_pdata->volt_reg = lp87565_buck_vout[idx];
+
+ return 0;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = lp87565_buck_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int buck_set_value(struct udevice *dev, int uV)
+{
+ return lp87565_buck_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+
+ ret = lp87565_buck_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ return lp87565_buck_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops lp87565_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+};
+
+U_BOOT_DRIVER(lp87565_buck) = {
+ .name = LP87565_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &lp87565_buck_ops,
+ .probe = lp87565_buck_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/max77686.c b/roms/u-boot/drivers/power/regulator/max77686.c
new file mode 100644
index 000000000..f05d791b7
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/max77686.c
@@ -0,0 +1,816 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012-2015 Samsung Electronics
+ *
+ * Rajeshwari Shinde <rajeshwari.s@samsung.com>
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/max77686_pmic.h>
+
+#define MODE(_id, _val, _name) { \
+ .id = _id, \
+ .register_value = _val, \
+ .name = _name, \
+}
+
+/* LDO: 1,3,4,5,9,17,18,19,20,21,22,23,24,26,26,27 */
+static struct dm_regulator_mode max77686_ldo_mode_standby1[] = {
+ MODE(OPMODE_OFF, MAX77686_LDO_MODE_OFF, "OFF"),
+ MODE(OPMODE_LPM, MAX77686_LDO_MODE_LPM, "LPM"),
+ MODE(OPMODE_STANDBY_LPM, MAX77686_LDO_MODE_STANDBY_LPM, "ON/LPM"),
+ MODE(OPMODE_ON, MAX77686_LDO_MODE_ON, "ON"),
+};
+
+/* LDO: 2,6,7,8,10,11,12,14,15,16 */
+static struct dm_regulator_mode max77686_ldo_mode_standby2[] = {
+ MODE(OPMODE_OFF, MAX77686_LDO_MODE_OFF, "OFF"),
+ MODE(OPMODE_STANDBY, MAX77686_LDO_MODE_STANDBY, "ON/OFF"),
+ MODE(OPMODE_STANDBY_LPM, MAX77686_LDO_MODE_STANDBY_LPM, "ON/LPM"),
+ MODE(OPMODE_ON, MAX77686_LDO_MODE_ON, "ON"),
+};
+
+/* Buck: 1 */
+static struct dm_regulator_mode max77686_buck_mode_standby[] = {
+ MODE(OPMODE_OFF, MAX77686_BUCK_MODE_OFF, "OFF"),
+ MODE(OPMODE_STANDBY, MAX77686_BUCK_MODE_STANDBY, "ON/OFF"),
+ MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"),
+};
+
+/* Buck: 2,3,4 */
+static struct dm_regulator_mode max77686_buck_mode_lpm[] = {
+ MODE(OPMODE_OFF, MAX77686_BUCK_MODE_OFF, "OFF"),
+ MODE(OPMODE_STANDBY, MAX77686_BUCK_MODE_STANDBY, "ON/OFF"),
+ MODE(OPMODE_LPM, MAX77686_BUCK_MODE_LPM, "LPM"),
+ MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"),
+};
+
+/* Buck: 5,6,7,8,9 */
+static struct dm_regulator_mode max77686_buck_mode_onoff[] = {
+ MODE(OPMODE_OFF, MAX77686_BUCK_MODE_OFF, "OFF"),
+ MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"),
+};
+
+static const char max77686_buck_ctrl[] = {
+ 0xff, 0x10, 0x12, 0x1c, 0x26, 0x30, 0x32, 0x34, 0x36, 0x38
+};
+
+static const char max77686_buck_out[] = {
+ 0xff, 0x11, 0x14, 0x1e, 0x28, 0x31, 0x33, 0x35, 0x37, 0x39
+};
+
+static int max77686_buck_volt2hex(int buck, int uV)
+{
+ int hex = 0;
+ int hex_max = 0;
+
+ switch (buck) {
+ case 2:
+ case 3:
+ case 4:
+ /* hex = (uV - 600000) / 12500; */
+ hex = (uV - MAX77686_BUCK_UV_LMIN) / MAX77686_BUCK_UV_LSTEP;
+ hex_max = MAX77686_BUCK234_VOLT_MAX_HEX;
+ break;
+ default:
+ /*
+ * hex = (uV - 750000) / 50000. We assume that dynamic voltage
+ * scaling via GPIOs is not enabled and don't support that.
+ * If this is enabled then the driver will need to take that
+ * into account and check different registers depending on
+ * the current setting. See the datasheet for details.
+ */
+ hex = (uV - MAX77686_BUCK_UV_HMIN) / MAX77686_BUCK_UV_HSTEP;
+ hex_max = MAX77686_BUCK_VOLT_MAX_HEX;
+ break;
+ }
+
+ if (hex >= 0 && hex <= hex_max)
+ return hex;
+
+ pr_err("Value: %d uV is wrong for BUCK%d", uV, buck);
+ return -EINVAL;
+}
+
+static int max77686_buck_hex2volt(int buck, int hex)
+{
+ unsigned uV = 0;
+ int hex_max = 0;
+
+ if (hex < 0)
+ goto bad_hex;
+
+ switch (buck) {
+ case 2:
+ case 3:
+ case 4:
+ hex_max = MAX77686_BUCK234_VOLT_MAX_HEX;
+ if (hex > hex_max)
+ goto bad_hex;
+
+ /* uV = hex * 12500 + 600000; */
+ uV = hex * MAX77686_BUCK_UV_LSTEP + MAX77686_BUCK_UV_LMIN;
+ break;
+ default:
+ hex_max = MAX77686_BUCK_VOLT_MAX_HEX;
+ if (hex > hex_max)
+ goto bad_hex;
+
+ /* uV = hex * 50000 + 750000; */
+ uV = hex * MAX77686_BUCK_UV_HSTEP + MAX77686_BUCK_UV_HMIN;
+ break;
+ }
+
+ return uV;
+
+bad_hex:
+ pr_err("Value: %#x is wrong for BUCK%d", hex, buck);
+ return -EINVAL;
+}
+
+static int max77686_ldo_volt2hex(int ldo, int uV)
+{
+ int hex = 0;
+
+ switch (ldo) {
+ case 1:
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 15:
+ hex = (uV - MAX77686_LDO_UV_MIN) / MAX77686_LDO_UV_LSTEP;
+ /* hex = (uV - 800000) / 25000; */
+ break;
+ default:
+ hex = (uV - MAX77686_LDO_UV_MIN) / MAX77686_LDO_UV_HSTEP;
+ /* hex = (uV - 800000) / 50000; */
+ }
+
+ if (hex >= 0 && hex <= MAX77686_LDO_VOLT_MAX_HEX)
+ return hex;
+
+ pr_err("Value: %d uV is wrong for LDO%d", uV, ldo);
+ return -EINVAL;
+}
+
+static int max77686_ldo_hex2volt(int ldo, int hex)
+{
+ unsigned int uV = 0;
+
+ if (hex > MAX77686_LDO_VOLT_MAX_HEX)
+ goto bad_hex;
+
+ switch (ldo) {
+ case 1:
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 15:
+ /* uV = hex * 25000 + 800000; */
+ uV = hex * MAX77686_LDO_UV_LSTEP + MAX77686_LDO_UV_MIN;
+ break;
+ default:
+ /* uV = hex * 50000 + 800000; */
+ uV = hex * MAX77686_LDO_UV_HSTEP + MAX77686_LDO_UV_MIN;
+ }
+
+ return uV;
+
+bad_hex:
+ pr_err("Value: %#x is wrong for ldo%d", hex, ldo);
+ return -EINVAL;
+}
+
+static int max77686_ldo_hex2mode(int ldo, int hex)
+{
+ if (hex > MAX77686_LDO_MODE_MASK)
+ return -EINVAL;
+
+ switch (hex) {
+ case MAX77686_LDO_MODE_OFF:
+ return OPMODE_OFF;
+ case MAX77686_LDO_MODE_LPM: /* == MAX77686_LDO_MODE_STANDBY: */
+ /* The same mode values but different meaning for each ldo */
+ switch (ldo) {
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ case 16:
+ return OPMODE_STANDBY;
+ default:
+ return OPMODE_LPM;
+ }
+ case MAX77686_LDO_MODE_STANDBY_LPM:
+ return OPMODE_STANDBY_LPM;
+ case MAX77686_LDO_MODE_ON:
+ return OPMODE_ON;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max77686_buck_hex2mode(int buck, int hex)
+{
+ if (hex > MAX77686_BUCK_MODE_MASK)
+ return -EINVAL;
+
+ switch (hex) {
+ case MAX77686_BUCK_MODE_OFF:
+ return OPMODE_OFF;
+ case MAX77686_BUCK_MODE_ON:
+ return OPMODE_ON;
+ case MAX77686_BUCK_MODE_STANDBY:
+ switch (buck) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return OPMODE_STANDBY;
+ default:
+ return -EINVAL;
+ }
+ case MAX77686_BUCK_MODE_LPM:
+ switch (buck) {
+ case 2:
+ case 3:
+ case 4:
+ return OPMODE_LPM;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max77686_buck_modes(int buck, struct dm_regulator_mode **modesp)
+{
+ int ret = -EINVAL;
+
+ if (buck < 1 || buck > MAX77686_BUCK_NUM)
+ return ret;
+
+ switch (buck) {
+ case 1:
+ *modesp = max77686_buck_mode_standby;
+ ret = ARRAY_SIZE(max77686_buck_mode_standby);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ *modesp = max77686_buck_mode_lpm;
+ ret = ARRAY_SIZE(max77686_buck_mode_lpm);
+ break;
+ default:
+ *modesp = max77686_buck_mode_onoff;
+ ret = ARRAY_SIZE(max77686_buck_mode_onoff);
+ }
+
+ return ret;
+}
+
+static int max77686_ldo_modes(int ldo, struct dm_regulator_mode **modesp,
+ struct udevice *dev)
+{
+ int ret = -EINVAL;
+
+ if (ldo < 1 || ldo > MAX77686_LDO_NUM)
+ return ret;
+
+ switch (ldo) {
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ case 16:
+ *modesp = max77686_ldo_mode_standby2;
+ ret = ARRAY_SIZE(max77686_ldo_mode_standby2);
+ break;
+ default:
+ *modesp = max77686_ldo_mode_standby1;
+ ret = ARRAY_SIZE(max77686_ldo_mode_standby1);
+ }
+
+ return ret;
+}
+
+static int max77686_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int adr;
+ unsigned char val;
+ int hex, ldo, ret;
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ ldo = dev->driver_data;
+ if (ldo < 1 || ldo > MAX77686_LDO_NUM) {
+ pr_err("Wrong ldo number: %d", ldo);
+ return -EINVAL;
+ }
+
+ adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1;
+
+ ret = pmic_read(dev->parent, adr, &val, 1);
+ if (ret)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ val &= MAX77686_LDO_VOLT_MASK;
+ ret = max77686_ldo_hex2volt(ldo, val);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+ return 0;
+ }
+
+ hex = max77686_ldo_volt2hex(ldo, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~MAX77686_LDO_VOLT_MASK;
+ val |= hex;
+ ret = pmic_write(dev->parent, adr, &val, 1);
+
+ return ret;
+}
+
+static int max77686_buck_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int mask, adr;
+ unsigned char val;
+ int hex, buck, ret;
+
+ buck = dev->driver_data;
+ if (buck < 1 || buck > MAX77686_BUCK_NUM) {
+ pr_err("Wrong buck number: %d", buck);
+ return -EINVAL;
+ }
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ /* &buck_out = ctrl + 1 */
+ adr = max77686_buck_out[buck];
+
+ /* mask */
+ switch (buck) {
+ case 2:
+ case 3:
+ case 4:
+ mask = MAX77686_BUCK234_VOLT_MASK;
+ break;
+ default:
+ mask = MAX77686_BUCK_VOLT_MASK;
+ break;
+ }
+
+ ret = pmic_read(dev->parent, adr, &val, 1);
+ if (ret)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ val &= mask;
+ ret = max77686_buck_hex2volt(buck, val);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+ return 0;
+ }
+
+ hex = max77686_buck_volt2hex(buck, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~mask;
+ val |= hex;
+ ret = pmic_write(dev->parent, adr, &val, 1);
+
+ return ret;
+}
+
+static int max77686_ldo_mode(struct udevice *dev, int op, int *opmode)
+{
+ unsigned int adr, mode;
+ unsigned char val;
+ int ldo, ret;
+
+ if (op == PMIC_OP_GET)
+ *opmode = -EINVAL;
+
+ ldo = dev->driver_data;
+ if (ldo < 1 || ldo > MAX77686_LDO_NUM) {
+ pr_err("Wrong ldo number: %d", ldo);
+ return -EINVAL;
+ }
+
+ adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1;
+
+ ret = pmic_read(dev->parent, adr, &val, 1);
+ if (ret)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ val &= MAX77686_LDO_MODE_MASK;
+ ret = max77686_ldo_hex2mode(ldo, val);
+ if (ret < 0)
+ return ret;
+ *opmode = ret;
+ return 0;
+ }
+
+ /* mode */
+ switch (*opmode) {
+ case OPMODE_OFF:
+ mode = MAX77686_LDO_MODE_OFF;
+ break;
+ case OPMODE_LPM:
+ switch (ldo) {
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ case 16:
+ return -EINVAL;
+ default:
+ mode = MAX77686_LDO_MODE_LPM;
+ }
+ break;
+ case OPMODE_STANDBY:
+ switch (ldo) {
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ case 16:
+ mode = MAX77686_LDO_MODE_STANDBY;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case OPMODE_STANDBY_LPM:
+ mode = MAX77686_LDO_MODE_STANDBY_LPM;
+ break;
+ case OPMODE_ON:
+ mode = MAX77686_LDO_MODE_ON;
+ break;
+ default:
+ mode = 0xff;
+ }
+
+ if (mode == 0xff) {
+ pr_err("Wrong mode: %d for ldo%d", *opmode, ldo);
+ return -EINVAL;
+ }
+
+ val &= ~MAX77686_LDO_MODE_MASK;
+ val |= mode;
+ ret = pmic_write(dev->parent, adr, &val, 1);
+
+ return ret;
+}
+
+static int max77686_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret, on_off;
+
+ if (op == PMIC_OP_GET) {
+ ret = max77686_ldo_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+
+ switch (on_off) {
+ case OPMODE_OFF:
+ *enable = false;
+ break;
+ case OPMODE_ON:
+ *enable = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ on_off = OPMODE_ON;
+ else
+ on_off = OPMODE_OFF;
+
+ ret = max77686_ldo_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max77686_buck_mode(struct udevice *dev, int op, int *opmode)
+{
+ unsigned int mask, adr, mode, mode_shift;
+ unsigned char val;
+ int buck, ret;
+
+ buck = dev->driver_data;
+ if (buck < 1 || buck > MAX77686_BUCK_NUM) {
+ pr_err("Wrong buck number: %d", buck);
+ return -EINVAL;
+ }
+
+ adr = max77686_buck_ctrl[buck];
+
+ /* mask */
+ switch (buck) {
+ case 2:
+ case 3:
+ case 4:
+ mode_shift = MAX77686_BUCK_MODE_SHIFT_2;
+ break;
+ default:
+ mode_shift = MAX77686_BUCK_MODE_SHIFT_1;
+ }
+
+ mask = MAX77686_BUCK_MODE_MASK << mode_shift;
+
+ ret = pmic_read(dev->parent, adr, &val, 1);
+ if (ret)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ val &= mask;
+ val >>= mode_shift;
+ ret = max77686_buck_hex2mode(buck, val);
+ if (ret < 0)
+ return ret;
+ *opmode = ret;
+ return 0;
+ }
+
+ /* mode */
+ switch (*opmode) {
+ case OPMODE_OFF:
+ mode = MAX77686_BUCK_MODE_OFF;
+ break;
+ case OPMODE_STANDBY:
+ switch (buck) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ mode = MAX77686_BUCK_MODE_STANDBY << mode_shift;
+ break;
+ default:
+ mode = 0xff;
+ }
+ break;
+ case OPMODE_LPM:
+ switch (buck) {
+ case 2:
+ case 3:
+ case 4:
+ mode = MAX77686_BUCK_MODE_LPM << mode_shift;
+ break;
+ default:
+ mode = 0xff;
+ }
+ break;
+ case OPMODE_ON:
+ mode = MAX77686_BUCK_MODE_ON << mode_shift;
+ break;
+ default:
+ mode = 0xff;
+ }
+
+ if (mode == 0xff) {
+ pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck);
+ return -EINVAL;
+ }
+
+ val &= ~mask;
+ val |= mode;
+ ret = pmic_write(dev->parent, adr, &val, 1);
+
+ return ret;
+}
+
+static int max77686_buck_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret, on_off;
+
+ if (op == PMIC_OP_GET) {
+ ret = max77686_buck_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+
+ switch (on_off) {
+ case OPMODE_OFF:
+ *enable = false;
+ break;
+ case OPMODE_ON:
+ *enable = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ on_off = OPMODE_ON;
+ else
+ on_off = OPMODE_OFF;
+
+ ret = max77686_buck_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max77686_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode_count = max77686_ldo_modes(dev->driver_data,
+ &uc_pdata->mode, dev);
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = max77686_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return max77686_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = max77686_ldo_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ return max77686_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int ldo_get_mode(struct udevice *dev)
+{
+ int mode;
+ int ret;
+
+ ret = max77686_ldo_mode(dev, PMIC_OP_GET, &mode);
+ if (ret)
+ return ret;
+
+ return mode;
+}
+
+static int ldo_set_mode(struct udevice *dev, int mode)
+{
+ return max77686_ldo_mode(dev, PMIC_OP_SET, &mode);
+}
+
+static int max77686_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode_count = max77686_buck_modes(dev->driver_data,
+ &uc_pdata->mode);
+
+ return 0;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = max77686_buck_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int buck_set_value(struct udevice *dev, int uV)
+{
+ return max77686_buck_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = max77686_buck_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ return max77686_buck_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int buck_get_mode(struct udevice *dev)
+{
+ int mode;
+ int ret;
+
+ ret = max77686_buck_mode(dev, PMIC_OP_GET, &mode);
+ if (ret)
+ return ret;
+
+ return mode;
+}
+
+static int buck_set_mode(struct udevice *dev, int mode)
+{
+ return max77686_buck_mode(dev, PMIC_OP_SET, &mode);
+}
+
+static const struct dm_regulator_ops max77686_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+ .get_mode = ldo_get_mode,
+ .set_mode = ldo_set_mode,
+};
+
+U_BOOT_DRIVER(max77686_ldo) = {
+ .name = MAX77686_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &max77686_ldo_ops,
+ .probe = max77686_ldo_probe,
+};
+
+static const struct dm_regulator_ops max77686_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+ .get_mode = buck_get_mode,
+ .set_mode = buck_set_mode,
+};
+
+U_BOOT_DRIVER(max77686_buck) = {
+ .name = MAX77686_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &max77686_buck_ops,
+ .probe = max77686_buck_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/palmas_regulator.c b/roms/u-boot/drivers/power/regulator/palmas_regulator.c
new file mode 100644
index 000000000..aaa5f3cfc
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/palmas_regulator.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Keerthy <j-keerthy@ti.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/palmas.h>
+
+#define REGULATOR_ON 0x1
+#define REGULATOR_OFF 0x0
+
+#define SMPS_MODE_MASK 0x3
+#define SMPS_MODE_SHIFT 0x0
+#define LDO_MODE_MASK 0x1
+#define LDO_MODE_SHIFT 0x0
+
+static const char palmas_smps_ctrl[][PALMAS_SMPS_NUM] = {
+ {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c},
+ {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38},
+ {0x20, 0x24, 0x2c, 0x30, 0x38},
+};
+
+static const char palmas_smps_volt[][PALMAS_SMPS_NUM] = {
+ {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3c},
+ {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b},
+ {0x23, 0x27, 0x2f, 0x33, 0x3B}
+};
+
+static const char palmas_ldo_ctrl[][PALMAS_LDO_NUM] = {
+ {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
+ {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
+ {0x50, 0x52, 0x54, 0x5e, 0x62}
+};
+
+static const char palmas_ldo_volt[][PALMAS_LDO_NUM] = {
+ {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
+ {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
+ {0x51, 0x53, 0x55, 0x5f, 0x63}
+};
+
+static int palmas_smps_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= PALMAS_SMPS_STATUS_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= PALMAS_SMPS_MODE_MASK;
+ else
+ ret &= ~(PALMAS_SMPS_MODE_MASK);
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int palmas_smps_volt2hex(int uV)
+{
+ if (uV > PALMAS_LDO_VOLT_MAX)
+ return -EINVAL;
+
+ if (uV > 1650000)
+ return (uV - 1000000) / 20000 + 0x6;
+
+ if (uV == 500000)
+ return 0x6;
+ else
+ return 0x6 + ((uV - 500000) / 10000);
+}
+
+static int palmas_smps_hex2volt(int hex, bool range)
+{
+ unsigned int uV = 0;
+
+ if (hex > PALMAS_SMPS_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (hex < 0x7)
+ uV = 500000;
+ else
+ uV = 500000 + (hex - 0x6) * 10000;
+
+ if (range)
+ uV *= 2;
+
+ return uV;
+}
+
+static int palmas_smps_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+ bool range;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ if (ret & PALMAS_SMPS_RANGE_MASK)
+ range = true;
+ else
+ range = false;
+
+ ret &= PALMAS_SMPS_VOLT_MASK;
+ ret = palmas_smps_hex2volt(ret, range);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+
+ return 0;
+ }
+
+ hex = palmas_smps_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= ~PALMAS_SMPS_VOLT_MASK;
+ ret |= hex;
+ if (*uV > 1650000)
+ ret |= PALMAS_SMPS_RANGE_MASK;
+
+ return pmic_reg_write(dev->parent, adr, ret);
+}
+
+static int palmas_ldo_bypass_enable(struct udevice *dev, bool enabled)
+{
+ int type = dev_get_driver_data(dev_get_parent(dev));
+ struct dm_regulator_uclass_plat *p;
+ unsigned int adr;
+ int reg;
+
+ if (type == TPS65917) {
+ /* bypass available only on LDO1 and LDO2 */
+ if (dev->driver_data > 2)
+ return -ENOTSUPP;
+ } else if (type == TPS659038) {
+ /* bypass available only on LDO9 */
+ if (dev->driver_data != 9)
+ return -ENOTSUPP;
+ }
+
+ p = dev_get_uclass_plat(dev);
+ adr = p->ctrl_reg;
+
+ reg = pmic_reg_read(dev->parent, adr);
+ if (reg < 0)
+ return reg;
+
+ if (enabled)
+ reg |= PALMAS_LDO_BYPASS_EN;
+ else
+ reg &= ~PALMAS_LDO_BYPASS_EN;
+
+ return pmic_reg_write(dev->parent, adr, reg);
+}
+
+static int palmas_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= PALMAS_LDO_STATUS_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= PALMAS_LDO_MODE_MASK;
+ else
+ ret &= ~(PALMAS_LDO_MODE_MASK);
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+
+ ret = palmas_ldo_bypass_enable(dev, false);
+ if (ret && (ret != -ENOTSUPP))
+ return ret;
+ }
+
+ return 0;
+}
+
+static int palmas_ldo_volt2hex(int uV)
+{
+ if (uV > PALMAS_LDO_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - 850000) / 50000;
+}
+
+static int palmas_ldo_hex2volt(int hex)
+{
+ if (hex > PALMAS_LDO_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (!hex)
+ return 0;
+
+ return (hex * 50000) + 850000;
+}
+
+static int palmas_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= PALMAS_LDO_VOLT_MASK;
+ ret = palmas_ldo_hex2volt(ret);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+ return 0;
+ }
+
+ hex = palmas_ldo_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= ~PALMAS_LDO_VOLT_MASK;
+ ret |= hex;
+ if (*uV > 1650000)
+ ret |= 0x80;
+
+ return pmic_reg_write(dev->parent, adr, ret);
+}
+
+static int palmas_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct udevice *parent;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ parent = dev_get_parent(dev);
+ int type = dev_get_driver_data(parent);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+
+ if (dev->driver_data) {
+ u8 idx = dev->driver_data - 1;
+ uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx];
+ uc_pdata->volt_reg = palmas_ldo_volt[type][idx];
+ } else {
+ /* check for ldoln and ldousb cases */
+ if (!strcmp("ldoln", dev->name)) {
+ uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9];
+ uc_pdata->volt_reg = palmas_ldo_volt[type][9];
+ } else if (!strcmp("ldousb", dev->name)) {
+ uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10];
+ uc_pdata->volt_reg = palmas_ldo_volt[type][10];
+ }
+ }
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = palmas_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return palmas_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = palmas_ldo_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ return palmas_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int palmas_smps_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct udevice *parent;
+ int idx;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ parent = dev_get_parent(dev);
+ int type = dev_get_driver_data(parent);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ switch (type) {
+ case PALMAS:
+ case TPS659038:
+ switch (dev->driver_data) {
+ case 123:
+ case 12:
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0];
+ uc_pdata->volt_reg = palmas_smps_volt[type][0];
+ break;
+ case 3:
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1];
+ uc_pdata->volt_reg = palmas_smps_volt[type][1];
+ break;
+ case 45:
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2];
+ uc_pdata->volt_reg = palmas_smps_volt[type][2];
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ idx = dev->driver_data - 3;
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
+ uc_pdata->volt_reg = palmas_smps_volt[type][idx];
+ break;
+
+ default:
+ printf("Wrong ID for regulator\n");
+ }
+ break;
+
+ case TPS65917:
+ switch (dev->driver_data) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ idx = dev->driver_data - 1;
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
+ uc_pdata->volt_reg = palmas_smps_volt[type][idx];
+ break;
+ case 12:
+ idx = 0;
+ uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
+ uc_pdata->volt_reg = palmas_smps_volt[type][idx];
+ break;
+ default:
+ printf("Wrong ID for regulator\n");
+ }
+ break;
+
+ default:
+ printf("Invalid PMIC ID\n");
+ }
+
+ return 0;
+}
+
+static int smps_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = palmas_smps_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int smps_set_value(struct udevice *dev, int uV)
+{
+ return palmas_smps_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int smps_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = palmas_smps_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int smps_set_enable(struct udevice *dev, bool enable)
+{
+ return palmas_smps_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops palmas_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+};
+
+U_BOOT_DRIVER(palmas_ldo) = {
+ .name = PALMAS_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &palmas_ldo_ops,
+ .probe = palmas_ldo_probe,
+};
+
+static const struct dm_regulator_ops palmas_smps_ops = {
+ .get_value = smps_get_value,
+ .set_value = smps_set_value,
+ .get_enable = smps_get_enable,
+ .set_enable = smps_set_enable,
+};
+
+U_BOOT_DRIVER(palmas_smps) = {
+ .name = PALMAS_SMPS_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &palmas_smps_ops,
+ .probe = palmas_smps_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/pbias_regulator.c b/roms/u-boot/drivers/power/regulator/pbias_regulator.c
new file mode 100644
index 000000000..5bf186e4d
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/pbias_regulator.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
+ * Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/ioport.h>
+#include <dm/device-internal.h>
+#include <dm/read.h>
+#ifdef CONFIG_MMC_OMAP36XX_PINS
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+#endif
+
+struct pbias_reg_info {
+ u32 enable;
+ u32 enable_mask;
+ u32 disable_val;
+ u32 vmode;
+ unsigned int enable_time;
+ char *name;
+};
+
+struct pbias_priv {
+ struct regmap *regmap;
+ int offset;
+};
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "pbias", .driver = "pbias_regulator"},
+ { },
+};
+
+static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ struct pbias_priv *priv = dev_get_priv(dev);
+ u32 val = *(u32 *)buff;
+
+ if (len != 4)
+ return -EINVAL;
+
+ return regmap_write(priv->regmap, priv->offset, val);
+}
+
+static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ struct pbias_priv *priv = dev_get_priv(dev);
+
+ if (len != 4)
+ return -EINVAL;
+
+ return regmap_read(priv->regmap, priv->offset, (u32 *)buff);
+}
+
+static int pbias_of_to_plat(struct udevice *dev)
+{
+ struct pbias_priv *priv = dev_get_priv(dev);
+ struct udevice *syscon;
+ struct regmap *regmap;
+ struct resource res;
+ int err;
+
+ err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ "syscon", &syscon);
+ if (err) {
+ pr_err("%s: unable to find syscon device (%d)\n", __func__,
+ err);
+ return err;
+ }
+
+ regmap = syscon_get_regmap(syscon);
+ if (IS_ERR(regmap)) {
+ pr_err("%s: unable to find regmap (%ld)\n", __func__,
+ PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+ priv->regmap = regmap;
+
+ err = dev_read_resource(dev, 0, &res);
+ if (err) {
+ pr_err("%s: unable to find offset (%d)\n", __func__, err);
+ return err;
+ }
+ priv->offset = res.start;
+
+ return 0;
+}
+
+static int pbias_bind(struct udevice *dev)
+{
+ int children;
+
+ children = pmic_bind_children(dev, dev_ofnode(dev),
+ pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ return 0;
+}
+
+static struct dm_pmic_ops pbias_ops = {
+ .read = pbias_read,
+ .write = pbias_write,
+};
+
+static const struct udevice_id pbias_ids[] = {
+ { .compatible = "ti,pbias-dra7" },
+ { .compatible = "ti,pbias-omap2" },
+ { .compatible = "ti,pbias-omap3" },
+ { .compatible = "ti,pbias-omap4" },
+ { .compatible = "ti,pbias-omap5" },
+ { }
+};
+
+U_BOOT_DRIVER(pbias_pmic) = {
+ .name = "pbias_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = pbias_ids,
+ .bind = pbias_bind,
+ .ops = &pbias_ops,
+ .of_to_plat = pbias_of_to_plat,
+ .priv_auto = sizeof(struct pbias_priv),
+};
+
+static const struct pbias_reg_info pbias_mmc_omap2430 = {
+ .enable = BIT(1),
+ .enable_mask = BIT(1),
+ .vmode = BIT(0),
+ .disable_val = 0,
+ .enable_time = 100,
+ .name = "pbias_mmc_omap2430"
+};
+
+static const struct pbias_reg_info pbias_sim_omap3 = {
+ .enable = BIT(9),
+ .enable_mask = BIT(9),
+ .vmode = BIT(8),
+ .enable_time = 100,
+ .name = "pbias_sim_omap3"
+};
+
+static const struct pbias_reg_info pbias_mmc_omap4 = {
+ .enable = BIT(26) | BIT(22),
+ .enable_mask = BIT(26) | BIT(25) | BIT(22),
+ .disable_val = BIT(25),
+ .vmode = BIT(21),
+ .enable_time = 100,
+ .name = "pbias_mmc_omap4"
+};
+
+static const struct pbias_reg_info pbias_mmc_omap5 = {
+ .enable = BIT(27) | BIT(26),
+ .enable_mask = BIT(27) | BIT(25) | BIT(26),
+ .disable_val = BIT(25),
+ .vmode = BIT(21),
+ .enable_time = 100,
+ .name = "pbias_mmc_omap5"
+};
+
+static const struct pbias_reg_info *pbias_reg_infos[] = {
+ &pbias_mmc_omap5,
+ &pbias_mmc_omap4,
+ &pbias_sim_omap3,
+ &pbias_mmc_omap2430,
+ NULL
+};
+
+static int pbias_regulator_probe(struct udevice *dev)
+{
+ const struct pbias_reg_info **p = pbias_reg_infos;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ while (*p) {
+ int rc;
+
+ rc = dev_read_stringlist_search(dev, "regulator-name",
+ (*p)->name);
+ if (rc >= 0) {
+ debug("found regulator %s\n", (*p)->name);
+ break;
+ } else if (rc != -ENODATA) {
+ return rc;
+ }
+ p++;
+ }
+ if (!*p) {
+ int i = 0;
+ const char *s;
+
+ debug("regulator ");
+ while (dev_read_string_index(dev, "regulator-name", i++, &s) >= 0)
+ debug("%s'%s' ", (i > 1) ? ", " : "", s);
+ debug("%s not supported\n", (i > 2) ? "are" : "is");
+ return -EINVAL;
+ }
+
+ uc_pdata->type = REGULATOR_TYPE_OTHER;
+ dev_set_priv(dev, (void *)*p);
+
+ return 0;
+}
+
+static int pbias_regulator_get_value(struct udevice *dev)
+{
+ const struct pbias_reg_info *p = dev_get_priv(dev);
+ int rc;
+ u32 reg;
+
+ rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+ if (rc)
+ return rc;
+
+ debug("%s voltage id %s\n", p->name,
+ (reg & p->vmode) ? "3.0v" : "1.8v");
+ return (reg & p->vmode) ? 3000000 : 1800000;
+}
+
+static int pbias_regulator_set_value(struct udevice *dev, int uV)
+{
+ const struct pbias_reg_info *p = dev_get_priv(dev);
+ int rc, ret;
+ u32 reg;
+#ifdef CONFIG_MMC_OMAP36XX_PINS
+ u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
+#endif
+
+ rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+ if (rc)
+ return rc;
+
+ if (uV == 3300000)
+ reg |= p->vmode;
+ else if (uV == 1800000)
+ reg &= ~p->vmode;
+ else
+ return -EINVAL;
+
+ debug("Setting %s voltage to %s\n", p->name,
+ (reg & p->vmode) ? "3.0v" : "1.8v");
+
+#ifdef CONFIG_MMC_OMAP36XX_PINS
+ if (get_cpu_family() == CPU_OMAP36XX) {
+ /* Disable extended drain IO before changing PBIAS */
+ wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
+ writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
+ }
+#endif
+ ret = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+#ifdef CONFIG_MMC_OMAP36XX_PINS
+ if (get_cpu_family() == CPU_OMAP36XX) {
+ /* Enable extended drain IO after changing PBIAS */
+ writel(wkup_ctrl |
+ OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
+ OMAP34XX_CTRL_WKUP_CTRL);
+ }
+#endif
+ return ret;
+}
+
+static int pbias_regulator_get_enable(struct udevice *dev)
+{
+ const struct pbias_reg_info *p = dev_get_priv(dev);
+ int rc;
+ u32 reg;
+
+ rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+ if (rc)
+ return rc;
+
+ debug("%s id %s\n", p->name,
+ (reg & p->enable_mask) == (p->disable_val) ? "on" : "off");
+
+ return (reg & p->enable_mask) == (p->disable_val);
+}
+
+static int pbias_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ const struct pbias_reg_info *p = dev_get_priv(dev);
+ int rc;
+ u32 reg;
+#ifdef CONFIG_MMC_OMAP36XX_PINS
+ u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
+#endif
+
+ debug("Turning %s %s\n", enable ? "on" : "off", p->name);
+
+#ifdef CONFIG_MMC_OMAP36XX_PINS
+ if (get_cpu_family() == CPU_OMAP36XX) {
+ /* Disable extended drain IO before changing PBIAS */
+ wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
+ writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
+ }
+#endif
+
+ rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+ if (rc)
+ return rc;
+
+ reg &= ~p->enable_mask;
+ if (enable)
+ reg |= p->enable;
+ else
+ reg |= p->disable_val;
+
+ rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
+
+#ifdef CONFIG_MMC_OMAP36XX_PINS
+ if (get_cpu_family() == CPU_OMAP36XX) {
+ /* Enable extended drain IO after changing PBIAS */
+ writel(wkup_ctrl |
+ OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
+ OMAP34XX_CTRL_WKUP_CTRL);
+ }
+#endif
+
+ if (rc)
+ return rc;
+
+ if (enable)
+ udelay(p->enable_time);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops pbias_regulator_ops = {
+ .get_value = pbias_regulator_get_value,
+ .set_value = pbias_regulator_set_value,
+ .get_enable = pbias_regulator_get_enable,
+ .set_enable = pbias_regulator_set_enable,
+};
+
+U_BOOT_DRIVER(pbias_regulator) = {
+ .name = "pbias_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &pbias_regulator_ops,
+ .probe = pbias_regulator_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/pfuze100.c b/roms/u-boot/drivers/power/regulator/pfuze100.c
new file mode 100644
index 000000000..698a6fa59
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/pfuze100.c
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/pfuze100_pmic.h>
+
+/**
+ * struct pfuze100_regulator_desc - regulator descriptor
+ *
+ * @name: Identify name for the regulator.
+ * @type: Indicates the regulator type.
+ * @uV_step: Voltage increase for each selector.
+ * @vsel_reg: Register for adjust regulator voltage for normal.
+ * @vsel_mask: Mask bit for setting regulator voltage for normal.
+ * @stby_reg: Register for adjust regulator voltage for standby.
+ * @stby_mask: Mask bit for setting regulator voltage for standby.
+ * @volt_table: Voltage mapping table (if table based mapping).
+ * @voltage: Current voltage for REGULATOR_TYPE_FIXED type regulator.
+ */
+struct pfuze100_regulator_desc {
+ char *name;
+ enum regulator_type type;
+ unsigned int uV_step;
+ unsigned int vsel_reg;
+ unsigned int vsel_mask;
+ unsigned int stby_reg;
+ unsigned int stby_mask;
+ unsigned int *volt_table;
+ unsigned int voltage;
+};
+
+/**
+ * struct pfuze100_regulator_plat - platform data for pfuze100
+ *
+ * @desc: Points the description entry of one regulator of pfuze100
+ */
+struct pfuze100_regulator_plat {
+ struct pfuze100_regulator_desc *desc;
+};
+
+#define PFUZE100_FIXED_REG(_name, base, vol) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_FIXED, \
+ .voltage = (vol), \
+ }
+
+#define PFUZE100_SW_REG(_name, base, step) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_BUCK, \
+ .uV_step = (step), \
+ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
+ .vsel_mask = 0x3F, \
+ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \
+ .stby_mask = 0x3F, \
+ }
+
+#define PFUZE100_SWB_REG(_name, base, mask, step, voltages) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_BUCK, \
+ .uV_step = (step), \
+ .vsel_reg = (base), \
+ .vsel_mask = (mask), \
+ .volt_table = (voltages), \
+ }
+
+#define PFUZE100_SNVS_REG(_name, base, mask, voltages) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_OTHER, \
+ .vsel_reg = (base), \
+ .vsel_mask = (mask), \
+ .volt_table = (voltages), \
+ }
+
+#define PFUZE100_VGEN_REG(_name, base, step) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_LDO, \
+ .uV_step = (step), \
+ .vsel_reg = (base), \
+ .vsel_mask = 0xF, \
+ .stby_reg = (base), \
+ .stby_mask = 0x20, \
+ }
+
+#define PFUZE3000_VCC_REG(_name, base, step) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_LDO, \
+ .uV_step = (step), \
+ .vsel_reg = (base), \
+ .vsel_mask = 0x3, \
+ .stby_reg = (base), \
+ .stby_mask = 0x20, \
+}
+
+#define PFUZE3000_SW1_REG(_name, base, step) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_BUCK, \
+ .uV_step = (step), \
+ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
+ .vsel_mask = 0x1F, \
+ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \
+ .stby_mask = 0x1F, \
+ }
+
+#define PFUZE3000_SW2_REG(_name, base, step) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_BUCK, \
+ .uV_step = (step), \
+ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
+ .vsel_mask = 0x7, \
+ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \
+ .stby_mask = 0x7, \
+ }
+
+#define PFUZE3000_SW3_REG(_name, base, step) \
+ { \
+ .name = #_name, \
+ .type = REGULATOR_TYPE_BUCK, \
+ .uV_step = (step), \
+ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
+ .vsel_mask = 0xF, \
+ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \
+ .stby_mask = 0xF, \
+ }
+
+static unsigned int pfuze100_swbst[] = {
+ 5000000, 5050000, 5100000, 5150000
+};
+
+static unsigned int pfuze100_vsnvs[] = {
+ 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, -1
+};
+
+static unsigned int pfuze3000_vsnvs[] = {
+ -1, -1, -1, -1, -1, -1, 3000000, -1
+};
+
+static unsigned int pfuze3000_sw2lo[] = {
+ 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000
+};
+
+/* PFUZE100 */
+static struct pfuze100_regulator_desc pfuze100_regulators[] = {
+ PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000),
+ PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000),
+ PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000),
+ PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000),
+ PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000),
+ PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000),
+ PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst),
+ PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+ PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000),
+ PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000),
+ PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000),
+ PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000),
+ PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000),
+ PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000),
+};
+
+/* PFUZE200 */
+static struct pfuze100_regulator_desc pfuze200_regulators[] = {
+ PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000),
+ PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000),
+ PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000),
+ PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000),
+ PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst),
+ PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+ PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000),
+ PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000),
+ PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000),
+ PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000),
+ PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000),
+ PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000),
+};
+
+/* PFUZE3000 */
+static struct pfuze100_regulator_desc pfuze3000_regulators[] = {
+ PFUZE3000_SW1_REG(sw1a, PFUZE100_SW1ABVOL, 25000),
+ PFUZE3000_SW1_REG(sw1b, PFUZE100_SW1CVOL, 25000),
+ PFUZE100_SWB_REG(sw2, PFUZE100_SW2VOL, 0x7, 50000, pfuze3000_sw2lo),
+ PFUZE3000_SW3_REG(sw3, PFUZE100_SW3AVOL, 50000),
+ PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst),
+ PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze3000_vsnvs),
+ PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(vldo1, PFUZE100_VGEN1VOL, 100000),
+ PFUZE100_VGEN_REG(vldo2, PFUZE100_VGEN2VOL, 50000),
+ PFUZE3000_VCC_REG(vccsd, PFUZE100_VGEN3VOL, 150000),
+ PFUZE3000_VCC_REG(v33, PFUZE100_VGEN4VOL, 150000),
+ PFUZE100_VGEN_REG(vldo3, PFUZE100_VGEN5VOL, 100000),
+ PFUZE100_VGEN_REG(vldo4, PFUZE100_VGEN6VOL, 100000),
+};
+
+#define MODE(_id, _val, _name) { \
+ .id = _id, \
+ .register_value = _val, \
+ .name = _name, \
+}
+
+/* SWx Buck regulator mode */
+static struct dm_regulator_mode pfuze_sw_modes[] = {
+ MODE(OFF_OFF, OFF_OFF, "OFF_OFF"),
+ MODE(PWM_OFF, PWM_OFF, "PWM_OFF"),
+ MODE(PFM_OFF, PFM_OFF, "PFM_OFF"),
+ MODE(APS_OFF, APS_OFF, "APS_OFF"),
+ MODE(PWM_PWM, PWM_PWM, "PWM_PWM"),
+ MODE(PWM_APS, PWM_APS, "PWM_APS"),
+ MODE(APS_APS, APS_APS, "APS_APS"),
+ MODE(APS_PFM, APS_PFM, "APS_PFM"),
+ MODE(PWM_PFM, PWM_PFM, "PWM_PFM"),
+};
+
+/* Boost Buck regulator mode for normal operation */
+static struct dm_regulator_mode pfuze_swbst_modes[] = {
+ MODE(SWBST_MODE_OFF, SWBST_MODE_OFF , "SWBST_MODE_OFF"),
+ MODE(SWBST_MODE_PFM, SWBST_MODE_PFM, "SWBST_MODE_PFM"),
+ MODE(SWBST_MODE_AUTO, SWBST_MODE_AUTO, "SWBST_MODE_AUTO"),
+ MODE(SWBST_MODE_APS, SWBST_MODE_APS, "SWBST_MODE_APS"),
+};
+
+/* VGENx LDO regulator mode for normal operation */
+static struct dm_regulator_mode pfuze_ldo_modes[] = {
+ MODE(LDO_MODE_OFF, LDO_MODE_OFF, "LDO_MODE_OFF"),
+ MODE(LDO_MODE_ON, LDO_MODE_ON, "LDO_MODE_ON"),
+};
+
+static struct pfuze100_regulator_desc *se_desc(struct pfuze100_regulator_desc *desc,
+ int size,
+ const char *name)
+{
+ int i;
+
+ for (i = 0; i < size; desc++) {
+ if (!strcmp(desc->name, name))
+ return desc;
+ continue;
+ }
+
+ return NULL;
+}
+
+static int pfuze100_regulator_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct pfuze100_regulator_plat *plat = dev_get_plat(dev);
+ struct pfuze100_regulator_desc *desc;
+
+ switch (dev_get_driver_data(dev_get_parent(dev))) {
+ case PFUZE100:
+ desc = se_desc(pfuze100_regulators,
+ ARRAY_SIZE(pfuze100_regulators),
+ dev->name);
+ break;
+ case PFUZE200:
+ desc = se_desc(pfuze200_regulators,
+ ARRAY_SIZE(pfuze200_regulators),
+ dev->name);
+ break;
+ case PFUZE3000:
+ desc = se_desc(pfuze3000_regulators,
+ ARRAY_SIZE(pfuze3000_regulators),
+ dev->name);
+ break;
+ default:
+ debug("Unsupported PFUZE\n");
+ return -EINVAL;
+ }
+ if (!desc) {
+ debug("Do not support regulator %s\n", dev->name);
+ return -EINVAL;
+ }
+
+ plat->desc = desc;
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = desc->type;
+ if (uc_pdata->type == REGULATOR_TYPE_BUCK) {
+ if (!strcmp(dev->name, "swbst")) {
+ uc_pdata->mode = pfuze_swbst_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(pfuze_swbst_modes);
+ } else {
+ uc_pdata->mode = pfuze_sw_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(pfuze_sw_modes);
+ }
+ } else if (uc_pdata->type == REGULATOR_TYPE_LDO) {
+ uc_pdata->mode = pfuze_ldo_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(pfuze_ldo_modes);
+ } else {
+ uc_pdata->mode = NULL;
+ uc_pdata->mode_count = 0;
+ }
+
+ return 0;
+}
+
+static int pfuze100_regulator_mode(struct udevice *dev, int op, int *opmode)
+{
+ int val;
+ struct pfuze100_regulator_plat *plat = dev_get_plat(dev);
+ struct pfuze100_regulator_desc *desc = plat->desc;
+
+ if (op == PMIC_OP_GET) {
+ if (desc->type == REGULATOR_TYPE_BUCK) {
+ if (!strcmp(dev->name, "swbst")) {
+ val = pmic_reg_read(dev->parent,
+ desc->vsel_reg);
+ if (val < 0)
+ return val;
+
+ val &= SWBST_MODE_MASK;
+ val >>= SWBST_MODE_SHIFT;
+ *opmode = val;
+
+ return 0;
+ }
+ val = pmic_reg_read(dev->parent,
+ desc->vsel_reg +
+ PFUZE100_MODE_OFFSET);
+ if (val < 0)
+ return val;
+
+ val &= SW_MODE_MASK;
+ val >>= SW_MODE_SHIFT;
+ *opmode = val;
+
+ return 0;
+
+ } else if (desc->type == REGULATOR_TYPE_LDO) {
+ val = pmic_reg_read(dev->parent, desc->vsel_reg);
+ if (val < 0)
+ return val;
+
+ val &= LDO_MODE_MASK;
+ val >>= LDO_MODE_SHIFT;
+ *opmode = val;
+
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ if (desc->type == REGULATOR_TYPE_BUCK) {
+ if (!strcmp(dev->name, "swbst"))
+ return pmic_clrsetbits(dev->parent, desc->vsel_reg,
+ SWBST_MODE_MASK,
+ *opmode << SWBST_MODE_SHIFT);
+
+ val = pmic_clrsetbits(dev->parent,
+ desc->vsel_reg + PFUZE100_MODE_OFFSET,
+ SW_MODE_MASK,
+ *opmode << SW_MODE_SHIFT);
+
+ } else if (desc->type == REGULATOR_TYPE_LDO) {
+ val = pmic_clrsetbits(dev->parent, desc->vsel_reg,
+ LDO_MODE_MASK,
+ *opmode << LDO_MODE_SHIFT);
+ return val;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pfuze100_regulator_enable(struct udevice *dev, int op, bool *enable)
+{
+ int val;
+ int ret, on_off;
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+
+ if (op == PMIC_OP_GET) {
+ if (!strcmp(dev->name, "vrefddr")) {
+ val = pmic_reg_read(dev->parent, PFUZE100_VREFDDRCON);
+ if (val < 0)
+ return val;
+
+ if (val & VREFDDRCON_EN)
+ *enable = true;
+ else
+ *enable = false;
+ return 0;
+ }
+ ret = pfuze100_regulator_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+ switch (on_off) {
+ /* OFF_OFF, SWBST_MODE_OFF, LDO_MODE_OFF have same value */
+ case OFF_OFF:
+ *enable = false;
+ break;
+ default:
+ *enable = true;
+ break;
+ }
+ } else if (op == PMIC_OP_SET) {
+ if (!strcmp(dev->name, "vrefddr")) {
+ val = pmic_reg_read(dev->parent, PFUZE100_VREFDDRCON);
+ if (val < 0)
+ return val;
+
+ if (val & VREFDDRCON_EN)
+ return 0;
+ val |= VREFDDRCON_EN;
+
+ return pmic_reg_write(dev->parent, PFUZE100_VREFDDRCON,
+ val);
+ }
+
+ if (uc_pdata->type == REGULATOR_TYPE_LDO) {
+ on_off = *enable ? LDO_MODE_ON : LDO_MODE_OFF;
+ } else if (uc_pdata->type == REGULATOR_TYPE_BUCK) {
+ if (!strcmp(dev->name, "swbst"))
+ on_off = *enable ? SWBST_MODE_AUTO :
+ SWBST_MODE_OFF;
+ else
+ on_off = *enable ? APS_PFM : OFF_OFF;
+ } else {
+ return -EINVAL;
+ }
+
+ return pfuze100_regulator_mode(dev, op, &on_off);
+ }
+
+ return 0;
+}
+
+static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV)
+{
+ int i;
+ int val;
+ struct pfuze100_regulator_plat *plat = dev_get_plat(dev);
+ struct pfuze100_regulator_desc *desc = plat->desc;
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+ if (uc_pdata->type == REGULATOR_TYPE_FIXED) {
+ *uV = desc->voltage;
+ } else if (desc->volt_table) {
+ val = pmic_reg_read(dev->parent, desc->vsel_reg);
+ if (val < 0)
+ return val;
+ val &= desc->vsel_mask;
+ *uV = desc->volt_table[val];
+ } else {
+ if (uc_pdata->min_uV < 0) {
+ debug("Need to provide min_uV in dts.\n");
+ return -EINVAL;
+ }
+ val = pmic_reg_read(dev->parent, desc->vsel_reg);
+ if (val < 0)
+ return val;
+ val &= desc->vsel_mask;
+ *uV = uc_pdata->min_uV + (int)val * desc->uV_step;
+ }
+
+ return 0;
+ }
+
+ if (uc_pdata->type == REGULATOR_TYPE_FIXED) {
+ debug("Set voltage for REGULATOR_TYPE_FIXED regulator\n");
+ return -EINVAL;
+ } else if (desc->volt_table) {
+ for (i = 0; i <= desc->vsel_mask; i++) {
+ if (*uV == desc->volt_table[i])
+ break;
+ }
+ if (i == desc->vsel_mask + 1) {
+ debug("Unsupported voltage %u\n", *uV);
+ return -EINVAL;
+ }
+
+ return pmic_clrsetbits(dev->parent, desc->vsel_reg,
+ desc->vsel_mask, i);
+ } else {
+ if (uc_pdata->min_uV < 0) {
+ debug("Need to provide min_uV in dts.\n");
+ return -EINVAL;
+ }
+ return pmic_clrsetbits(dev->parent, desc->vsel_reg,
+ desc->vsel_mask,
+ (*uV - uc_pdata->min_uV) / desc->uV_step);
+ }
+
+ return 0;
+}
+
+static int pfuze100_regulator_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = pfuze100_regulator_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int pfuze100_regulator_set_value(struct udevice *dev, int uV)
+{
+ return pfuze100_regulator_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int pfuze100_regulator_get_enable(struct udevice *dev)
+{
+ int ret;
+ bool enable = false;
+
+ ret = pfuze100_regulator_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int pfuze100_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ return pfuze100_regulator_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int pfuze100_regulator_get_mode(struct udevice *dev)
+{
+ int mode;
+ int ret;
+
+ ret = pfuze100_regulator_mode(dev, PMIC_OP_GET, &mode);
+ if (ret)
+ return ret;
+
+ return mode;
+}
+
+static int pfuze100_regulator_set_mode(struct udevice *dev, int mode)
+{
+ return pfuze100_regulator_mode(dev, PMIC_OP_SET, &mode);
+}
+
+static const struct dm_regulator_ops pfuze100_regulator_ops = {
+ .get_value = pfuze100_regulator_get_value,
+ .set_value = pfuze100_regulator_set_value,
+ .get_enable = pfuze100_regulator_get_enable,
+ .set_enable = pfuze100_regulator_set_enable,
+ .get_mode = pfuze100_regulator_get_mode,
+ .set_mode = pfuze100_regulator_set_mode,
+};
+
+U_BOOT_DRIVER(pfuze100_regulator) = {
+ .name = "pfuze100_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &pfuze100_regulator_ops,
+ .probe = pfuze100_regulator_probe,
+ .plat_auto = sizeof(struct pfuze100_regulator_plat),
+};
diff --git a/roms/u-boot/drivers/power/regulator/pwm_regulator.c b/roms/u-boot/drivers/power/regulator/pwm_regulator.c
new file mode 100644
index 000000000..ca59f3ae3
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/pwm_regulator.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd
+ *
+ * Based on kernel drivers/regulator/pwm-regulator.c
+ * Copyright (C) 2014 - STMicroelectronics Inc.
+ * Author: Lee Jones <lee.jones@linaro.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <pwm.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pwm_regulator_info {
+ /* pwm id corresponding to the PWM driver */
+ int pwm_id;
+ /* the period of one PWM cycle */
+ int period_ns;
+ /*
+ * the polarity of one PWM
+ * 0: normal polarity
+ * 1: inverted polarity
+ */
+ bool polarity;
+ struct udevice *pwm;
+ /* initialize voltage of regulator */
+ int init_voltage;
+ /* the maximum voltage of regulator */
+ int max_voltage;
+ /* the minimum voltage of regulator */
+ int min_voltage;
+ /* the current voltage of regulator */
+ int volt_uV;
+};
+
+static int pwm_regulator_enable(struct udevice *dev, bool enable)
+{
+ struct pwm_regulator_info *priv = dev_get_priv(dev);
+
+ return pwm_set_enable(priv->pwm, priv->pwm_id, enable);
+}
+
+static int pwm_voltage_to_duty_cycle_percentage(struct udevice *dev, int req_uV)
+{
+ struct pwm_regulator_info *priv = dev_get_priv(dev);
+ int min_uV = priv->min_voltage;
+ int max_uV = priv->max_voltage;
+ int diff = max_uV - min_uV;
+
+ return ((req_uV * 100) - (min_uV * 100)) / diff;
+}
+
+static int pwm_regulator_get_voltage(struct udevice *dev)
+{
+ struct pwm_regulator_info *priv = dev_get_priv(dev);
+
+ return priv->volt_uV;
+}
+
+static int pwm_regulator_set_voltage(struct udevice *dev, int uvolt)
+{
+ struct pwm_regulator_info *priv = dev_get_priv(dev);
+ int duty_cycle;
+ int ret = 0;
+
+ duty_cycle = pwm_voltage_to_duty_cycle_percentage(dev, uvolt);
+
+ ret = pwm_set_invert(priv->pwm, priv->pwm_id, priv->polarity);
+ if (ret) {
+ dev_err(dev, "Failed to init PWM\n");
+ return ret;
+ }
+
+ ret = pwm_set_config(priv->pwm, priv->pwm_id,
+ priv->period_ns, (priv->period_ns / 100) * duty_cycle);
+ if (ret) {
+ dev_err(dev, "Failed to configure PWM\n");
+ return ret;
+ }
+
+ priv->volt_uV = uvolt;
+
+ return ret;
+}
+
+static int pwm_regulator_of_to_plat(struct udevice *dev)
+{
+ struct pwm_regulator_info *priv = dev_get_priv(dev);
+ struct ofnode_phandle_args args;
+ int ret;
+
+ ret = dev_read_phandle_with_args(dev, "pwms", "#pwm-cells", 0, 0, &args);
+ if (ret) {
+ debug("%s: Cannot get PWM phandle: ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ priv->period_ns = args.args[1];
+ priv->polarity = args.args[2];
+
+ priv->init_voltage = dev_read_u32_default(dev, "regulator-init-microvolt", -1);
+ if (priv->init_voltage < 0) {
+ printf("Cannot find regulator pwm init_voltage\n");
+ return -EINVAL;
+ }
+
+ ret = uclass_get_device_by_ofnode(UCLASS_PWM, args.node, &priv->pwm);
+ if (ret) {
+ debug("%s: Cannot get PWM: ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pwm_regulator_probe(struct udevice *dev)
+{
+ struct pwm_regulator_info *priv = dev_get_priv(dev);
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode_count = 0;
+ priv->max_voltage = uc_pdata->max_uV;
+ priv->min_voltage = uc_pdata->min_uV;
+
+ if (priv->init_voltage)
+ pwm_regulator_set_voltage(dev, priv->init_voltage);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops pwm_regulator_ops = {
+ .get_value = pwm_regulator_get_voltage,
+ .set_value = pwm_regulator_set_voltage,
+ .set_enable = pwm_regulator_enable,
+};
+
+static const struct udevice_id pwm_regulator_ids[] = {
+ { .compatible = "pwm-regulator" },
+ { }
+};
+
+U_BOOT_DRIVER(pwm_regulator) = {
+ .name = "pwm_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &pwm_regulator_ops,
+ .probe = pwm_regulator_probe,
+ .of_match = pwm_regulator_ids,
+ .of_to_plat = pwm_regulator_of_to_plat,
+ .priv_auto = sizeof(struct pwm_regulator_info),
+};
diff --git a/roms/u-boot/drivers/power/regulator/regulator-uclass.c b/roms/u-boot/drivers/power/regulator/regulator-uclass.c
new file mode 100644
index 000000000..fac960682
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/regulator-uclass.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/uclass-internal.h>
+#include <linux/delay.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ *modep = NULL;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata)
+ return -ENXIO;
+
+ *modep = uc_pdata->mode;
+ return uc_pdata->mode_count;
+}
+
+int regulator_get_value(struct udevice *dev)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops || !ops->get_value)
+ return -ENOSYS;
+
+ return ops->get_value(dev);
+}
+
+static void regulator_set_value_ramp_delay(struct udevice *dev, int old_uV,
+ int new_uV, unsigned int ramp_delay)
+{
+ int delay = DIV_ROUND_UP(abs(new_uV - old_uV), ramp_delay);
+
+ debug("regulator %s: delay %u us (%d uV -> %d uV)\n", dev->name, delay,
+ old_uV, new_uV);
+
+ udelay(delay);
+}
+
+int regulator_set_value(struct udevice *dev, int uV)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int ret, old_uV = uV, is_enabled = 0;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV)
+ return -EINVAL;
+ if (uc_pdata->max_uV != -ENODATA && uV > uc_pdata->max_uV)
+ return -EINVAL;
+
+ if (!ops || !ops->set_value)
+ return -ENOSYS;
+
+ if (uc_pdata->ramp_delay) {
+ is_enabled = regulator_get_enable(dev);
+ old_uV = regulator_get_value(dev);
+ }
+
+ ret = ops->set_value(dev, uV);
+
+ if (!ret) {
+ if (uc_pdata->ramp_delay && old_uV > 0 && is_enabled)
+ regulator_set_value_ramp_delay(dev, old_uV, uV,
+ uc_pdata->ramp_delay);
+ }
+
+ return ret;
+}
+
+int regulator_set_suspend_value(struct udevice *dev, int uV)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV)
+ return -EINVAL;
+ if (uc_pdata->max_uV != -ENODATA && uV > uc_pdata->max_uV)
+ return -EINVAL;
+
+ if (!ops->set_suspend_value)
+ return -ENOSYS;
+
+ return ops->set_suspend_value(dev, uV);
+}
+
+int regulator_get_suspend_value(struct udevice *dev)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops->get_suspend_value)
+ return -ENOSYS;
+
+ return ops->get_suspend_value(dev);
+}
+
+/*
+ * To be called with at most caution as there is no check
+ * before setting the actual voltage value.
+ */
+int regulator_set_value_force(struct udevice *dev, int uV)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops || !ops->set_value)
+ return -ENOSYS;
+
+ return ops->set_value(dev, uV);
+}
+
+int regulator_get_current(struct udevice *dev)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops || !ops->get_current)
+ return -ENOSYS;
+
+ return ops->get_current(dev);
+}
+
+int regulator_set_current(struct udevice *dev, int uA)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (uc_pdata->min_uA != -ENODATA && uA < uc_pdata->min_uA)
+ return -EINVAL;
+ if (uc_pdata->max_uA != -ENODATA && uA > uc_pdata->max_uA)
+ return -EINVAL;
+
+ if (!ops || !ops->set_current)
+ return -ENOSYS;
+
+ return ops->set_current(dev, uA);
+}
+
+int regulator_get_enable(struct udevice *dev)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops || !ops->get_enable)
+ return -ENOSYS;
+
+ return ops->get_enable(dev);
+}
+
+int regulator_set_enable(struct udevice *dev, bool enable)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int ret, old_enable = 0;
+
+ if (!ops || !ops->set_enable)
+ return -ENOSYS;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!enable && uc_pdata->always_on)
+ return -EACCES;
+
+ if (uc_pdata->ramp_delay)
+ old_enable = regulator_get_enable(dev);
+
+ ret = ops->set_enable(dev, enable);
+ if (!ret) {
+ if (uc_pdata->ramp_delay && !old_enable && enable) {
+ int uV = regulator_get_value(dev);
+
+ if (uV > 0) {
+ regulator_set_value_ramp_delay(dev, 0, uV,
+ uc_pdata->ramp_delay);
+ }
+ }
+ }
+
+ return ret;
+}
+
+int regulator_set_enable_if_allowed(struct udevice *dev, bool enable)
+{
+ int ret;
+
+ ret = regulator_set_enable(dev, enable);
+ if (ret == -ENOSYS || ret == -EACCES)
+ return 0;
+
+ return ret;
+}
+
+int regulator_set_suspend_enable(struct udevice *dev, bool enable)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops->set_suspend_enable)
+ return -ENOSYS;
+
+ return ops->set_suspend_enable(dev, enable);
+}
+
+int regulator_get_suspend_enable(struct udevice *dev)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops->get_suspend_enable)
+ return -ENOSYS;
+
+ return ops->get_suspend_enable(dev);
+}
+
+int regulator_get_mode(struct udevice *dev)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops || !ops->get_mode)
+ return -ENOSYS;
+
+ return ops->get_mode(dev);
+}
+
+int regulator_set_mode(struct udevice *dev, int mode)
+{
+ const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops || !ops->set_mode)
+ return -ENOSYS;
+
+ return ops->set_mode(dev, mode);
+}
+
+int regulator_get_by_platname(const char *plat_name, struct udevice **devp)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+
+ for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
+ ret = uclass_find_next_device(&dev)) {
+ if (ret) {
+ debug("regulator %s, ret=%d\n", dev->name, ret);
+ continue;
+ }
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
+ continue;
+
+ return uclass_get_device_tail(dev, 0, devp);
+ }
+
+ debug("%s: can't find: %s, ret=%d\n", __func__, plat_name, ret);
+
+ return -ENODEV;
+}
+
+int regulator_get_by_devname(const char *devname, struct udevice **devp)
+{
+ return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
+}
+
+int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
+ struct udevice **devp)
+{
+ return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ supply_name, devp);
+}
+
+int regulator_autoset(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int ret = 0;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on);
+ if (!ret && uc_pdata->suspend_on) {
+ ret = regulator_set_suspend_value(dev, uc_pdata->suspend_uV);
+ if (!ret)
+ return ret;
+ }
+
+ if (!uc_pdata->always_on && !uc_pdata->boot_on)
+ return -EMEDIUMTYPE;
+
+ if (uc_pdata->type == REGULATOR_TYPE_FIXED)
+ return regulator_set_enable(dev, true);
+
+ if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
+ ret = regulator_set_value(dev, uc_pdata->min_uV);
+ if (uc_pdata->init_uV > 0)
+ ret = regulator_set_value(dev, uc_pdata->init_uV);
+ if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
+ ret = regulator_set_current(dev, uc_pdata->min_uA);
+
+ if (!ret)
+ ret = regulator_set_enable(dev, true);
+
+ return ret;
+}
+
+int regulator_unset(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (uc_pdata && uc_pdata->force_off)
+ return regulator_set_enable(dev, false);
+
+ return -EMEDIUMTYPE;
+}
+
+static void regulator_show(struct udevice *dev, int ret)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ printf("%s@%s: ", dev->name, uc_pdata->name);
+ if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
+ printf("set %d uV", uc_pdata->min_uV);
+ if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)
+ printf("; set %d uA", uc_pdata->min_uA);
+ printf("; enabling");
+ if (ret)
+ printf(" (ret: %d)", ret);
+ printf("\n");
+}
+
+int regulator_autoset_by_name(const char *platname, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = regulator_get_by_platname(platname, &dev);
+ if (devp)
+ *devp = dev;
+ if (ret) {
+ debug("Can get the regulator: %s (err=%d)\n", platname, ret);
+ return ret;
+ }
+
+ return regulator_autoset(dev);
+}
+
+int regulator_list_autoset(const char *list_platname[],
+ struct udevice *list_devp[],
+ bool verbose)
+{
+ struct udevice *dev;
+ int error = 0, i = 0, ret;
+
+ while (list_platname[i]) {
+ ret = regulator_autoset_by_name(list_platname[i], &dev);
+ if (ret != -EMEDIUMTYPE && verbose)
+ regulator_show(dev, ret);
+ if (ret & !error)
+ error = ret;
+
+ if (list_devp)
+ list_devp[i] = dev;
+
+ i++;
+ }
+
+ return error;
+}
+
+static bool regulator_name_is_unique(struct udevice *check_dev,
+ const char *check_name)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct udevice *dev;
+ int check_len = strlen(check_name);
+ int ret;
+ int len;
+
+ for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
+ ret = uclass_find_next_device(&dev)) {
+ if (ret || dev == check_dev)
+ continue;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ len = strlen(uc_pdata->name);
+ if (len != check_len)
+ continue;
+
+ if (!strcmp(uc_pdata->name, check_name))
+ return false;
+ }
+
+ return true;
+}
+
+static int regulator_post_bind(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ const char *property = "regulator-name";
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ /* Regulator's mandatory constraint */
+ uc_pdata->name = dev_read_string(dev, property);
+ if (!uc_pdata->name) {
+ debug("%s: dev '%s' has no property '%s'\n",
+ __func__, dev->name, property);
+ uc_pdata->name = dev_read_name(dev);
+ if (!uc_pdata->name)
+ return -EINVAL;
+ }
+
+ if (regulator_name_is_unique(dev, uc_pdata->name))
+ return 0;
+
+ debug("'%s' of dev: '%s', has nonunique value: '%s\n",
+ property, dev->name, uc_pdata->name);
+
+ return -EINVAL;
+}
+
+static int regulator_pre_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ ofnode node;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ if (!uc_pdata)
+ return -ENXIO;
+
+ /* Regulator's optional constraints */
+ uc_pdata->min_uV = dev_read_u32_default(dev, "regulator-min-microvolt",
+ -ENODATA);
+ uc_pdata->max_uV = dev_read_u32_default(dev, "regulator-max-microvolt",
+ -ENODATA);
+ uc_pdata->init_uV = dev_read_u32_default(dev, "regulator-init-microvolt",
+ -ENODATA);
+ uc_pdata->min_uA = dev_read_u32_default(dev, "regulator-min-microamp",
+ -ENODATA);
+ uc_pdata->max_uA = dev_read_u32_default(dev, "regulator-max-microamp",
+ -ENODATA);
+ uc_pdata->always_on = dev_read_bool(dev, "regulator-always-on");
+ uc_pdata->boot_on = dev_read_bool(dev, "regulator-boot-on");
+ uc_pdata->ramp_delay = dev_read_u32_default(dev, "regulator-ramp-delay",
+ 0);
+ uc_pdata->force_off = dev_read_bool(dev, "regulator-force-boot-off");
+
+ node = dev_read_subnode(dev, "regulator-state-mem");
+ if (ofnode_valid(node)) {
+ uc_pdata->suspend_on = !ofnode_read_bool(node, "regulator-off-in-suspend");
+ if (ofnode_read_u32(node, "regulator-suspend-microvolt", &uc_pdata->suspend_uV))
+ uc_pdata->suspend_uV = uc_pdata->max_uV;
+ } else {
+ uc_pdata->suspend_on = true;
+ uc_pdata->suspend_uV = uc_pdata->max_uV;
+ }
+
+ /* Those values are optional (-ENODATA if unset) */
+ if ((uc_pdata->min_uV != -ENODATA) &&
+ (uc_pdata->max_uV != -ENODATA) &&
+ (uc_pdata->min_uV == uc_pdata->max_uV))
+ uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
+
+ /* Those values are optional (-ENODATA if unset) */
+ if ((uc_pdata->min_uA != -ENODATA) &&
+ (uc_pdata->max_uA != -ENODATA) &&
+ (uc_pdata->min_uA == uc_pdata->max_uA))
+ uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
+
+ return 0;
+}
+
+int regulators_enable_boot_on(bool verbose)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_REGULATOR, &uc);
+ if (ret)
+ return ret;
+ for (uclass_first_device(UCLASS_REGULATOR, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ ret = regulator_autoset(dev);
+ if (ret == -EMEDIUMTYPE) {
+ ret = 0;
+ continue;
+ }
+ if (verbose)
+ regulator_show(dev, ret);
+ if (ret == -ENOSYS)
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int regulators_enable_boot_off(bool verbose)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_REGULATOR, &uc);
+ if (ret)
+ return ret;
+ for (uclass_first_device(UCLASS_REGULATOR, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ ret = regulator_unset(dev);
+ if (ret == -EMEDIUMTYPE) {
+ ret = 0;
+ continue;
+ }
+ if (verbose)
+ regulator_show(dev, ret);
+ if (ret == -ENOSYS)
+ ret = 0;
+ }
+
+ return ret;
+}
+
+UCLASS_DRIVER(regulator) = {
+ .id = UCLASS_REGULATOR,
+ .name = "regulator",
+ .post_bind = regulator_post_bind,
+ .pre_probe = regulator_pre_probe,
+ .per_device_plat_auto = sizeof(struct dm_regulator_uclass_plat),
+};
diff --git a/roms/u-boot/drivers/power/regulator/regulator_common.c b/roms/u-boot/drivers/power/regulator/regulator_common.c
new file mode 100644
index 000000000..93d8196b3
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/regulator_common.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Disruptive Technologies Research AS
+ * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+
+#include "regulator_common.h"
+
+int regulator_common_of_to_plat(struct udevice *dev,
+ struct regulator_common_plat *dev_pdata,
+ const char *enable_gpio_name)
+{
+ struct gpio_desc *gpio;
+ int flags = GPIOD_IS_OUT;
+ int ret;
+
+ if (!dev_read_bool(dev, "enable-active-high"))
+ flags |= GPIOD_ACTIVE_LOW;
+ if (dev_read_bool(dev, "regulator-boot-on"))
+ flags |= GPIOD_IS_OUT_ACTIVE;
+
+ /* Get optional enable GPIO desc */
+ gpio = &dev_pdata->gpio;
+ ret = gpio_request_by_name(dev, enable_gpio_name, 0, gpio, flags);
+ if (ret) {
+ debug("Regulator '%s' optional enable GPIO - not found! Error: %d\n",
+ dev->name, ret);
+ if (ret != -ENOENT)
+ return ret;
+ }
+
+ /* Get optional ramp up delay */
+ dev_pdata->startup_delay_us = dev_read_u32_default(dev,
+ "startup-delay-us", 0);
+ dev_pdata->off_on_delay_us =
+ dev_read_u32_default(dev, "off-on-delay-us", 0);
+ if (!dev_pdata->off_on_delay_us) {
+ dev_pdata->off_on_delay_us =
+ dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0);
+ }
+
+ return 0;
+}
+
+int regulator_common_get_enable(const struct udevice *dev,
+ struct regulator_common_plat *dev_pdata)
+{
+ /* Enable GPIO is optional */
+ if (!dev_pdata->gpio.dev)
+ return true;
+
+ return dm_gpio_get_value(&dev_pdata->gpio);
+}
+
+int regulator_common_set_enable(const struct udevice *dev,
+ struct regulator_common_plat *dev_pdata, bool enable)
+{
+ int ret;
+
+ debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__,
+ dev->name, enable, dev_pdata->startup_delay_us,
+ dm_gpio_is_valid(&dev_pdata->gpio));
+ /* Enable GPIO is optional */
+ if (!dm_gpio_is_valid(&dev_pdata->gpio)) {
+ if (!enable)
+ return -ENOSYS;
+ return 0;
+ }
+
+ ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
+ if (ret) {
+ pr_err("Can't set regulator : %s gpio to: %d\n", dev->name,
+ enable);
+ return ret;
+ }
+
+ if (enable && dev_pdata->startup_delay_us)
+ udelay(dev_pdata->startup_delay_us);
+ debug("%s: done\n", __func__);
+
+ if (!enable && dev_pdata->off_on_delay_us)
+ udelay(dev_pdata->off_on_delay_us);
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/regulator/regulator_common.h b/roms/u-boot/drivers/power/regulator/regulator_common.h
new file mode 100644
index 000000000..c10492f01
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/regulator_common.h
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Disruptive Technologies Research AS
+ * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com>
+ */
+
+#ifndef _REGULATOR_COMMON_H
+#define _REGULATOR_COMMON_H
+
+#include <asm/gpio.h>
+
+struct regulator_common_plat {
+ struct gpio_desc gpio; /* GPIO for regulator enable control */
+ unsigned int startup_delay_us;
+ unsigned int off_on_delay_us;
+};
+
+int regulator_common_of_to_plat(struct udevice *dev,
+ struct regulator_common_plat *dev_pdata, const
+ char *enable_gpio_name);
+int regulator_common_get_enable(const struct udevice *dev,
+ struct regulator_common_plat *dev_pdata);
+int regulator_common_set_enable(const struct udevice *dev,
+ struct regulator_common_plat *dev_pdata, bool enable);
+
+#endif /* _REGULATOR_COMMON_H */
diff --git a/roms/u-boot/drivers/power/regulator/rk8xx.c b/roms/u-boot/drivers/power/regulator/rk8xx.c
new file mode 100644
index 000000000..0ee07ad29
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/rk8xx.c
@@ -0,0 +1,1158 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * Based on Rockchip's drivers/power/pmic/pmic_rk808.c:
+ * Copyright (C) 2012 rockchips
+ * zyw <zyw@rock-chips.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <power/rk8xx_pmic.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#ifndef CONFIG_SPL_BUILD
+#define ENABLE_DRIVER
+#endif
+
+/* Not used or exisit register and configure */
+#define NA 0xff
+
+/* Field Definitions */
+#define RK808_BUCK_VSEL_MASK 0x3f
+#define RK808_BUCK4_VSEL_MASK 0xf
+#define RK808_LDO_VSEL_MASK 0x1f
+
+/* RK809 BUCK5 */
+#define RK809_BUCK5_CONFIG(n) (0xde + (n) * 1)
+#define RK809_BUCK5_VSEL_MASK 0x07
+
+/* RK817 BUCK */
+#define RK817_BUCK_ON_VSEL(n) (0xbb + 3 * ((n) - 1))
+#define RK817_BUCK_SLP_VSEL(n) (0xbc + 3 * ((n) - 1))
+#define RK817_BUCK_VSEL_MASK 0x7f
+#define RK817_BUCK_CONFIG(i) (0xba + (i) * 3)
+
+/* RK817 LDO */
+#define RK817_LDO_ON_VSEL(n) (0xcc + 2 * ((n) - 1))
+#define RK817_LDO_SLP_VSEL(n) (0xcd + 2 * ((n) - 1))
+#define RK817_LDO_VSEL_MASK 0x7f
+
+/* RK817 ENABLE */
+#define RK817_POWER_EN(n) (0xb1 + (n))
+#define RK817_POWER_SLP_EN(n) (0xb5 + (n))
+
+#define RK818_BUCK_VSEL_MASK 0x3f
+#define RK818_BUCK4_VSEL_MASK 0x1f
+#define RK818_LDO_VSEL_MASK 0x1f
+#define RK818_LDO3_ON_VSEL_MASK 0xf
+#define RK818_BOOST_ON_VSEL_MASK 0xe0
+#define RK818_USB_ILIM_SEL_MASK 0x0f
+#define RK818_USB_CHG_SD_VSEL_MASK 0x70
+
+/*
+ * Ramp delay
+ */
+#define RK805_RAMP_RATE_OFFSET 3
+#define RK805_RAMP_RATE_MASK (3 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_3MV_PER_US (0 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_6MV_PER_US (1 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_12_5MV_PER_US (2 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_25MV_PER_US (3 << RK805_RAMP_RATE_OFFSET)
+
+#define RK808_RAMP_RATE_OFFSET 3
+#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET)
+
+#define RK817_RAMP_RATE_OFFSET 6
+#define RK817_RAMP_RATE_MASK (0x3 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_3MV_PER_US (0x0 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_6_3MV_PER_US (0x1 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_12_5MV_PER_US (0x2 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_25MV_PER_US (0x3 << RK817_RAMP_RATE_OFFSET)
+
+struct rk8xx_reg_info {
+ uint min_uv;
+ uint step_uv;
+ u8 vsel_reg;
+ u8 vsel_sleep_reg;
+ u8 config_reg;
+ u8 vsel_mask;
+ u8 min_sel;
+};
+
+static const struct rk8xx_reg_info rk808_buck[] = {
+ { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, },
+ { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, },
+ { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK808_BUCK_VSEL_MASK, },
+ { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, },
+};
+
+static const struct rk8xx_reg_info rk816_buck[] = {
+ /* buck 1 */
+ { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
+ { 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
+ { 2300000, 0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
+ /* buck 2 */
+ { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
+ { 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
+ { 2300000, 0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
+ /* buck 3 */
+ { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
+ /* buck 4 */
+ { 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
+};
+
+static const struct rk8xx_reg_info rk809_buck5[] = {
+ /* buck 5 */
+ { 1500000, 0, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x00, },
+ { 1800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x01, },
+ { 2800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x04, },
+ { 3300000, 300000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x06, },
+};
+
+static const struct rk8xx_reg_info rk817_buck[] = {
+ /* buck 1 */
+ { 500000, 12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x50, },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x59, },
+ /* buck 2 */
+ { 500000, 12500, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x00, },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x50, },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x59, },
+ /* buck 3 */
+ { 500000, 12500, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x00, },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x50, },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x59, },
+ /* buck 4 */
+ { 500000, 12500, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x00, },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x50, },
+ { 3400000, 0, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x63, },
+};
+
+static const struct rk8xx_reg_info rk818_buck[] = {
+ { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, },
+ { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, },
+ { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
+ { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
+};
+
+#ifdef ENABLE_DRIVER
+static const struct rk8xx_reg_info rk808_ldo[] = {
+ { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK808_BUCK4_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+};
+
+static const struct rk8xx_reg_info rk816_ldo[] = {
+ { 800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+};
+
+static const struct rk8xx_reg_info rk817_ldo[] = {
+ /* ldo1 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo2 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo3 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo4 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo5 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo6 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo7 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo8 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo9 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x70, },
+};
+
+static const struct rk8xx_reg_info rk818_ldo[] = {
+ { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO3_ON_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+};
+#endif
+
+static const u16 rk818_chrg_cur_input_array[] = {
+ 450, 800, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000
+};
+
+static const uint rk818_chrg_shutdown_vsel_array[] = {
+ 2780000, 2850000, 2920000, 2990000, 3060000, 3130000, 3190000, 3260000
+};
+
+static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
+ int num, int uvolt)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ switch (num) {
+ case 0:
+ case 1:
+ if (uvolt <= 1450000)
+ return &rk816_buck[num * 3 + 0];
+ else if (uvolt <= 2200000)
+ return &rk816_buck[num * 3 + 1];
+ else
+ return &rk816_buck[num * 3 + 2];
+ default:
+ return &rk816_buck[num + 4];
+ }
+
+ case RK809_ID:
+ case RK817_ID:
+ switch (num) {
+ case 0 ... 2:
+ if (uvolt < 1500000)
+ return &rk817_buck[num * 3 + 0];
+ else if (uvolt < 2400000)
+ return &rk817_buck[num * 3 + 1];
+ else
+ return &rk817_buck[num * 3 + 2];
+ case 3:
+ if (uvolt < 1500000)
+ return &rk817_buck[num * 3 + 0];
+ else if (uvolt < 3400000)
+ return &rk817_buck[num * 3 + 1];
+ else
+ return &rk817_buck[num * 3 + 2];
+ /* BUCK5 for RK809 */
+ default:
+ if (uvolt < 1800000)
+ return &rk809_buck5[0];
+ else if (uvolt < 2800000)
+ return &rk809_buck5[1];
+ else if (uvolt < 3300000)
+ return &rk809_buck5[2];
+ else
+ return &rk809_buck5[3];
+ }
+ case RK818_ID:
+ return &rk818_buck[num];
+ default:
+ return &rk808_buck[num];
+ }
+}
+
+static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
+{
+ const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ int mask = info->vsel_mask;
+ int val;
+
+ if (info->vsel_reg == NA)
+ return -ENOSYS;
+
+ if (info->step_uv == 0) /* Fixed voltage */
+ val = info->min_sel;
+ else
+ val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+ debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+ __func__, uvolt, buck + 1, info->vsel_reg, mask, val);
+
+ if (priv->variant == RK816_ID) {
+ pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
+ return pmic_clrsetbits(pmic, RK816_REG_DCDC_EN2,
+ 1 << 7, 1 << 7);
+ } else {
+ return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
+ }
+}
+
+static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
+{
+ uint mask, value, en_reg;
+ int ret = 0;
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ if (buck >= 4) {
+ buck -= 4;
+ en_reg = RK816_REG_DCDC_EN2;
+ } else {
+ en_reg = RK816_REG_DCDC_EN1;
+ }
+ if (enable)
+ value = ((1 << buck) | (1 << (buck + 4)));
+ else
+ value = ((0 << buck) | (1 << (buck + 4)));
+ ret = pmic_reg_write(pmic, en_reg, value);
+ break;
+
+ case RK808_ID:
+ case RK818_ID:
+ mask = 1 << buck;
+ if (enable) {
+ ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX,
+ 0, 3 << (buck * 2));
+ if (ret)
+ return ret;
+ }
+ ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask,
+ enable ? mask : 0);
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ if (buck < 4) {
+ if (enable)
+ value = ((1 << buck) | (1 << (buck + 4)));
+ else
+ value = ((0 << buck) | (1 << (buck + 4)));
+ ret = pmic_reg_write(pmic, RK817_POWER_EN(0), value);
+ /* BUCK5 for RK809 */
+ } else {
+ if (enable)
+ value = ((1 << 1) | (1 << 5));
+ else
+ value = ((0 << 1) | (1 << 5));
+ ret = pmic_reg_write(pmic, RK817_POWER_EN(3), value);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+#ifdef ENABLE_DRIVER
+static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt)
+{
+ const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
+ int mask = info->vsel_mask;
+ int val;
+
+ if (info->vsel_sleep_reg == NA)
+ return -ENOSYS;
+
+ if (info->step_uv == 0)
+ val = info->min_sel;
+ else
+ val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+ debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+ __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val);
+
+ return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val);
+}
+
+static int _buck_get_enable(struct udevice *pmic, int buck)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint mask = 0;
+ int ret = 0;
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ if (buck >= 4) {
+ mask = 1 << (buck - 4);
+ ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN2);
+ } else {
+ mask = 1 << buck;
+ ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN1);
+ }
+ break;
+ case RK808_ID:
+ case RK818_ID:
+ mask = 1 << buck;
+ ret = pmic_reg_read(pmic, REG_DCDC_EN);
+ if (ret < 0)
+ return ret;
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ if (buck < 4) {
+ mask = 1 << buck;
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(0));
+ /* BUCK5 for RK809 */
+ } else {
+ mask = 1 << 1;
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
+ }
+ break;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return ret & mask ? true : false;
+}
+
+static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
+{
+ uint mask = 0;
+ int ret;
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ mask = 1 << buck;
+ ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask,
+ enable ? mask : 0);
+ break;
+ case RK808_ID:
+ case RK818_ID:
+ mask = 1 << buck;
+ ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask,
+ enable ? 0 : mask);
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ if (buck < 4)
+ mask = 1 << buck;
+ else
+ mask = 1 << 5; /* BUCK5 for RK809 */
+ ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
+ enable ? mask : 0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ int ret, val;
+ uint mask = 0;
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ mask = 1 << buck;
+ val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN);
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ break;
+ case RK808_ID:
+ case RK818_ID:
+ mask = 1 << buck;
+ val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF1);
+ if (val < 0)
+ return val;
+ ret = val & mask ? 0 : 1;
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ if (buck < 4)
+ mask = 1 << buck;
+ else
+ mask = 1 << 5; /* BUCK5 for RK809 */
+
+ val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
+ int num, int uvolt)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ return &rk816_ldo[num];
+ case RK809_ID:
+ case RK817_ID:
+ if (uvolt < 3400000)
+ return &rk817_ldo[num * 2 + 0];
+ else
+ return &rk817_ldo[num * 2 + 1];
+ case RK818_ID:
+ return &rk818_ldo[num];
+ default:
+ return &rk808_ldo[num];
+ }
+}
+
+static int _ldo_get_enable(struct udevice *pmic, int ldo)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint mask = 0;
+ int ret = 0;
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ if (ldo >= 4) {
+ mask = 1 << (ldo - 4);
+ ret = pmic_reg_read(pmic, RK816_REG_LDO_EN2);
+ } else {
+ mask = 1 << ldo;
+ ret = pmic_reg_read(pmic, RK816_REG_LDO_EN1);
+ }
+ break;
+ case RK808_ID:
+ case RK818_ID:
+ mask = 1 << ldo;
+ ret = pmic_reg_read(pmic, REG_LDO_EN);
+ if (ret < 0)
+ return ret;
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ if (ldo < 4) {
+ mask = 1 << ldo;
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(1));
+ } else if (ldo < 8) {
+ mask = 1 << (ldo - 4);
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(2));
+ } else if (ldo == 8) {
+ mask = 1 << 0;
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
+ } else {
+ return false;
+ }
+ break;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return ret & mask ? true : false;
+}
+
+static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint mask, value, en_reg;
+ int ret = 0;
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ if (ldo >= 4) {
+ ldo -= 4;
+ en_reg = RK816_REG_LDO_EN2;
+ } else {
+ en_reg = RK816_REG_LDO_EN1;
+ }
+ if (enable)
+ value = ((1 << ldo) | (1 << (ldo + 4)));
+ else
+ value = ((0 << ldo) | (1 << (ldo + 4)));
+
+ ret = pmic_reg_write(pmic, en_reg, value);
+ break;
+ case RK808_ID:
+ case RK818_ID:
+ mask = 1 << ldo;
+ ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
+ enable ? mask : 0);
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ if (ldo < 4) {
+ en_reg = RK817_POWER_EN(1);
+ } else if (ldo < 8) {
+ ldo -= 4;
+ en_reg = RK817_POWER_EN(2);
+ } else if (ldo == 8) {
+ ldo = 0; /* BIT 0 */
+ en_reg = RK817_POWER_EN(3);
+ } else {
+ return -EINVAL;
+ }
+ if (enable)
+ value = ((1 << ldo) | (1 << (ldo + 4)));
+ else
+ value = ((0 << ldo) | (1 << (ldo + 4)));
+ ret = pmic_reg_write(pmic, en_reg, value);
+ break;
+ }
+
+ return ret;
+}
+
+static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint mask;
+ int ret = 0;
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ mask = 1 << ldo;
+ ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask,
+ enable ? mask : 0);
+ break;
+ case RK808_ID:
+ case RK818_ID:
+ mask = 1 << ldo;
+ ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask,
+ enable ? 0 : mask);
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ if (ldo == 8) {
+ mask = 1 << 4; /* LDO9 */
+ ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
+ enable ? mask : 0);
+ } else {
+ mask = 1 << ldo;
+ ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(1), mask,
+ enable ? mask : 0);
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ int val, ret = 0;
+ uint mask;
+
+ switch (priv->variant) {
+ case RK805_ID:
+ case RK816_ID:
+ mask = 1 << ldo;
+ val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN);
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ break;
+ case RK808_ID:
+ case RK818_ID:
+ mask = 1 << ldo;
+ val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF2);
+ if (val < 0)
+ return val;
+ ret = val & mask ? 0 : 1;
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ if (ldo == 8) {
+ mask = 1 << 4; /* LDO9 */
+ val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ } else {
+ mask = 1 << ldo;
+ val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(1));
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int buck = dev->driver_data - 1;
+ /* We assume level-1 voltage is enough for usage in U-Boot */
+ const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
+ int mask = info->vsel_mask;
+ int ret, val;
+
+ if (info->vsel_reg == NA)
+ return -ENOSYS;
+
+ ret = pmic_reg_read(dev->parent, info->vsel_reg);
+ if (ret < 0)
+ return ret;
+ val = ret & mask;
+
+ return info->min_uv + val * info->step_uv;
+}
+
+static int buck_set_value(struct udevice *dev, int uvolt)
+{
+ int buck = dev->driver_data - 1;
+
+ return _buck_set_value(dev->parent, buck, uvolt);
+}
+
+static int buck_get_suspend_value(struct udevice *dev)
+{
+ int buck = dev->driver_data - 1;
+ /* We assume level-1 voltage is enough for usage in U-Boot */
+ const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
+ int mask = info->vsel_mask;
+ int ret, val;
+
+ if (info->vsel_sleep_reg == NA)
+ return -ENOSYS;
+
+ ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
+ if (ret < 0)
+ return ret;
+
+ val = ret & mask;
+
+ return info->min_uv + val * info->step_uv;
+}
+
+static int buck_set_suspend_value(struct udevice *dev, int uvolt)
+{
+ int buck = dev->driver_data - 1;
+
+ return _buck_set_suspend_value(dev->parent, buck, uvolt);
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ int buck = dev->driver_data - 1;
+
+ return _buck_set_enable(dev->parent, buck, enable);
+}
+
+static int buck_set_suspend_enable(struct udevice *dev, bool enable)
+{
+ int buck = dev->driver_data - 1;
+
+ return _buck_set_suspend_enable(dev->parent, buck, enable);
+}
+
+static int buck_get_suspend_enable(struct udevice *dev)
+{
+ int buck = dev->driver_data - 1;
+
+ return _buck_get_suspend_enable(dev->parent, buck);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ int buck = dev->driver_data - 1;
+
+ return _buck_get_enable(dev->parent, buck);
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int ldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
+ int mask = info->vsel_mask;
+ int ret, val;
+
+ if (info->vsel_reg == NA)
+ return -ENOSYS;
+ ret = pmic_reg_read(dev->parent, info->vsel_reg);
+ if (ret < 0)
+ return ret;
+ val = ret & mask;
+
+ return info->min_uv + val * info->step_uv;
+}
+
+static int ldo_set_value(struct udevice *dev, int uvolt)
+{
+ int ldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
+ int mask = info->vsel_mask;
+ int val;
+
+ if (info->vsel_reg == NA)
+ return -ENOSYS;
+
+ if (info->step_uv == 0)
+ val = info->min_sel;
+ else
+ val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+ debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+ __func__, uvolt, ldo + 1, info->vsel_reg, mask, val);
+
+ return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
+}
+
+static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
+{
+ int ldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
+ int mask = info->vsel_mask;
+ int val;
+
+ if (info->vsel_sleep_reg == NA)
+ return -ENOSYS;
+
+ if (info->step_uv == 0)
+ val = info->min_sel;
+ else
+ val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+ debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+ __func__, uvolt, ldo + 1, info->vsel_sleep_reg, mask, val);
+
+ return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val);
+}
+
+static int ldo_get_suspend_value(struct udevice *dev)
+{
+ int ldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
+ int mask = info->vsel_mask;
+ int val, ret;
+
+ if (info->vsel_sleep_reg == NA)
+ return -ENOSYS;
+
+ ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
+ if (ret < 0)
+ return ret;
+
+ val = ret & mask;
+
+ return info->min_uv + val * info->step_uv;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ int ldo = dev->driver_data - 1;
+
+ return _ldo_set_enable(dev->parent, ldo, enable);
+}
+
+static int ldo_set_suspend_enable(struct udevice *dev, bool enable)
+{
+ int ldo = dev->driver_data - 1;
+
+ return _ldo_set_suspend_enable(dev->parent, ldo, enable);
+}
+
+static int ldo_get_suspend_enable(struct udevice *dev)
+{
+ int ldo = dev->driver_data - 1;
+
+ return _ldo_get_suspend_enable(dev->parent, ldo);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ int ldo = dev->driver_data - 1;
+
+ return _ldo_get_enable(dev->parent, ldo);
+}
+
+static int switch_set_enable(struct udevice *dev, bool enable)
+{
+ struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+ int ret = 0, sw = dev->driver_data - 1;
+ uint mask = 0;
+
+ switch (priv->variant) {
+ case RK808_ID:
+ mask = 1 << (sw + 5);
+ ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
+ enable ? mask : 0);
+ break;
+ case RK809_ID:
+ mask = (1 << (sw + 2)) | (1 << (sw + 6));
+ ret = pmic_clrsetbits(dev->parent, RK817_POWER_EN(3), mask,
+ enable ? mask : 0);
+ break;
+ case RK818_ID:
+ mask = 1 << 6;
+ ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
+ enable ? mask : 0);
+ break;
+ }
+
+ debug("%s: switch%d, enable=%d, mask=0x%x\n",
+ __func__, sw + 1, enable, mask);
+
+ return ret;
+}
+
+static int switch_get_enable(struct udevice *dev)
+{
+ struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+ int ret = 0, sw = dev->driver_data - 1;
+ uint mask = 0;
+
+ switch (priv->variant) {
+ case RK808_ID:
+ mask = 1 << (sw + 5);
+ ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
+ break;
+ case RK809_ID:
+ mask = 1 << (sw + 2);
+ ret = pmic_reg_read(dev->parent, RK817_POWER_EN(3));
+ break;
+ case RK818_ID:
+ mask = 1 << 6;
+ ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
+ break;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return ret & mask ? true : false;
+}
+
+static int switch_set_suspend_value(struct udevice *dev, int uvolt)
+{
+ return 0;
+}
+
+static int switch_get_suspend_value(struct udevice *dev)
+{
+ return 0;
+}
+
+static int switch_set_suspend_enable(struct udevice *dev, bool enable)
+{
+ struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+ int ret = 0, sw = dev->driver_data - 1;
+ uint mask = 0;
+
+ switch (priv->variant) {
+ case RK808_ID:
+ mask = 1 << (sw + 5);
+ ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
+ enable ? 0 : mask);
+ break;
+ case RK809_ID:
+ mask = 1 << (sw + 6);
+ ret = pmic_clrsetbits(dev->parent, RK817_POWER_SLP_EN(0), mask,
+ enable ? mask : 0);
+ break;
+ case RK818_ID:
+ mask = 1 << 6;
+ ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
+ enable ? 0 : mask);
+ break;
+ }
+
+ debug("%s: switch%d, enable=%d, mask=0x%x\n",
+ __func__, sw + 1, enable, mask);
+
+ return ret;
+}
+
+static int switch_get_suspend_enable(struct udevice *dev)
+{
+ struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+ int val, ret = 0, sw = dev->driver_data - 1;
+ uint mask = 0;
+
+ switch (priv->variant) {
+ case RK808_ID:
+ mask = 1 << (sw + 5);
+ val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
+ if (val < 0)
+ return val;
+ ret = val & mask ? 0 : 1;
+ break;
+ case RK809_ID:
+ mask = 1 << (sw + 6);
+ val = pmic_reg_read(dev->parent, RK817_POWER_SLP_EN(0));
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ break;
+ case RK818_ID:
+ mask = 1 << 6;
+ val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
+ if (val < 0)
+ return val;
+ ret = val & mask ? 0 : 1;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * RK8xx switch does not need to set the voltage,
+ * but if dts set regulator-min-microvolt/regulator-max-microvolt,
+ * will cause regulator set value fail and not to enable this switch.
+ * So add an empty function to return success.
+ */
+static int switch_get_value(struct udevice *dev)
+{
+ return 0;
+}
+
+static int switch_set_value(struct udevice *dev, int uvolt)
+{
+ return 0;
+}
+
+static int rk8xx_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static int rk8xx_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static int rk8xx_switch_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_FIXED;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops rk8xx_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .set_suspend_value = buck_set_suspend_value,
+ .get_suspend_value = buck_get_suspend_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+ .set_suspend_enable = buck_set_suspend_enable,
+ .get_suspend_enable = buck_get_suspend_enable,
+};
+
+static const struct dm_regulator_ops rk8xx_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .set_suspend_value = ldo_set_suspend_value,
+ .get_suspend_value = ldo_get_suspend_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+ .set_suspend_enable = ldo_set_suspend_enable,
+ .get_suspend_enable = ldo_get_suspend_enable,
+};
+
+static const struct dm_regulator_ops rk8xx_switch_ops = {
+ .get_value = switch_get_value,
+ .set_value = switch_set_value,
+ .get_enable = switch_get_enable,
+ .set_enable = switch_set_enable,
+ .set_suspend_enable = switch_set_suspend_enable,
+ .get_suspend_enable = switch_get_suspend_enable,
+ .set_suspend_value = switch_set_suspend_value,
+ .get_suspend_value = switch_get_suspend_value,
+};
+
+U_BOOT_DRIVER(rk8xx_buck) = {
+ .name = "rk8xx_buck",
+ .id = UCLASS_REGULATOR,
+ .ops = &rk8xx_buck_ops,
+ .probe = rk8xx_buck_probe,
+};
+
+U_BOOT_DRIVER(rk8xx_ldo) = {
+ .name = "rk8xx_ldo",
+ .id = UCLASS_REGULATOR,
+ .ops = &rk8xx_ldo_ops,
+ .probe = rk8xx_ldo_probe,
+};
+
+U_BOOT_DRIVER(rk8xx_switch) = {
+ .name = "rk8xx_switch",
+ .id = UCLASS_REGULATOR,
+ .ops = &rk8xx_switch_ops,
+ .probe = rk8xx_switch_probe,
+};
+#endif
+
+int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
+{
+ int ret;
+
+ ret = _buck_set_value(pmic, buck, uvolt);
+ if (ret)
+ return ret;
+
+ return _buck_set_enable(pmic, buck, true);
+}
+
+int rk818_spl_configure_usb_input_current(struct udevice *pmic, int current_ma)
+{
+ uint i;
+
+ for (i = 0; i < ARRAY_SIZE(rk818_chrg_cur_input_array); i++)
+ if (current_ma <= rk818_chrg_cur_input_array[i])
+ break;
+
+ return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_ILIM_SEL_MASK, i);
+}
+
+int rk818_spl_configure_usb_chrg_shutdown(struct udevice *pmic, int uvolt)
+{
+ uint i;
+
+ for (i = 0; i < ARRAY_SIZE(rk818_chrg_shutdown_vsel_array); i++)
+ if (uvolt <= rk818_chrg_shutdown_vsel_array[i])
+ break;
+
+ return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_CHG_SD_VSEL_MASK,
+ i);
+}
diff --git a/roms/u-boot/drivers/power/regulator/s2mps11_regulator.c b/roms/u-boot/drivers/power/regulator/s2mps11_regulator.c
new file mode 100644
index 000000000..1c6d8358d
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/s2mps11_regulator.c
@@ -0,0 +1,608 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Samsung Electronics
+ * Jaehoon Chung <jh80.chung@samsung.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <linux/delay.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/s2mps11.h>
+
+#define MODE(_id, _val, _name) { \
+ .id = _id, \
+ .register_value = _val, \
+ .name = _name, \
+}
+
+/* BUCK : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 */
+static struct dm_regulator_mode s2mps11_buck_modes[] = {
+ MODE(OP_OFF, S2MPS11_BUCK_MODE_OFF, "OFF"),
+ MODE(OP_STANDBY, S2MPS11_BUCK_MODE_STANDBY, "ON/OFF"),
+ MODE(OP_ON, S2MPS11_BUCK_MODE_STANDBY, "ON"),
+};
+
+static struct dm_regulator_mode s2mps11_ldo_modes[] = {
+ MODE(OP_OFF, S2MPS11_LDO_MODE_OFF, "OFF"),
+ MODE(OP_STANDBY, S2MPS11_LDO_MODE_STANDBY, "ON/OFF"),
+ MODE(OP_STANDBY_LPM, S2MPS11_LDO_MODE_STANDBY_LPM, "ON/LPM"),
+ MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"),
+};
+
+static const char s2mps11_buck_ctrl[] = {
+ 0xff, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x37, 0x39, 0x3b
+};
+
+static const char s2mps11_buck_out[] = {
+ 0xff, 0x26, 0x28, 0x2a, 0x2c, 0x2f, 0x34, 0x36, 0x38, 0x3a, 0x3c
+};
+
+static int s2mps11_buck_hex2volt(int buck, int hex)
+{
+ unsigned int uV = 0;
+
+ if (hex < 0)
+ goto bad;
+
+ switch (buck) {
+ case 7:
+ case 8:
+ case 10:
+ if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
+ goto bad;
+
+ uV = hex * S2MPS11_BUCK_HSTEP + S2MPS11_BUCK_UV_HMIN;
+ break;
+ case 9:
+ if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
+ goto bad;
+ uV = hex * S2MPS11_BUCK9_STEP * 2 + S2MPS11_BUCK9_UV_MIN;
+ break;
+ default:
+ if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX)
+ goto bad;
+ else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX)
+ goto bad;
+
+ uV = hex * S2MPS11_BUCK_LSTEP + S2MPS11_BUCK_UV_MIN;
+ break;
+ }
+
+ return uV;
+bad:
+ pr_err("Value: %#x is wrong for BUCK%d", hex, buck);
+ return -EINVAL;
+}
+
+static int s2mps11_buck_volt2hex(int buck, int uV)
+{
+ int hex;
+
+ switch (buck) {
+ case 7:
+ case 8:
+ case 10:
+ hex = (uV - S2MPS11_BUCK_UV_HMIN) / S2MPS11_BUCK_HSTEP;
+ if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
+ goto bad;
+
+ break;
+ case 9:
+ hex = (uV - S2MPS11_BUCK9_UV_MIN) / S2MPS11_BUCK9_STEP;
+ if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
+ goto bad;
+ break;
+ default:
+ hex = (uV - S2MPS11_BUCK_UV_MIN) / S2MPS11_BUCK_LSTEP;
+ if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX)
+ goto bad;
+ else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX)
+ goto bad;
+ break;
+ };
+
+ if (hex >= 0)
+ return hex;
+
+bad:
+ pr_err("Value: %d uV is wrong for BUCK%d", uV, buck);
+ return -EINVAL;
+}
+
+static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
+{
+ int hex, buck, ret;
+ u32 mask, addr;
+ u8 val;
+
+ buck = dev->driver_data;
+ if (buck < 1 || buck > S2MPS11_BUCK_NUM) {
+ pr_err("Wrong buck number: %d\n", buck);
+ return -EINVAL;
+ }
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ addr = s2mps11_buck_out[buck];
+
+ switch (buck) {
+ case 9:
+ mask = S2MPS11_BUCK9_VOLT_MASK;
+ break;
+ default:
+ mask = S2MPS11_BUCK_VOLT_MASK;
+ break;
+ }
+
+ ret = pmic_read(dev->parent, addr, &val, 1);
+ if (ret)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ val &= mask;
+ ret = s2mps11_buck_hex2volt(buck, val);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+ return 0;
+ }
+
+ hex = s2mps11_buck_volt2hex(buck, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~mask;
+ val |= hex;
+ ret = pmic_write(dev->parent, addr, &val, 1);
+
+ return ret;
+}
+
+static int s2mps11_buck_mode(struct udevice *dev, int op, int *opmode)
+{
+ unsigned int addr, mode;
+ unsigned char val;
+ int buck, ret;
+
+ buck = dev->driver_data;
+ if (buck < 1 || buck > S2MPS11_BUCK_NUM) {
+ pr_err("Wrong buck number: %d\n", buck);
+ return -EINVAL;
+ }
+
+ addr = s2mps11_buck_ctrl[buck];
+
+ ret = pmic_read(dev->parent, addr, &val, 1);
+ if (ret)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ val &= (S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT);
+ switch (val) {
+ case S2MPS11_BUCK_MODE_OFF:
+ *opmode = OP_OFF;
+ break;
+ case S2MPS11_BUCK_MODE_STANDBY:
+ *opmode = OP_STANDBY;
+ break;
+ case S2MPS11_BUCK_MODE_ON:
+ *opmode = OP_ON;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ switch (*opmode) {
+ case OP_OFF:
+ mode = S2MPS11_BUCK_MODE_OFF;
+ break;
+ case OP_STANDBY:
+ mode = S2MPS11_BUCK_MODE_STANDBY;
+ break;
+ case OP_ON:
+ mode = S2MPS11_BUCK_MODE_ON;
+ break;
+ default:
+ pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck);
+ return -EINVAL;
+ }
+
+ val &= ~(S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT);
+ val |= mode;
+ ret = pmic_write(dev->parent, addr, &val, 1);
+
+ return ret;
+}
+
+static int s2mps11_buck_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret, on_off;
+
+ if (op == PMIC_OP_GET) {
+ ret = s2mps11_buck_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+ switch (on_off) {
+ case OP_OFF:
+ *enable = false;
+ break;
+ case OP_ON:
+ *enable = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ on_off = OP_ON;
+ else
+ on_off = OP_OFF;
+
+ ret = s2mps11_buck_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = s2mps11_buck_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+ return uV;
+}
+
+static int buck_set_value(struct udevice *dev, int uV)
+{
+ return s2mps11_buck_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = s2mps11_buck_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+ return enable;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ return s2mps11_buck_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int buck_get_mode(struct udevice *dev)
+{
+ int mode;
+ int ret;
+
+ ret = s2mps11_buck_mode(dev, PMIC_OP_GET, &mode);
+ if (ret)
+ return ret;
+
+ return mode;
+}
+
+static int buck_set_mode(struct udevice *dev, int mode)
+{
+ return s2mps11_buck_mode(dev, PMIC_OP_SET, &mode);
+}
+
+static int s2mps11_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode = s2mps11_buck_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mps11_buck_modes);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops s2mps11_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+ .get_mode = buck_get_mode,
+ .set_mode = buck_set_mode,
+};
+
+U_BOOT_DRIVER(s2mps11_buck) = {
+ .name = S2MPS11_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &s2mps11_buck_ops,
+ .probe = s2mps11_buck_probe,
+};
+
+static int s2mps11_ldo_hex2volt(int ldo, int hex)
+{
+ unsigned int uV = 0;
+
+ if (hex > S2MPS11_LDO_VOLT_MAX_HEX) {
+ pr_err("Value: %#x is wrong for LDO%d", hex, ldo);
+ return -EINVAL;
+ }
+
+ switch (ldo) {
+ case 1:
+ case 6:
+ case 11:
+ case 22:
+ case 23:
+ case 27:
+ case 35:
+ uV = hex * S2MPS11_LDO_STEP + S2MPS11_LDO_UV_MIN;
+ break;
+ default:
+ uV = hex * S2MPS11_LDO_STEP * 2 + S2MPS11_LDO_UV_MIN;
+ break;
+ }
+
+ return uV;
+}
+
+static int s2mps11_ldo_volt2hex(int ldo, int uV)
+{
+ int hex = 0;
+
+ switch (ldo) {
+ case 1:
+ case 6:
+ case 11:
+ case 22:
+ case 23:
+ case 27:
+ case 35:
+ hex = (uV - S2MPS11_LDO_UV_MIN) / S2MPS11_LDO_STEP;
+ break;
+ default:
+ hex = (uV - S2MPS11_LDO_UV_MIN) / (S2MPS11_LDO_STEP * 2);
+ break;
+ }
+
+ if (hex >= 0 && hex <= S2MPS11_LDO_VOLT_MAX_HEX)
+ return hex;
+
+ pr_err("Value: %d uV is wrong for LDO%d", uV, ldo);
+ return -EINVAL;
+
+ return 0;
+}
+
+static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int addr;
+ unsigned char val;
+ int hex, ldo, ret;
+
+ ldo = dev->driver_data;
+ if (ldo < 1 || ldo > S2MPS11_LDO_NUM) {
+ pr_err("Wrong ldo number: %d\n", ldo);
+ return -EINVAL;
+ }
+
+ addr = S2MPS11_REG_L1CTRL + ldo - 1;
+
+ ret = pmic_read(dev->parent, addr, &val, 1);
+ if (ret)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+ val &= S2MPS11_LDO_VOLT_MASK;
+ ret = s2mps11_ldo_hex2volt(ldo, val);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = s2mps11_ldo_volt2hex(ldo, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~S2MPS11_LDO_VOLT_MASK;
+ val |= hex;
+ ret = pmic_write(dev->parent, addr, &val, 1);
+
+ return ret;
+}
+
+static int s2mps11_ldo_mode(struct udevice *dev, int op, int *opmode)
+{
+ unsigned int addr, mode;
+ unsigned char val;
+ int ldo, ret;
+
+ ldo = dev->driver_data;
+ if (ldo < 1 || ldo > S2MPS11_LDO_NUM) {
+ pr_err("Wrong ldo number: %d\n", ldo);
+ return -EINVAL;
+ }
+ addr = S2MPS11_REG_L1CTRL + ldo - 1;
+
+ ret = pmic_read(dev->parent, addr, &val, 1);
+ if (ret)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ val &= (S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT);
+ switch (val) {
+ case S2MPS11_LDO_MODE_OFF:
+ *opmode = OP_OFF;
+ break;
+ case S2MPS11_LDO_MODE_STANDBY:
+ *opmode = OP_STANDBY;
+ break;
+ case S2MPS11_LDO_MODE_STANDBY_LPM:
+ *opmode = OP_STANDBY_LPM;
+ break;
+ case S2MPS11_LDO_MODE_ON:
+ *opmode = OP_ON;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ switch (*opmode) {
+ case OP_OFF:
+ mode = S2MPS11_LDO_MODE_OFF;
+ break;
+ case OP_STANDBY:
+ mode = S2MPS11_LDO_MODE_STANDBY;
+ break;
+ case OP_STANDBY_LPM:
+ mode = S2MPS11_LDO_MODE_STANDBY_LPM;
+ break;
+ case OP_ON:
+ mode = S2MPS11_LDO_MODE_ON;
+ break;
+ default:
+ pr_err("Wrong mode: %d for ldo: %d\n", *opmode, ldo);
+ return -EINVAL;
+ }
+
+ val &= ~(S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT);
+ val |= mode;
+ ret = pmic_write(dev->parent, addr, &val, 1);
+
+ return ret;
+}
+
+static int s2mps11_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret, on_off;
+
+ if (op == PMIC_OP_GET) {
+ ret = s2mps11_ldo_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+ switch (on_off) {
+ case OP_OFF:
+ *enable = false;
+ break;
+ case OP_ON:
+ *enable = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ on_off = OP_ON;
+ else
+ on_off = OP_OFF;
+
+ ret = s2mps11_ldo_mode(dev, op, &on_off);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = s2mps11_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return s2mps11_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = s2mps11_ldo_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+ return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ int ret;
+
+ ret = s2mps11_ldo_enable(dev, PMIC_OP_SET, &enable);
+ if (ret)
+ return ret;
+
+ /* Wait the "enable delay" for voltage to start to rise */
+ udelay(15);
+
+ return 0;
+}
+
+static int ldo_get_mode(struct udevice *dev)
+{
+ int mode, ret;
+
+ ret = s2mps11_ldo_mode(dev, PMIC_OP_GET, &mode);
+ if (ret)
+ return ret;
+ return mode;
+}
+
+static int ldo_set_mode(struct udevice *dev, int mode)
+{
+ return s2mps11_ldo_mode(dev, PMIC_OP_SET, &mode);
+}
+
+static int s2mps11_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode = s2mps11_ldo_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mps11_ldo_modes);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops s2mps11_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+ .get_mode = ldo_get_mode,
+ .set_mode = ldo_set_mode,
+};
+
+U_BOOT_DRIVER(s2mps11_ldo) = {
+ .name = S2MPS11_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &s2mps11_ldo_ops,
+ .probe = s2mps11_ldo_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/s5m8767.c b/roms/u-boot/drivers/power/regulator/s5m8767.c
new file mode 100644
index 000000000..ad0b98621
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/s5m8767.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/s5m8767.h>
+
+static const struct sec_voltage_desc buck_v1 = {
+ .max = 2225000,
+ .min = 650000,
+ .step = 6250,
+};
+
+static const struct sec_voltage_desc buck_v2 = {
+ .max = 1600000,
+ .min = 600000,
+ .step = 6250,
+};
+
+static const struct sec_voltage_desc buck_v3 = {
+ .max = 3000000,
+ .min = 750000,
+ .step = 12500,
+};
+
+static const struct sec_voltage_desc ldo_v1 = {
+ .max = 3950000,
+ .min = 800000,
+ .step = 50000,
+};
+
+static const struct sec_voltage_desc ldo_v2 = {
+ .max = 2375000,
+ .min = 800000,
+ .step = 25000,
+};
+
+static const struct s5m8767_para buck_param[] = {
+ /*
+ * | voltage ----| | enable -| voltage
+ * regnum addr bpos mask addr on desc
+ */
+ {S5M8767_BUCK1, 0x33, 0x0, 0xff, 0x32, 0x3, &buck_v1},
+ {S5M8767_BUCK2, 0x35, 0x0, 0xff, 0x34, 0x1, &buck_v2},
+ {S5M8767_BUCK3, 0x3e, 0x0, 0xff, 0x3d, 0x1, &buck_v2},
+ {S5M8767_BUCK4, 0x47, 0x0, 0xff, 0x46, 0x1, &buck_v2},
+ {S5M8767_BUCK5, 0x50, 0x0, 0xff, 0x4f, 0x3, &buck_v1},
+ {S5M8767_BUCK6, 0x55, 0x0, 0xff, 0x54, 0x3, &buck_v1},
+ {S5M8767_BUCK7, 0x57, 0x0, 0xff, 0x56, 0x3, &buck_v3},
+ {S5M8767_BUCK8, 0x59, 0x0, 0xff, 0x58, 0x3, &buck_v3},
+ {S5M8767_BUCK9, 0x5b, 0x0, 0xff, 0x5a, 0x3, &buck_v3},
+};
+
+static const struct s5m8767_para ldo_param[] = {
+ {S5M8767_LDO1, 0x5c, 0x0, 0x3f, 0x5c, 0x3, &ldo_v2},
+ {S5M8767_LDO2, 0x5d, 0x0, 0x3f, 0x5d, 0x1, &ldo_v2},
+ {S5M8767_LDO3, 0x61, 0x0, 0x3f, 0x61, 0x3, &ldo_v1},
+ {S5M8767_LDO4, 0x62, 0x0, 0x3f, 0x62, 0x3, &ldo_v1},
+ {S5M8767_LDO5, 0x63, 0x0, 0x3f, 0x63, 0x3, &ldo_v1},
+ {S5M8767_LDO6, 0x64, 0x0, 0x3f, 0x64, 0x1, &ldo_v2},
+ {S5M8767_LDO7, 0x65, 0x0, 0x3f, 0x65, 0x1, &ldo_v2},
+ {S5M8767_LDO8, 0x66, 0x0, 0x3f, 0x66, 0x1, &ldo_v2},
+ {S5M8767_LDO9, 0x67, 0x0, 0x3f, 0x67, 0x3, &ldo_v1},
+ {S5M8767_LDO10, 0x68, 0x0, 0x3f, 0x68, 0x1, &ldo_v1},
+ {S5M8767_LDO11, 0x69, 0x0, 0x3f, 0x69, 0x1, &ldo_v1},
+ {S5M8767_LDO12, 0x6a, 0x0, 0x3f, 0x6a, 0x1, &ldo_v1},
+ {S5M8767_LDO13, 0x6b, 0x0, 0x3f, 0x6b, 0x3, &ldo_v1},
+ {S5M8767_LDO14, 0x6c, 0x0, 0x3f, 0x6c, 0x1, &ldo_v1},
+ {S5M8767_LDO15, 0x6d, 0x0, 0x3f, 0x6d, 0x1, &ldo_v2},
+ {S5M8767_LDO16, 0x6e, 0x0, 0x3f, 0x6e, 0x1, &ldo_v1},
+ {S5M8767_LDO17, 0x6f, 0x0, 0x3f, 0x6f, 0x3, &ldo_v1},
+ {S5M8767_LDO18, 0x70, 0x0, 0x3f, 0x70, 0x3, &ldo_v1},
+ {S5M8767_LDO19, 0x71, 0x0, 0x3f, 0x71, 0x3, &ldo_v1},
+ {S5M8767_LDO20, 0x72, 0x0, 0x3f, 0x72, 0x3, &ldo_v1},
+ {S5M8767_LDO21, 0x73, 0x0, 0x3f, 0x73, 0x3, &ldo_v1},
+ {S5M8767_LDO22, 0x74, 0x0, 0x3f, 0x74, 0x3, &ldo_v1},
+ {S5M8767_LDO23, 0x75, 0x0, 0x3f, 0x75, 0x3, &ldo_v1},
+ {S5M8767_LDO24, 0x76, 0x0, 0x3f, 0x76, 0x3, &ldo_v1},
+ {S5M8767_LDO25, 0x77, 0x0, 0x3f, 0x77, 0x3, &ldo_v1},
+ {S5M8767_LDO26, 0x78, 0x0, 0x3f, 0x78, 0x3, &ldo_v1},
+ {S5M8767_LDO27, 0x79, 0x0, 0x3f, 0x79, 0x3, &ldo_v1},
+ {S5M8767_LDO28, 0x7a, 0x0, 0x3f, 0x7a, 0x3, &ldo_v1},
+};
+
+enum {
+ ENABLE_SHIFT = 6,
+ ENABLE_MASK = 3,
+};
+
+static int reg_get_value(struct udevice *dev, const struct s5m8767_para *param)
+{
+ const struct sec_voltage_desc *desc;
+ int ret, uv, val;
+
+ ret = pmic_reg_read(dev->parent, param->vol_addr);
+ if (ret < 0)
+ return ret;
+
+ desc = param->vol;
+ val = (ret >> param->vol_bitpos) & param->vol_bitmask;
+ uv = desc->min + val * desc->step;
+
+ return uv;
+}
+
+static int reg_set_value(struct udevice *dev, const struct s5m8767_para *param,
+ int uv)
+{
+ const struct sec_voltage_desc *desc;
+ int ret, val;
+
+ desc = param->vol;
+ if (uv < desc->min || uv > desc->max)
+ return -EINVAL;
+ val = (uv - desc->min) / desc->step;
+ val = (val & param->vol_bitmask) << param->vol_bitpos;
+ ret = pmic_clrsetbits(dev->parent, param->vol_addr,
+ param->vol_bitmask << param->vol_bitpos,
+ val);
+
+ return ret;
+}
+
+static int s5m8767_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+static int ldo_get_value(struct udevice *dev)
+{
+ int ldo = dev->driver_data;
+
+ return reg_get_value(dev, &ldo_param[ldo]);
+}
+
+static int ldo_set_value(struct udevice *dev, int uv)
+{
+ int ldo = dev->driver_data;
+
+ return reg_set_value(dev, &ldo_param[ldo], uv);
+}
+
+static int reg_get_enable(struct udevice *dev, const struct s5m8767_para *param)
+{
+ bool enable;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, param->reg_enaddr);
+ if (ret < 0)
+ return ret;
+
+ enable = (ret >> ENABLE_SHIFT) & ENABLE_MASK;
+
+ return enable;
+}
+
+static int reg_set_enable(struct udevice *dev, const struct s5m8767_para *param,
+ bool enable)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, param->reg_enaddr);
+ if (ret < 0)
+ return ret;
+
+ ret = pmic_clrsetbits(dev->parent, param->reg_enaddr,
+ ENABLE_MASK << ENABLE_SHIFT,
+ enable ? param->reg_enbiton << ENABLE_SHIFT : 0);
+
+ return ret;
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ int ldo = dev->driver_data;
+
+ return reg_get_enable(dev, &ldo_param[ldo]);
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ int ldo = dev->driver_data;
+
+ return reg_set_enable(dev, &ldo_param[ldo], enable);
+}
+
+static int s5m8767_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int buck = dev->driver_data;
+
+ return reg_get_value(dev, &buck_param[buck]);
+}
+
+static int buck_set_value(struct udevice *dev, int uv)
+{
+ int buck = dev->driver_data;
+
+ return reg_set_value(dev, &buck_param[buck], uv);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ int buck = dev->driver_data;
+
+ return reg_get_enable(dev, &buck_param[buck]);
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ int buck = dev->driver_data;
+
+ return reg_set_enable(dev, &buck_param[buck], enable);
+}
+
+static const struct dm_regulator_ops s5m8767_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+};
+
+U_BOOT_DRIVER(s5m8767_ldo) = {
+ .name = S5M8767_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &s5m8767_ldo_ops,
+ .probe = s5m8767_ldo_probe,
+};
+
+static const struct dm_regulator_ops s5m8767_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+};
+
+U_BOOT_DRIVER(s5m8767_buck) = {
+ .name = S5M8767_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &s5m8767_buck_ops,
+ .probe = s5m8767_buck_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/sandbox.c b/roms/u-boot/drivers/power/regulator/sandbox.c
new file mode 100644
index 000000000..c52fe3d10
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/sandbox.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/sandbox_pmic.h>
+
+#define MODE(_id, _val, _name) [_id] = { \
+ .id = _id, \
+ .register_value = _val, \
+ .name = _name, \
+}
+
+#define RANGE(_min, _max, _step) { \
+ .min = _min, \
+ .max = _max, \
+ .step = _step, \
+}
+
+/*
+ * struct output_range - helper structure type to define the range of output
+ * operating values (current/voltage), limited by the PMIC IC design.
+ *
+ * @min - minimum value
+ * @max - maximum value
+ * @step - step value
+*/
+struct output_range {
+ int min;
+ int max;
+ int step;
+};
+
+/* BUCK: 1,2 - voltage range */
+static struct output_range buck_voltage_range[] = {
+ RANGE(OUT_BUCK1_UV_MIN, OUT_BUCK1_UV_MAX, OUT_BUCK1_UV_STEP),
+ RANGE(OUT_BUCK2_UV_MIN, OUT_BUCK2_UV_MAX, OUT_BUCK2_UV_STEP),
+};
+
+/* BUCK: 1 - current range */
+static struct output_range buck_current_range[] = {
+ RANGE(OUT_BUCK1_UA_MIN, OUT_BUCK1_UA_MAX, OUT_BUCK1_UA_STEP),
+};
+
+/* BUCK operating modes */
+static struct dm_regulator_mode sandbox_buck_modes[] = {
+ MODE(BUCK_OM_OFF, OM2REG(BUCK_OM_OFF), "OFF"),
+ MODE(BUCK_OM_ON, OM2REG(BUCK_OM_ON), "ON"),
+ MODE(BUCK_OM_PWM, OM2REG(BUCK_OM_PWM), "PWM"),
+};
+
+/* LDO: 1,2 - voltage range */
+static struct output_range ldo_voltage_range[] = {
+ RANGE(OUT_LDO1_UV_MIN, OUT_LDO1_UV_MAX, OUT_LDO1_UV_STEP),
+ RANGE(OUT_LDO2_UV_MIN, OUT_LDO2_UV_MAX, OUT_LDO2_UV_STEP),
+};
+
+/* LDO: 1 - current range */
+static struct output_range ldo_current_range[] = {
+ RANGE(OUT_LDO1_UA_MIN, OUT_LDO1_UA_MAX, OUT_LDO1_UA_STEP),
+};
+
+/* LDO operating modes */
+static struct dm_regulator_mode sandbox_ldo_modes[] = {
+ MODE(LDO_OM_OFF, OM2REG(LDO_OM_OFF), "OFF"),
+ MODE(LDO_OM_ON, OM2REG(LDO_OM_ON), "ON"),
+ MODE(LDO_OM_SLEEP, OM2REG(LDO_OM_SLEEP), "SLEEP"),
+ MODE(LDO_OM_STANDBY, OM2REG(LDO_OM_STANDBY), "STANDBY"),
+};
+
+int out_get_value(struct udevice *dev, int output_count, int reg_type,
+ struct output_range *range)
+{
+ uint8_t reg_val;
+ uint reg;
+ int ret;
+
+ if (dev->driver_data > output_count) {
+ pr_err("Unknown regulator number: %lu for PMIC %s!",
+ dev->driver_data, dev->name);
+ return -EINVAL;
+ }
+
+ reg = (dev->driver_data - 1) * OUT_REG_COUNT + reg_type;
+ ret = pmic_read(dev->parent, reg, &reg_val, 1);
+ if (ret) {
+ pr_err("PMIC read failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = REG2VAL(range[dev->driver_data - 1].min,
+ range[dev->driver_data - 1].step,
+ reg_val);
+
+ return ret;
+}
+
+static int out_set_value(struct udevice *dev, int output_count, int reg_type,
+ struct output_range *range, int value)
+{
+ uint8_t reg_val;
+ uint reg;
+ int ret;
+ int max_value;
+
+ if (dev->driver_data > output_count) {
+ pr_err("Unknown regulator number: %lu for PMIC %s!",
+ dev->driver_data, dev->name);
+ return -EINVAL;
+ }
+
+ max_value = range[dev->driver_data - 1].max;
+ if (value > max_value) {
+ pr_err("Wrong value for %s: %lu. Max is: %d.",
+ dev->name, dev->driver_data, max_value);
+ return -EINVAL;
+ }
+
+ reg_val = VAL2REG(range[dev->driver_data - 1].min,
+ range[dev->driver_data - 1].step,
+ value);
+
+ reg = (dev->driver_data - 1) * OUT_REG_COUNT + reg_type;
+ ret = pmic_write(dev->parent, reg, &reg_val, 1);
+ if (ret) {
+ pr_err("PMIC write failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int out_get_mode(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ uint8_t reg_val;
+ uint reg;
+ int ret;
+ int i;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ reg = (dev->driver_data - 1) * OUT_REG_COUNT + OUT_REG_OM;
+ ret = pmic_read(dev->parent, reg, &reg_val, 1);
+ if (ret) {
+ pr_err("PMIC read failed: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (reg_val == uc_pdata->mode[i].register_value)
+ return uc_pdata->mode[i].id;
+ }
+
+ pr_err("Unknown operation mode for %s!", dev->name);
+ return -EINVAL;
+}
+
+static int out_set_mode(struct udevice *dev, int mode)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int reg_val = -1;
+ uint reg;
+ int ret;
+ int i;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ if (mode >= uc_pdata->mode_count)
+ return -EINVAL;
+
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (mode == uc_pdata->mode[i].id) {
+ reg_val = uc_pdata->mode[i].register_value;
+ break;
+ }
+ }
+
+ if (reg_val == -1) {
+ pr_err("Unknown operation mode for %s!", dev->name);
+ return -EINVAL;
+ }
+
+ reg = (dev->driver_data - 1) * OUT_REG_COUNT + OUT_REG_OM;
+ ret = pmic_write(dev->parent, reg, (uint8_t *)&reg_val, 1);
+ if (ret) {
+ pr_err("PMIC write failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int buck_get_voltage(struct udevice *dev)
+{
+ return out_get_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UV,
+ buck_voltage_range);
+}
+
+static int buck_set_voltage(struct udevice *dev, int uV)
+{
+ return out_set_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UV,
+ buck_voltage_range, uV);
+}
+
+static int buck_get_current(struct udevice *dev)
+{
+ /* BUCK2 - unsupported */
+ if (dev->driver_data == 2)
+ return -ENOSYS;
+
+ return out_get_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UA,
+ buck_current_range);
+}
+
+static int buck_set_current(struct udevice *dev, int uA)
+{
+ /* BUCK2 - unsupported */
+ if (dev->driver_data == 2)
+ return -ENOSYS;
+
+ return out_set_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UA,
+ buck_current_range, uA);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ if (out_get_mode(dev) == BUCK_OM_OFF)
+ return false;
+
+ return true;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ return out_set_mode(dev, enable ? BUCK_OM_ON : BUCK_OM_OFF);
+}
+
+static int sandbox_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode = sandbox_buck_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(sandbox_buck_modes);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops sandbox_buck_ops = {
+ .get_value = buck_get_voltage,
+ .set_value = buck_set_voltage,
+ .get_current = buck_get_current,
+ .set_current = buck_set_current,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+ .get_mode = out_get_mode,
+ .set_mode = out_set_mode,
+};
+
+U_BOOT_DRIVER(sandbox_buck) = {
+ .name = SANDBOX_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &sandbox_buck_ops,
+ .probe = sandbox_buck_probe,
+};
+
+static int ldo_get_voltage(struct udevice *dev)
+{
+ return out_get_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UV,
+ ldo_voltage_range);
+}
+
+static int ldo_set_voltage(struct udevice *dev, int uV)
+{
+ return out_set_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UV,
+ ldo_voltage_range, uV);
+}
+
+static int ldo_get_current(struct udevice *dev)
+{
+ /* LDO2 - unsupported */
+ if (dev->driver_data == 2)
+ return -ENOSYS;
+
+ return out_get_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UA,
+ ldo_current_range);
+}
+
+static int ldo_set_current(struct udevice *dev, int uA)
+{
+ /* LDO2 - unsupported */
+ if (dev->driver_data == 2)
+ return -ENOSYS;
+
+ return out_set_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UA,
+ ldo_current_range, uA);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ if (out_get_mode(dev) == LDO_OM_OFF)
+ return false;
+
+ return true;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ return out_set_mode(dev, enable ? LDO_OM_ON : LDO_OM_OFF);
+}
+
+static int sandbox_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode = sandbox_ldo_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(sandbox_ldo_modes);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops sandbox_ldo_ops = {
+ .get_value = ldo_get_voltage,
+ .set_value = ldo_set_voltage,
+ .get_current = ldo_get_current,
+ .set_current = ldo_set_current,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+ .get_mode = out_get_mode,
+ .set_mode = out_set_mode,
+};
+
+U_BOOT_DRIVER(sandbox_ldo) = {
+ .name = SANDBOX_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &sandbox_ldo_ops,
+ .probe = sandbox_ldo_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/scmi_regulator.c b/roms/u-boot/drivers/power/regulator/scmi_regulator.c
new file mode 100644
index 000000000..b3142bf4e
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/scmi_regulator.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020-2021 Linaro Limited
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <linux/kernel.h>
+#include <power/regulator.h>
+
+/**
+ * struct scmi_regulator_platdata - Platform data for a scmi voltage domain regulator
+ * @domain_id: ID representing the regulator for the related SCMI agent
+ */
+struct scmi_regulator_platdata {
+ u32 domain_id;
+};
+
+static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_config_set_in in = {
+ .domain_id = pdata->domain_id,
+ .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
+ };
+ struct scmi_voltd_config_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_CONFIG_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int scmi_voltd_get_enable(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_config_get_in in = {
+ .domain_id = pdata->domain_id,
+ };
+ struct scmi_voltd_config_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_CONFIG_GET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return out.config == SCMI_VOLTD_CONFIG_ON;
+}
+
+static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_level_set_in in = {
+ .domain_id = pdata->domain_id,
+ .voltage_level = uV,
+ };
+ struct scmi_voltd_level_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_LEVEL_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_voltd_get_voltage_level(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_level_get_in in = {
+ .domain_id = pdata->domain_id,
+ };
+ struct scmi_voltd_level_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_LEVEL_GET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return out.voltage_level;
+}
+
+static int scmi_regulator_of_to_plat(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ fdt_addr_t reg;
+
+ reg = dev_read_addr(dev);
+ if (reg == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ pdata->domain_id = (u32)reg;
+
+ return 0;
+}
+
+static int scmi_regulator_probe(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_attr_in in = { 0 };
+ struct scmi_voltd_attr_out out = { 0 };
+ struct scmi_msg scmi_msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ .message_id = SCMI_VOLTAGE_DOMAIN_ATTRIBUTES,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ /* Check voltage domain is known from SCMI server */
+ in.domain_id = pdata->domain_id;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &scmi_msg);
+ if (ret) {
+ dev_err(dev, "Failed to query voltage domain %u: %d\n",
+ pdata->domain_id, ret);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops scmi_voltd_ops = {
+ .get_value = scmi_voltd_get_voltage_level,
+ .set_value = scmi_voltd_set_voltage_level,
+ .get_enable = scmi_voltd_get_enable,
+ .set_enable = scmi_voltd_set_enable,
+};
+
+U_BOOT_DRIVER(scmi_regulator) = {
+ .name = "scmi_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &scmi_voltd_ops,
+ .probe = scmi_regulator_probe,
+ .of_to_plat = scmi_regulator_of_to_plat,
+ .plat_auto = sizeof(struct scmi_regulator_platdata),
+};
+
+static int scmi_regulator_bind(struct udevice *dev)
+{
+ struct driver *drv;
+ ofnode node;
+ int ret;
+
+ drv = DM_DRIVER_GET(scmi_regulator);
+
+ ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+ ret = device_bind(dev, drv, ofnode_get_name(node),
+ NULL, node, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(scmi_voltage_domain) = {
+ .name = "scmi_voltage_domain",
+ .id = UCLASS_NOP,
+ .bind = scmi_regulator_bind,
+};
diff --git a/roms/u-boot/drivers/power/regulator/stm32-vrefbuf.c b/roms/u-boot/drivers/power/regulator/stm32-vrefbuf.c
new file mode 100644
index 000000000..c37998a4b
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/stm32-vrefbuf.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * Originally based on the Linux kernel v4.16 drivers/regulator/stm32-vrefbuf.c
+ */
+
+#define LOG_CATEGORY UCLASS_REGULATOR
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <power/regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR 0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS GENMASK(6, 4)
+#define STM32_VRS_SHIFT 4
+#define STM32_VRR BIT(3)
+#define STM32_HIZ BIT(1)
+#define STM32_ENVR BIT(0)
+
+struct stm32_vrefbuf {
+ void __iomem *base;
+ struct clk clk;
+ struct udevice *vdda_supply;
+};
+
+static const int stm32_vrefbuf_voltages[] = {
+ /* Matches resp. VRS = 000b, 001b, 010b, 011b */
+ 2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_set_enable(struct udevice *dev, bool enable)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+ u32 val;
+ int ret;
+
+ if (enable && !(readl(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR)) {
+ /*
+ * There maybe an overshoot:
+ * - when disabling, then re-enabling vrefbuf too quickly
+ * - or upon platform reset as external capacitor maybe slow
+ * discharging (VREFBUF is HiZ at reset by default).
+ * So force active discharge (HiZ=0) for 1ms before enabling.
+ */
+ clrbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_HIZ);
+ udelay(1000);
+ }
+
+ clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_ENVR,
+ enable ? STM32_ENVR : 0);
+ if (!enable)
+ return 0;
+
+ /*
+ * Vrefbuf startup time depends on external capacitor: wait here for
+ * VRR to be set. That means output has reached expected value.
+ * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+ * arbitrary timeout.
+ */
+ ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+ val & STM32_VRR, 10000);
+ if (ret < 0) {
+ dev_err(dev, "stm32 vrefbuf timed out: %d\n", ret);
+ clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_ENVR,
+ STM32_HIZ);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_vrefbuf_get_enable(struct udevice *dev)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+
+ return readl(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+}
+
+static int stm32_vrefbuf_set_value(struct udevice *dev, int uV)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(stm32_vrefbuf_voltages); i++) {
+ if (uV == stm32_vrefbuf_voltages[i]) {
+ clrsetbits_le32(priv->base + STM32_VREFBUF_CSR,
+ STM32_VRS, i << STM32_VRS_SHIFT);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int stm32_vrefbuf_get_value(struct udevice *dev)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+ u32 val;
+
+ val = readl(priv->base + STM32_VREFBUF_CSR) & STM32_VRS;
+ val >>= STM32_VRS_SHIFT;
+
+ return stm32_vrefbuf_voltages[val];
+}
+
+static const struct dm_regulator_ops stm32_vrefbuf_ops = {
+ .get_value = stm32_vrefbuf_get_value,
+ .set_value = stm32_vrefbuf_set_value,
+ .get_enable = stm32_vrefbuf_get_enable,
+ .set_enable = stm32_vrefbuf_set_enable,
+};
+
+static int stm32_vrefbuf_probe(struct udevice *dev)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret) {
+ dev_err(dev, "Can't get clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&priv->clk);
+ if (ret) {
+ dev_err(dev, "Can't enable clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vdda-supply",
+ &priv->vdda_supply);
+ if (ret) {
+ dev_dbg(dev, "No vdda-supply: %d\n", ret);
+ return 0;
+ }
+
+ ret = regulator_set_enable(priv->vdda_supply, true);
+ if (ret) {
+ dev_err(dev, "Can't enable vdda-supply: %d\n", ret);
+ clk_disable(&priv->clk);
+ }
+
+ return ret;
+}
+
+static const struct udevice_id stm32_vrefbuf_ids[] = {
+ { .compatible = "st,stm32-vrefbuf" },
+ { }
+};
+
+U_BOOT_DRIVER(stm32_vrefbuf) = {
+ .name = "stm32-vrefbuf",
+ .id = UCLASS_REGULATOR,
+ .of_match = stm32_vrefbuf_ids,
+ .probe = stm32_vrefbuf_probe,
+ .ops = &stm32_vrefbuf_ops,
+ .priv_auto = sizeof(struct stm32_vrefbuf),
+};
diff --git a/roms/u-boot/drivers/power/regulator/stpmic1.c b/roms/u-boot/drivers/power/regulator/stpmic1.c
new file mode 100644
index 000000000..4839d8343
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/stpmic1.c
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author: Christophe Kerello <christophe.kerello@st.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <linux/delay.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/stpmic1.h>
+
+struct stpmic1_range {
+ int min_uv;
+ int min_sel;
+ int max_sel;
+ int step;
+};
+
+struct stpmic1_output {
+ const struct stpmic1_range *ranges;
+ int nbranges;
+};
+
+#define STPMIC1_MODE(_id, _val, _name) { \
+ .id = _id, \
+ .register_value = _val, \
+ .name = _name, \
+}
+
+#define STPMIC1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \
+ .min_uv = _min_uv, \
+ .min_sel = _min_sel, \
+ .max_sel = _max_sel, \
+ .step = _step, \
+}
+
+#define STPMIC1_OUTPUT(_ranges, _nbranges) { \
+ .ranges = _ranges, \
+ .nbranges = _nbranges, \
+}
+
+static int stpmic1_output_find_uv(int sel,
+ const struct stpmic1_output *output)
+{
+ const struct stpmic1_range *range;
+ int i;
+
+ for (i = 0, range = output->ranges;
+ i < output->nbranges; i++, range++) {
+ if (sel >= range->min_sel && sel <= range->max_sel)
+ return range->min_uv +
+ (sel - range->min_sel) * range->step;
+ }
+
+ return -EINVAL;
+}
+
+static int stpmic1_output_find_sel(int uv,
+ const struct stpmic1_output *output)
+{
+ const struct stpmic1_range *range;
+ int i;
+
+ for (i = 0, range = output->ranges;
+ i < output->nbranges; i++, range++) {
+ if (uv == range->min_uv && !range->step)
+ return range->min_sel;
+
+ if (uv >= range->min_uv &&
+ uv <= range->min_uv +
+ (range->max_sel - range->min_sel) * range->step)
+ return range->min_sel +
+ (uv - range->min_uv) / range->step;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * BUCK regulators
+ */
+
+static const struct stpmic1_range buck1_ranges[] = {
+ STPMIC1_RANGE(725000, 0, 4, 0),
+ STPMIC1_RANGE(725000, 5, 36, 25000),
+ STPMIC1_RANGE(1500000, 37, 63, 0),
+};
+
+static const struct stpmic1_range buck2_ranges[] = {
+ STPMIC1_RANGE(1000000, 0, 17, 0),
+ STPMIC1_RANGE(1050000, 18, 19, 0),
+ STPMIC1_RANGE(1100000, 20, 21, 0),
+ STPMIC1_RANGE(1150000, 22, 23, 0),
+ STPMIC1_RANGE(1200000, 24, 25, 0),
+ STPMIC1_RANGE(1250000, 26, 27, 0),
+ STPMIC1_RANGE(1300000, 28, 29, 0),
+ STPMIC1_RANGE(1350000, 30, 31, 0),
+ STPMIC1_RANGE(1400000, 32, 33, 0),
+ STPMIC1_RANGE(1450000, 34, 35, 0),
+ STPMIC1_RANGE(1500000, 36, 63, 0),
+};
+
+static const struct stpmic1_range buck3_ranges[] = {
+ STPMIC1_RANGE(1000000, 0, 19, 0),
+ STPMIC1_RANGE(1100000, 20, 23, 0),
+ STPMIC1_RANGE(1200000, 24, 27, 0),
+ STPMIC1_RANGE(1300000, 28, 31, 0),
+ STPMIC1_RANGE(1400000, 32, 35, 0),
+ STPMIC1_RANGE(1500000, 36, 55, 100000),
+ STPMIC1_RANGE(3400000, 56, 63, 0),
+};
+
+static const struct stpmic1_range buck4_ranges[] = {
+ STPMIC1_RANGE(600000, 0, 27, 25000),
+ STPMIC1_RANGE(1300000, 28, 29, 0),
+ STPMIC1_RANGE(1350000, 30, 31, 0),
+ STPMIC1_RANGE(1400000, 32, 33, 0),
+ STPMIC1_RANGE(1450000, 34, 35, 0),
+ STPMIC1_RANGE(1500000, 36, 60, 100000),
+ STPMIC1_RANGE(3900000, 61, 63, 0),
+};
+
+/* BUCK: 1,2,3,4 - voltage ranges */
+static const struct stpmic1_output buck_voltage_range[] = {
+ STPMIC1_OUTPUT(buck1_ranges, ARRAY_SIZE(buck1_ranges)),
+ STPMIC1_OUTPUT(buck2_ranges, ARRAY_SIZE(buck2_ranges)),
+ STPMIC1_OUTPUT(buck3_ranges, ARRAY_SIZE(buck3_ranges)),
+ STPMIC1_OUTPUT(buck4_ranges, ARRAY_SIZE(buck4_ranges)),
+};
+
+/* BUCK modes */
+static const struct dm_regulator_mode buck_modes[] = {
+ STPMIC1_MODE(STPMIC1_PREG_MODE_HP, STPMIC1_PREG_MODE_HP, "HP"),
+ STPMIC1_MODE(STPMIC1_PREG_MODE_LP, STPMIC1_PREG_MODE_LP, "LP"),
+};
+
+static int stpmic1_buck_get_uv(struct udevice *dev, int buck)
+{
+ int sel;
+
+ sel = pmic_reg_read(dev, STPMIC1_BUCKX_MAIN_CR(buck));
+ if (sel < 0)
+ return sel;
+
+ sel &= STPMIC1_BUCK_VOUT_MASK;
+ sel >>= STPMIC1_BUCK_VOUT_SHIFT;
+
+ return stpmic1_output_find_uv(sel, &buck_voltage_range[buck]);
+}
+
+static int stpmic1_buck_get_value(struct udevice *dev)
+{
+ return stpmic1_buck_get_uv(dev->parent, dev->driver_data - 1);
+}
+
+static int stpmic1_buck_set_value(struct udevice *dev, int uv)
+{
+ int sel, buck = dev->driver_data - 1;
+
+ sel = stpmic1_output_find_sel(uv, &buck_voltage_range[buck]);
+ if (sel < 0)
+ return sel;
+
+ return pmic_clrsetbits(dev->parent,
+ STPMIC1_BUCKX_MAIN_CR(buck),
+ STPMIC1_BUCK_VOUT_MASK,
+ sel << STPMIC1_BUCK_VOUT_SHIFT);
+}
+
+static int stpmic1_buck_get_enable(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent,
+ STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1));
+ if (ret < 0)
+ return false;
+
+ return ret & STPMIC1_BUCK_ENA ? true : false;
+}
+
+static int stpmic1_buck_set_enable(struct udevice *dev, bool enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
+ STPMIC1_DEFAULT_STOP_DELAY_MS;
+ int ret, uv;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (stpmic1_buck_get_enable(dev) == enable)
+ return 0;
+
+ if (enable) {
+ uc_pdata = dev_get_uclass_plat(dev);
+ uv = stpmic1_buck_get_value(dev);
+ if (uv < uc_pdata->min_uV || uv > uc_pdata->max_uV)
+ stpmic1_buck_set_value(dev, uc_pdata->min_uV);
+ }
+
+ ret = pmic_clrsetbits(dev->parent,
+ STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1),
+ STPMIC1_BUCK_ENA, enable ? STPMIC1_BUCK_ENA : 0);
+ mdelay(delay);
+
+ return ret;
+}
+
+static int stpmic1_buck_get_mode(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent,
+ STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1));
+ if (ret < 0)
+ return ret;
+
+ return ret & STPMIC1_BUCK_PREG_MODE ? STPMIC1_PREG_MODE_LP :
+ STPMIC1_PREG_MODE_HP;
+}
+
+static int stpmic1_buck_set_mode(struct udevice *dev, int mode)
+{
+ return pmic_clrsetbits(dev->parent,
+ STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1),
+ STPMIC1_BUCK_PREG_MODE,
+ mode ? STPMIC1_BUCK_PREG_MODE : 0);
+}
+
+static int stpmic1_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_BUCK)
+ return -EINVAL;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode = (struct dm_regulator_mode *)buck_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(buck_modes);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmic1_buck_ops = {
+ .get_value = stpmic1_buck_get_value,
+ .set_value = stpmic1_buck_set_value,
+ .get_enable = stpmic1_buck_get_enable,
+ .set_enable = stpmic1_buck_set_enable,
+ .get_mode = stpmic1_buck_get_mode,
+ .set_mode = stpmic1_buck_set_mode,
+};
+
+U_BOOT_DRIVER(stpmic1_buck) = {
+ .name = "stpmic1_buck",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmic1_buck_ops,
+ .probe = stpmic1_buck_probe,
+};
+
+/*
+ * LDO regulators
+ */
+
+static const struct stpmic1_range ldo12_ranges[] = {
+ STPMIC1_RANGE(1700000, 0, 7, 0),
+ STPMIC1_RANGE(1700000, 8, 24, 100000),
+ STPMIC1_RANGE(3300000, 25, 31, 0),
+};
+
+static const struct stpmic1_range ldo3_ranges[] = {
+ STPMIC1_RANGE(1700000, 0, 7, 0),
+ STPMIC1_RANGE(1700000, 8, 24, 100000),
+ STPMIC1_RANGE(3300000, 25, 30, 0),
+ /* Sel 31 is special case when LDO3 is in mode sync_source (BUCK2/2) */
+};
+
+static const struct stpmic1_range ldo5_ranges[] = {
+ STPMIC1_RANGE(1700000, 0, 7, 0),
+ STPMIC1_RANGE(1700000, 8, 30, 100000),
+ STPMIC1_RANGE(3900000, 31, 31, 0),
+};
+
+static const struct stpmic1_range ldo6_ranges[] = {
+ STPMIC1_RANGE(900000, 0, 24, 100000),
+ STPMIC1_RANGE(3300000, 25, 31, 0),
+};
+
+/* LDO: 1,2,3,4,5,6 - voltage ranges */
+static const struct stpmic1_output ldo_voltage_range[] = {
+ STPMIC1_OUTPUT(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)),
+ STPMIC1_OUTPUT(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)),
+ STPMIC1_OUTPUT(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)),
+ STPMIC1_OUTPUT(NULL, 0),
+ STPMIC1_OUTPUT(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)),
+ STPMIC1_OUTPUT(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)),
+};
+
+/* LDO modes */
+static const struct dm_regulator_mode ldo_modes[] = {
+ STPMIC1_MODE(STPMIC1_LDO_MODE_NORMAL,
+ STPMIC1_LDO_MODE_NORMAL, "NORMAL"),
+ STPMIC1_MODE(STPMIC1_LDO_MODE_BYPASS,
+ STPMIC1_LDO_MODE_BYPASS, "BYPASS"),
+ STPMIC1_MODE(STPMIC1_LDO_MODE_SINK_SOURCE,
+ STPMIC1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"),
+};
+
+static int stpmic1_ldo_get_value(struct udevice *dev)
+{
+ int sel, ldo = dev->driver_data - 1;
+
+ sel = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
+ if (sel < 0)
+ return sel;
+
+ /* ldo4 => 3,3V */
+ if (ldo == STPMIC1_LDO4)
+ return STPMIC1_LDO4_UV;
+
+ sel &= STPMIC1_LDO12356_VOUT_MASK;
+ sel >>= STPMIC1_LDO12356_VOUT_SHIFT;
+
+ /* ldo3, sel = 31 => BUCK2/2 */
+ if (ldo == STPMIC1_LDO3 && sel == STPMIC1_LDO3_DDR_SEL)
+ return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2;
+
+ return stpmic1_output_find_uv(sel, &ldo_voltage_range[ldo]);
+}
+
+static int stpmic1_ldo_set_value(struct udevice *dev, int uv)
+{
+ int sel, ldo = dev->driver_data - 1;
+
+ /* ldo4 => not possible */
+ if (ldo == STPMIC1_LDO4)
+ return -EINVAL;
+
+ sel = stpmic1_output_find_sel(uv, &ldo_voltage_range[ldo]);
+ if (sel < 0)
+ return sel;
+
+ return pmic_clrsetbits(dev->parent,
+ STPMIC1_LDOX_MAIN_CR(ldo),
+ STPMIC1_LDO12356_VOUT_MASK,
+ sel << STPMIC1_LDO12356_VOUT_SHIFT);
+}
+
+static int stpmic1_ldo_get_enable(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent,
+ STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1));
+ if (ret < 0)
+ return false;
+
+ return ret & STPMIC1_LDO_ENA ? true : false;
+}
+
+static int stpmic1_ldo_set_enable(struct udevice *dev, bool enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
+ STPMIC1_DEFAULT_STOP_DELAY_MS;
+ int ret, uv;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (stpmic1_ldo_get_enable(dev) == enable)
+ return 0;
+
+ if (enable) {
+ uc_pdata = dev_get_uclass_plat(dev);
+ uv = stpmic1_ldo_get_value(dev);
+ if (uv < uc_pdata->min_uV || uv > uc_pdata->max_uV)
+ stpmic1_ldo_set_value(dev, uc_pdata->min_uV);
+ }
+
+ ret = pmic_clrsetbits(dev->parent,
+ STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1),
+ STPMIC1_LDO_ENA, enable ? STPMIC1_LDO_ENA : 0);
+ mdelay(delay);
+
+ return ret;
+}
+
+static int stpmic1_ldo_get_mode(struct udevice *dev)
+{
+ int ret, ldo = dev->driver_data - 1;
+
+ if (ldo != STPMIC1_LDO3)
+ return -EINVAL;
+
+ ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
+ if (ret < 0)
+ return ret;
+
+ if (ret & STPMIC1_LDO3_MODE)
+ return STPMIC1_LDO_MODE_BYPASS;
+
+ ret &= STPMIC1_LDO12356_VOUT_MASK;
+ ret >>= STPMIC1_LDO12356_VOUT_SHIFT;
+
+ return ret == STPMIC1_LDO3_DDR_SEL ? STPMIC1_LDO_MODE_SINK_SOURCE :
+ STPMIC1_LDO_MODE_NORMAL;
+}
+
+static int stpmic1_ldo_set_mode(struct udevice *dev, int mode)
+{
+ int ret, ldo = dev->driver_data - 1;
+
+ if (ldo != STPMIC1_LDO3)
+ return -EINVAL;
+
+ ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
+ if (ret < 0)
+ return ret;
+
+ switch (mode) {
+ case STPMIC1_LDO_MODE_SINK_SOURCE:
+ ret &= ~STPMIC1_LDO12356_VOUT_MASK;
+ ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_VOUT_SHIFT;
+ /* fallthrough */
+ case STPMIC1_LDO_MODE_NORMAL:
+ ret &= ~STPMIC1_LDO3_MODE;
+ break;
+ case STPMIC1_LDO_MODE_BYPASS:
+ ret |= STPMIC1_LDO3_MODE;
+ break;
+ }
+
+ return pmic_reg_write(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo), ret);
+}
+
+static int stpmic1_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_LDO)
+ return -EINVAL;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ if (dev->driver_data - 1 == STPMIC1_LDO3) {
+ uc_pdata->mode = (struct dm_regulator_mode *)ldo_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(ldo_modes);
+ } else {
+ uc_pdata->mode_count = 0;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmic1_ldo_ops = {
+ .get_value = stpmic1_ldo_get_value,
+ .set_value = stpmic1_ldo_set_value,
+ .get_enable = stpmic1_ldo_get_enable,
+ .set_enable = stpmic1_ldo_set_enable,
+ .get_mode = stpmic1_ldo_get_mode,
+ .set_mode = stpmic1_ldo_set_mode,
+};
+
+U_BOOT_DRIVER(stpmic1_ldo) = {
+ .name = "stpmic1_ldo",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmic1_ldo_ops,
+ .probe = stpmic1_ldo_probe,
+};
+
+/*
+ * VREF DDR regulator
+ */
+
+static int stpmic1_vref_ddr_get_value(struct udevice *dev)
+{
+ /* BUCK2/2 */
+ return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2;
+}
+
+static int stpmic1_vref_ddr_get_enable(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMIC1_REFDDR_MAIN_CR);
+ if (ret < 0)
+ return false;
+
+ return ret & STPMIC1_VREF_ENA ? true : false;
+}
+
+static int stpmic1_vref_ddr_set_enable(struct udevice *dev, bool enable)
+{
+ int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
+ STPMIC1_DEFAULT_STOP_DELAY_MS;
+ int ret;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (stpmic1_vref_ddr_get_enable(dev) == enable)
+ return 0;
+
+ ret = pmic_clrsetbits(dev->parent, STPMIC1_REFDDR_MAIN_CR,
+ STPMIC1_VREF_ENA, enable ? STPMIC1_VREF_ENA : 0);
+ mdelay(delay);
+
+ return ret;
+}
+
+static int stpmic1_vref_ddr_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_FIXED;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmic1_vref_ddr_ops = {
+ .get_value = stpmic1_vref_ddr_get_value,
+ .get_enable = stpmic1_vref_ddr_get_enable,
+ .set_enable = stpmic1_vref_ddr_set_enable,
+};
+
+U_BOOT_DRIVER(stpmic1_vref_ddr) = {
+ .name = "stpmic1_vref_ddr",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmic1_vref_ddr_ops,
+ .probe = stpmic1_vref_ddr_probe,
+};
+
+/*
+ * BOOST regulator
+ */
+
+static int stpmic1_boost_get_enable(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
+ if (ret < 0)
+ return false;
+
+ return ret & STPMIC1_BST_ON ? true : false;
+}
+
+static int stpmic1_boost_set_enable(struct udevice *dev, bool enable)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
+ if (ret < 0)
+ return ret;
+
+ if (!enable && ret & STPMIC1_PWR_SW_ON)
+ return -EINVAL;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (!!(ret & STPMIC1_BST_ON) == enable)
+ return 0;
+
+ ret = pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
+ STPMIC1_BST_ON,
+ enable ? STPMIC1_BST_ON : 0);
+ if (enable)
+ mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS);
+
+ return ret;
+}
+
+static int stpmic1_boost_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_FIXED;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmic1_boost_ops = {
+ .get_enable = stpmic1_boost_get_enable,
+ .set_enable = stpmic1_boost_set_enable,
+};
+
+U_BOOT_DRIVER(stpmic1_boost) = {
+ .name = "stpmic1_boost",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmic1_boost_ops,
+ .probe = stpmic1_boost_probe,
+};
+
+/*
+ * USB power switch
+ */
+
+static int stpmic1_pwr_sw_get_enable(struct udevice *dev)
+{
+ uint mask = 1 << dev->driver_data;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
+ if (ret < 0)
+ return false;
+
+ return ret & mask ? true : false;
+}
+
+static int stpmic1_pwr_sw_set_enable(struct udevice *dev, bool enable)
+{
+ uint mask = 1 << dev->driver_data;
+ int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
+ STPMIC1_DEFAULT_STOP_DELAY_MS;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
+ if (ret < 0)
+ return ret;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (!!(ret & mask) == enable)
+ return 0;
+
+ /* Boost management */
+ if (enable && !(ret & STPMIC1_BST_ON)) {
+ pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
+ STPMIC1_BST_ON, STPMIC1_BST_ON);
+ mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS);
+ } else if (!enable && ret & STPMIC1_BST_ON &&
+ (ret & STPMIC1_PWR_SW_ON) != STPMIC1_PWR_SW_ON) {
+ pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
+ STPMIC1_BST_ON, 0);
+ }
+
+ ret = pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
+ mask, enable ? mask : 0);
+ mdelay(delay);
+
+ return ret;
+}
+
+static int stpmic1_pwr_sw_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_PWR_SW)
+ return -EINVAL;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_FIXED;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmic1_pwr_sw_ops = {
+ .get_enable = stpmic1_pwr_sw_get_enable,
+ .set_enable = stpmic1_pwr_sw_set_enable,
+};
+
+U_BOOT_DRIVER(stpmic1_pwr_sw) = {
+ .name = "stpmic1_pwr_sw",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmic1_pwr_sw_ops,
+ .probe = stpmic1_pwr_sw_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/tps62360_regulator.c b/roms/u-boot/drivers/power/regulator/tps62360_regulator.c
new file mode 100644
index 000000000..b9f450453
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/tps62360_regulator.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Tero Kristo <t-kristo@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <dm/device_compat.h>
+#include <power/regulator.h>
+
+#define TPS62360_REG_SET0 0
+
+#define TPS62360_I2C_CHIP 0x60
+
+#define TPS62360_VSEL_STEPSIZE 10000 /* In uV */
+
+struct tps62360_regulator_config {
+ u32 vmin;
+ u32 vmax;
+};
+
+struct tps62360_regulator_pdata {
+ u8 vsel_offset;
+ struct udevice *i2c;
+ struct tps62360_regulator_config *config;
+};
+
+/*
+ * TPS62362/TPS62363 are just re-using these values for now, their preset
+ * voltage values are just different compared to TPS62360/TPS62361.
+ */
+static struct tps62360_regulator_config tps62360_data = {
+ .vmin = 770000,
+ .vmax = 1400000,
+};
+
+static struct tps62360_regulator_config tps62361_data = {
+ .vmin = 500000,
+ .vmax = 1770000,
+};
+
+static int tps62360_regulator_set_value(struct udevice *dev, int uV)
+{
+ struct tps62360_regulator_pdata *pdata = dev_get_plat(dev);
+ u8 regval;
+
+ if (uV < pdata->config->vmin || uV > pdata->config->vmax)
+ return -EINVAL;
+
+ uV -= pdata->config->vmin;
+
+ uV = DIV_ROUND_UP(uV, TPS62360_VSEL_STEPSIZE);
+
+ if (uV > U8_MAX)
+ return -EINVAL;
+
+ regval = (u8)uV;
+
+ return dm_i2c_write(pdata->i2c, TPS62360_REG_SET0 + pdata->vsel_offset,
+ &regval, 1);
+}
+
+static int tps62360_regulator_get_value(struct udevice *dev)
+{
+ u8 regval;
+ int ret;
+ struct tps62360_regulator_pdata *pdata = dev_get_plat(dev);
+
+ ret = dm_i2c_read(pdata->i2c, TPS62360_REG_SET0 + pdata->vsel_offset,
+ &regval, 1);
+ if (ret) {
+ dev_err(dev, "i2c read failed: %d\n", ret);
+ return ret;
+ }
+
+ return (u32)regval * TPS62360_VSEL_STEPSIZE + pdata->config->vmin;
+}
+
+static int tps62360_regulator_probe(struct udevice *dev)
+{
+ struct tps62360_regulator_pdata *pdata = dev_get_plat(dev);
+ u8 vsel0;
+ u8 vsel1;
+ int ret;
+
+ pdata->config = (void *)dev_get_driver_data(dev);
+
+ vsel0 = dev_read_bool(dev, "ti,vsel0-state-high");
+ vsel1 = dev_read_bool(dev, "ti,vsel1-state-high");
+
+ pdata->vsel_offset = vsel0 + vsel1 * 2;
+
+ ret = i2c_get_chip(dev->parent, TPS62360_I2C_CHIP, 1, &pdata->i2c);
+ if (ret) {
+ dev_err(dev, "i2c dev get failed.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops tps62360_regulator_ops = {
+ .get_value = tps62360_regulator_get_value,
+ .set_value = tps62360_regulator_set_value,
+};
+
+static const struct udevice_id tps62360_regulator_ids[] = {
+ { .compatible = "ti,tps62360", .data = (ulong)&tps62360_data },
+ { .compatible = "ti,tps62361", .data = (ulong)&tps62361_data },
+ { .compatible = "ti,tps62362", .data = (ulong)&tps62360_data },
+ { .compatible = "ti,tps62363", .data = (ulong)&tps62361_data },
+ { },
+};
+
+U_BOOT_DRIVER(tps62360_regulator) = {
+ .name = "tps62360_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &tps62360_regulator_ops,
+ .of_match = tps62360_regulator_ids,
+ .plat_auto = sizeof(struct tps62360_regulator_pdata),
+ .probe = tps62360_regulator_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/tps65090_regulator.c b/roms/u-boot/drivers/power/regulator/tps65090_regulator.c
new file mode 100644
index 000000000..174ee58d0
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/tps65090_regulator.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65090.h>
+
+static int tps65090_fet_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_OTHER;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static int tps65090_fet_get_enable(struct udevice *dev)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ int ret, fet_id;
+
+ fet_id = dev->driver_data;
+ debug("%s: fet_id=%d\n", __func__, fet_id);
+
+ ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
+ if (ret < 0)
+ return ret;
+
+ return ret & FET_CTRL_ENFET;
+}
+
+/**
+ * Set the power state for a FET
+ *
+ * @param pmic pmic structure for the tps65090
+ * @param fet_id FET number to set (1..MAX_FET_NUM)
+ * @param set 1 to power on FET, 0 to power off
+ * @return -EIO if we got a comms error, -EAGAIN if the FET failed to
+ * change state. If all is ok, returns 0.
+ */
+static int tps65090_fet_set(struct udevice *pmic, int fet_id, bool set)
+{
+ int retry;
+ u32 value;
+ int ret;
+
+ value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
+ if (set)
+ value |= FET_CTRL_ENFET;
+
+ if (pmic_reg_write(pmic, REG_FET_BASE + fet_id, value))
+ return -EIO;
+
+ /* Try reading until we get a result */
+ for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
+ ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
+ if (ret < 0)
+ return ret;
+
+ /* Check that the FET went into the expected state */
+ debug("%s: flags=%x\n", __func__, ret);
+ if (!!(ret & FET_CTRL_PGFET) == set)
+ return 0;
+
+ /* If we got a timeout, there is no point in waiting longer */
+ if (ret & FET_CTRL_TOFET)
+ break;
+
+ mdelay(1);
+ }
+
+ debug("FET %d: Power good should have set to %d but reg=%#02x\n",
+ fet_id, set, ret);
+ return -EAGAIN;
+}
+
+static int tps65090_fet_set_enable(struct udevice *dev, bool enable)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ int ret, fet_id;
+ ulong start;
+ int loops;
+
+ fet_id = dev->driver_data;
+ debug("%s: fet_id=%d, enable=%d\n", __func__, fet_id, enable);
+
+ start = get_timer(0);
+ for (loops = 0;; loops++) {
+ ret = tps65090_fet_set(pmic, fet_id, enable);
+ if (!ret)
+ break;
+
+ if (get_timer(start) > 100)
+ break;
+
+ /* Turn it off and try again until we time out */
+ tps65090_fet_set(pmic, fet_id, false);
+ }
+
+ if (ret)
+ debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
+ __func__, fet_id, get_timer(start), loops);
+ else if (loops)
+ debug("%s: FET%d powered on after %lums, loops=%d\n",
+ __func__, fet_id, get_timer(start), loops);
+
+ /*
+ * Unfortunately there are some conditions where the power-good bit
+ * will be 0, but the FET still comes up. One such case occurs with
+ * the LCD backlight on snow. We'll just return 0 here and assume
+ * that the FET will eventually come up.
+ */
+ if (ret == -EAGAIN)
+ ret = 0;
+
+ return ret;
+}
+
+static const struct dm_regulator_ops tps65090_fet_ops = {
+ .get_enable = tps65090_fet_get_enable,
+ .set_enable = tps65090_fet_set_enable,
+};
+
+U_BOOT_DRIVER(tps65090_fet) = {
+ .name = TPS65090_FET_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65090_fet_ops,
+ .probe = tps65090_fet_probe,
+};
diff --git a/roms/u-boot/drivers/power/regulator/tps65910_regulator.c b/roms/u-boot/drivers/power/regulator/tps65910_regulator.c
new file mode 100644
index 000000000..0ed4952a1
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/tps65910_regulator.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65910_pmic.h>
+
+#define VOUT_CHOICE_COUNT 4
+
+/*
+ * struct regulator_props - Properties of a LDO and VIO SMPS regulator
+ *
+ * All of these regulators allow setting one out of four output voltages.
+ * These output voltages are only achievable when supplying the regulator
+ * with a minimum input voltage.
+ *
+ * @vin_min[]: minimum supply input voltage in uV required to achieve the
+ * corresponding vout[] voltage
+ * @vout[]: regulator output voltage in uV
+ * @reg: I2C register used to set regulator voltage
+ */
+struct regulator_props {
+ int vin_min[VOUT_CHOICE_COUNT];
+ int vout[VOUT_CHOICE_COUNT];
+ int reg;
+};
+
+static const struct regulator_props ldo_props_vdig1 = {
+ .vin_min = { 1700000, 2100000, 2700000, 3200000 },
+ .vout = { 1200000, 1500000, 1800000, 2700000 },
+ .reg = TPS65910_REG_VDIG1
+};
+
+static const struct regulator_props ldo_props_vdig2 = {
+ .vin_min = { 1700000, 1700000, 1700000, 2700000 },
+ .vout = { 1000000, 1100000, 1200000, 1800000 },
+ .reg = TPS65910_REG_VDIG2
+};
+
+static const struct regulator_props ldo_props_vpll = {
+ .vin_min = { 2700000, 2700000, 2700000, 3000000 },
+ .vout = { 1000000, 1100000, 1800000, 2500000 },
+ .reg = TPS65910_REG_VPLL
+};
+
+static const struct regulator_props ldo_props_vdac = {
+ .vin_min = { 2700000, 3000000, 3200000, 3200000 },
+ .vout = { 1800000, 2600000, 2800000, 2850000 },
+ .reg = TPS65910_REG_VDAC
+};
+
+static const struct regulator_props ldo_props_vaux1 = {
+ .vin_min = { 2700000, 3200000, 3200000, 3200000 },
+ .vout = { 1800000, 2500000, 2800000, 2850000 },
+ .reg = TPS65910_REG_VAUX1
+};
+
+static const struct regulator_props ldo_props_vaux2 = {
+ .vin_min = { 2700000, 3200000, 3200000, 3600000 },
+ .vout = { 1800000, 2800000, 2900000, 3300000 },
+ .reg = TPS65910_REG_VAUX2
+};
+
+static const struct regulator_props ldo_props_vaux33 = {
+ .vin_min = { 2700000, 2700000, 3200000, 3600000 },
+ .vout = { 1800000, 2000000, 2800000, 3300000 },
+ .reg = TPS65910_REG_VAUX33
+};
+
+static const struct regulator_props ldo_props_vmmc = {
+ .vin_min = { 2700000, 3200000, 3200000, 3600000 },
+ .vout = { 1800000, 2800000, 3000000, 3300000 },
+ .reg = TPS65910_REG_VMMC
+};
+
+static const struct regulator_props smps_props_vio = {
+ .vin_min = { 3200000, 3200000, 4000000, 4400000 },
+ .vout = { 1500000, 1800000, 2500000, 3300000 },
+ .reg = TPS65910_REG_VIO
+};
+
+/* lookup table of control registers indexed by regulator unit number */
+static const int ctrl_regs[] = {
+ TPS65910_REG_VRTC,
+ TPS65910_REG_VIO,
+ TPS65910_REG_VDD1,
+ TPS65910_REG_VDD2,
+ TPS65910_REG_VDD3,
+ TPS65910_REG_VDIG1,
+ TPS65910_REG_VDIG2,
+ TPS65910_REG_VPLL,
+ TPS65910_REG_VDAC,
+ TPS65910_REG_VAUX1,
+ TPS65910_REG_VAUX2,
+ TPS65910_REG_VAUX33,
+ TPS65910_REG_VMMC
+};
+
+/* supply names as used in DT */
+static const char * const supply_names[] = {
+ "vccio-supply",
+ "vcc1-supply",
+ "vcc2-supply",
+ "vcc3-supply",
+ "vcc4-supply",
+ "vcc5-supply",
+ "vcc6-supply",
+ "vcc7-supply"
+};
+
+/* lookup table of regulator supplies indexed by regulator unit number */
+static const int regulator_supplies[] = {
+ TPS65910_SUPPLY_VCC7,
+ TPS65910_SUPPLY_VCCIO,
+ TPS65910_SUPPLY_VCC1,
+ TPS65910_SUPPLY_VCC2,
+ TPS65910_SUPPLY_VCC7,
+ TPS65910_SUPPLY_VCC6,
+ TPS65910_SUPPLY_VCC6,
+ TPS65910_SUPPLY_VCC5,
+ TPS65910_SUPPLY_VCC5,
+ TPS65910_SUPPLY_VCC4,
+ TPS65910_SUPPLY_VCC4,
+ TPS65910_SUPPLY_VCC3,
+ TPS65910_SUPPLY_VCC3
+};
+
+static int get_ctrl_reg_from_unit_addr(const uint unit_addr)
+{
+ if (unit_addr < ARRAY_SIZE(ctrl_regs))
+ return ctrl_regs[unit_addr];
+ return -ENXIO;
+}
+
+static int tps65910_regulator_get_value(struct udevice *dev,
+ const struct regulator_props *rgp)
+{
+ int sel, val, vout;
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+ int vin = pdata->supply;
+
+ val = pmic_reg_read(dev->parent, rgp->reg);
+ if (val < 0)
+ return val;
+ sel = (val & TPS65910_SEL_MASK) >> 2;
+ vout = (vin >= *(rgp->vin_min + sel)) ? *(rgp->vout + sel) : 0;
+ vout = ((val & TPS65910_SUPPLY_STATE_MASK) == 1) ? vout : 0;
+
+ return vout;
+}
+
+static int tps65910_ldo_get_value(struct udevice *dev)
+{
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+ int vin;
+
+ if (!pdata)
+ return 0;
+ vin = pdata->supply;
+
+ switch (pdata->unit) {
+ case TPS65910_UNIT_VRTC:
+ /* VRTC is fixed and can't be turned off */
+ return (vin >= 2500000) ? 1830000 : 0;
+ case TPS65910_UNIT_VDIG1:
+ return tps65910_regulator_get_value(dev, &ldo_props_vdig1);
+ case TPS65910_UNIT_VDIG2:
+ return tps65910_regulator_get_value(dev, &ldo_props_vdig2);
+ case TPS65910_UNIT_VPLL:
+ return tps65910_regulator_get_value(dev, &ldo_props_vpll);
+ case TPS65910_UNIT_VDAC:
+ return tps65910_regulator_get_value(dev, &ldo_props_vdac);
+ case TPS65910_UNIT_VAUX1:
+ return tps65910_regulator_get_value(dev, &ldo_props_vaux1);
+ case TPS65910_UNIT_VAUX2:
+ return tps65910_regulator_get_value(dev, &ldo_props_vaux2);
+ case TPS65910_UNIT_VAUX33:
+ return tps65910_regulator_get_value(dev, &ldo_props_vaux33);
+ case TPS65910_UNIT_VMMC:
+ return tps65910_regulator_get_value(dev, &ldo_props_vmmc);
+ default:
+ return 0;
+ }
+}
+
+static int tps65910_regulator_set_value(struct udevice *dev,
+ const struct regulator_props *ldo,
+ int uV)
+{
+ int val;
+ int sel = 0;
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+
+ do {
+ /* we only allow exact voltage matches */
+ if (uV == *(ldo->vout + sel))
+ break;
+ } while (++sel < VOUT_CHOICE_COUNT);
+ if (sel == VOUT_CHOICE_COUNT)
+ return -EINVAL;
+ if (pdata->supply < *(ldo->vin_min + sel))
+ return -EINVAL;
+
+ val = pmic_reg_read(dev->parent, ldo->reg);
+ if (val < 0)
+ return val;
+ val &= ~TPS65910_SEL_MASK;
+ val |= sel << 2;
+ return pmic_reg_write(dev->parent, ldo->reg, val);
+}
+
+static int tps65910_ldo_set_value(struct udevice *dev, int uV)
+{
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+ int vin = pdata->supply;
+
+ switch (pdata->unit) {
+ case TPS65910_UNIT_VRTC:
+ /* VRTC is fixed to 1.83V and can't be turned off */
+ if (vin < 2500000)
+ return -EINVAL;
+ return 0;
+ case TPS65910_UNIT_VDIG1:
+ return tps65910_regulator_set_value(dev, &ldo_props_vdig1, uV);
+ case TPS65910_UNIT_VDIG2:
+ return tps65910_regulator_set_value(dev, &ldo_props_vdig2, uV);
+ case TPS65910_UNIT_VPLL:
+ return tps65910_regulator_set_value(dev, &ldo_props_vpll, uV);
+ case TPS65910_UNIT_VDAC:
+ return tps65910_regulator_set_value(dev, &ldo_props_vdac, uV);
+ case TPS65910_UNIT_VAUX1:
+ return tps65910_regulator_set_value(dev, &ldo_props_vaux1, uV);
+ case TPS65910_UNIT_VAUX2:
+ return tps65910_regulator_set_value(dev, &ldo_props_vaux2, uV);
+ case TPS65910_UNIT_VAUX33:
+ return tps65910_regulator_set_value(dev, &ldo_props_vaux33, uV);
+ case TPS65910_UNIT_VMMC:
+ return tps65910_regulator_set_value(dev, &ldo_props_vmmc, uV);
+ default:
+ return 0;
+ }
+}
+
+static int tps65910_get_enable(struct udevice *dev)
+{
+ int reg, val;
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+
+ reg = get_ctrl_reg_from_unit_addr(pdata->unit);
+ if (reg < 0)
+ return reg;
+
+ val = pmic_reg_read(dev->parent, reg);
+ if (val < 0)
+ return val;
+
+ /* bits 1:0 of regulator control register define state */
+ return ((val & TPS65910_SUPPLY_STATE_MASK) == 1);
+}
+
+static int tps65910_set_enable(struct udevice *dev, bool enable)
+{
+ int reg;
+ uint clr, set;
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+
+ reg = get_ctrl_reg_from_unit_addr(pdata->unit);
+ if (reg < 0)
+ return reg;
+
+ if (enable) {
+ clr = TPS65910_SUPPLY_STATE_MASK & ~TPS65910_SUPPLY_STATE_ON;
+ set = TPS65910_SUPPLY_STATE_MASK & TPS65910_SUPPLY_STATE_ON;
+ } else {
+ clr = TPS65910_SUPPLY_STATE_MASK & ~TPS65910_SUPPLY_STATE_OFF;
+ set = TPS65910_SUPPLY_STATE_MASK & TPS65910_SUPPLY_STATE_OFF;
+ }
+ return pmic_clrsetbits(dev->parent, reg, clr, set);
+}
+
+static int buck_get_vdd1_vdd2_value(struct udevice *dev, int reg_vdd)
+{
+ int gain;
+ int val = pmic_reg_read(dev, reg_vdd);
+
+ if (val < 0)
+ return val;
+ gain = (val & TPS65910_GAIN_SEL_MASK) >> 6;
+ gain = (gain == 0) ? 1 : gain;
+ val = pmic_reg_read(dev, reg_vdd + 1);
+ if (val < 0)
+ return val;
+ if (val & TPS65910_VDD_SR_MASK)
+ /* use smart reflex value instead */
+ val = pmic_reg_read(dev, reg_vdd + 2);
+ if (val < 0)
+ return val;
+ return (562500 + (val & TPS65910_VDD_SEL_MASK) * 12500) * gain;
+}
+
+static int tps65910_buck_get_value(struct udevice *dev)
+{
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+
+ switch (pdata->unit) {
+ case TPS65910_UNIT_VIO:
+ return tps65910_regulator_get_value(dev, &smps_props_vio);
+ case TPS65910_UNIT_VDD1:
+ return buck_get_vdd1_vdd2_value(dev->parent, TPS65910_REG_VDD1);
+ case TPS65910_UNIT_VDD2:
+ return buck_get_vdd1_vdd2_value(dev->parent, TPS65910_REG_VDD2);
+ default:
+ return 0;
+ }
+}
+
+static int buck_set_vdd1_vdd2_value(struct udevice *dev, int uV)
+{
+ int ret, reg_vdd, gain;
+ int val;
+ struct dm_regulator_uclass_plat *uc_pdata;
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+
+ switch (pdata->unit) {
+ case TPS65910_UNIT_VDD1:
+ reg_vdd = TPS65910_REG_VDD1;
+ break;
+ case TPS65910_UNIT_VDD2:
+ reg_vdd = TPS65910_REG_VDD2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ /* check setpoint is within limits */
+ if (uV < uc_pdata->min_uV) {
+ pr_err("voltage %duV for %s too low\n", uV, dev->name);
+ return -EINVAL;
+ }
+ if (uV > uc_pdata->max_uV) {
+ pr_err("voltage %duV for %s too high\n", uV, dev->name);
+ return -EINVAL;
+ }
+
+ val = pmic_reg_read(dev->parent, reg_vdd);
+ if (val < 0)
+ return val;
+ gain = (val & TPS65910_GAIN_SEL_MASK) >> 6;
+ gain = (gain == 0) ? 1 : gain;
+ val = ((uV / gain) - 562500) / 12500;
+ if (val < TPS65910_VDD_SEL_MIN || val > TPS65910_VDD_SEL_MAX)
+ /*
+ * Neither do we change the gain, nor do we allow shutdown or
+ * any approximate value (for now)
+ */
+ return -EPERM;
+ val &= TPS65910_VDD_SEL_MASK;
+ ret = pmic_reg_write(dev->parent, reg_vdd + 1, val);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+static int tps65910_buck_set_value(struct udevice *dev, int uV)
+{
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+
+ if (pdata->unit == TPS65910_UNIT_VIO)
+ return tps65910_regulator_set_value(dev, &smps_props_vio, uV);
+
+ return buck_set_vdd1_vdd2_value(dev, uV);
+}
+
+static int tps65910_boost_get_value(struct udevice *dev)
+{
+ int vout;
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+
+ vout = (pdata->supply >= 3000000) ? 5000000 : 0;
+ return vout;
+}
+
+static int tps65910_regulator_of_to_plat(struct udevice *dev)
+{
+ struct udevice *supply;
+ int ret;
+ const char *supply_name;
+ struct tps65910_regulator_pdata *pdata = dev_get_plat(dev);
+
+ pdata->unit = dev_get_driver_data(dev);
+ if (pdata->unit > TPS65910_UNIT_VMMC)
+ return -EINVAL;
+ supply_name = supply_names[regulator_supplies[pdata->unit]];
+
+ debug("Looking up supply power %s\n", supply_name);
+ ret = device_get_supply_regulator(dev->parent, supply_name, &supply);
+ if (ret) {
+ debug(" missing supply power %s\n", supply_name);
+ return ret;
+ }
+ pdata->supply = regulator_get_value(supply);
+ if (pdata->supply < 0) {
+ debug(" invalid supply voltage for regulator %s\n",
+ supply->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops tps65910_boost_ops = {
+ .get_value = tps65910_boost_get_value,
+ .get_enable = tps65910_get_enable,
+ .set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_boost) = {
+ .name = TPS65910_BOOST_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65910_boost_ops,
+ .plat_auto = sizeof(struct tps65910_regulator_pdata),
+ .of_to_plat = tps65910_regulator_of_to_plat,
+};
+
+static const struct dm_regulator_ops tps65910_buck_ops = {
+ .get_value = tps65910_buck_get_value,
+ .set_value = tps65910_buck_set_value,
+ .get_enable = tps65910_get_enable,
+ .set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_buck) = {
+ .name = TPS65910_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65910_buck_ops,
+ .plat_auto = sizeof(struct tps65910_regulator_pdata),
+ .of_to_plat = tps65910_regulator_of_to_plat,
+};
+
+static const struct dm_regulator_ops tps65910_ldo_ops = {
+ .get_value = tps65910_ldo_get_value,
+ .set_value = tps65910_ldo_set_value,
+ .get_enable = tps65910_get_enable,
+ .set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_ldo) = {
+ .name = TPS65910_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65910_ldo_ops,
+ .plat_auto = sizeof(struct tps65910_regulator_pdata),
+ .of_to_plat = tps65910_regulator_of_to_plat,
+};
diff --git a/roms/u-boot/drivers/power/regulator/tps65941_regulator.c b/roms/u-boot/drivers/power/regulator/tps65941_regulator.c
new file mode 100644
index 000000000..d73f83248
--- /dev/null
+++ b/roms/u-boot/drivers/power/regulator/tps65941_regulator.c
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Keerthy <j-keerthy@ti.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65941.h>
+
+static const char tps65941_buck_ctrl[TPS65941_BUCK_NUM] = {0x4, 0x6, 0x8, 0xA,
+ 0xC};
+static const char tps65941_buck_vout[TPS65941_BUCK_NUM] = {0xE, 0x10, 0x12,
+ 0x14, 0x16};
+static const char tps65941_ldo_ctrl[TPS65941_BUCK_NUM] = {0x1D, 0x1E, 0x1F,
+ 0x20};
+static const char tps65941_ldo_vout[TPS65941_BUCK_NUM] = {0x23, 0x24, 0x25,
+ 0x26};
+
+static int tps65941_buck_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= TPS65941_BUCK_MODE_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= TPS65941_BUCK_MODE_MASK;
+ else
+ ret &= ~TPS65941_BUCK_MODE_MASK;
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps65941_buck_volt2val(int uV)
+{
+ if (uV > TPS65941_BUCK_VOLT_MAX)
+ return -EINVAL;
+ else if (uV > 1650000)
+ return (uV - 1660000) / 20000 + 0xAB;
+ else if (uV > 1110000)
+ return (uV - 1110000) / 10000 + 0x73;
+ else if (uV > 600000)
+ return (uV - 600000) / 5000 + 0x0F;
+ else if (uV >= 300000)
+ return (uV - 300000) / 20000 + 0x00;
+ else
+ return -EINVAL;
+}
+
+static int tps65941_buck_val2volt(int val)
+{
+ if (val > TPS65941_BUCK_VOLT_MAX_HEX)
+ return -EINVAL;
+ else if (val > 0xAB)
+ return 1660000 + (val - 0xAB) * 20000;
+ else if (val > 0x73)
+ return 1100000 + (val - 0x73) * 10000;
+ else if (val > 0xF)
+ return 600000 + (val - 0xF) * 5000;
+ else if (val >= 0x0)
+ return 300000 + val * 5000;
+ else
+ return -EINVAL;
+}
+
+int tps65941_lookup_slew(int id)
+{
+ switch (id) {
+ case 0:
+ return 33000;
+ case 1:
+ return 20000;
+ case 2:
+ return 10000;
+ case 3:
+ return 5000;
+ case 4:
+ return 2500;
+ case 5:
+ return 1300;
+ case 6:
+ return 630;
+ case 7:
+ return 310;
+ default:
+ return -1;
+ }
+}
+
+static int tps65941_buck_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret, delta, uwait, slew;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ ret &= TPS65941_BUCK_VOLT_MASK;
+ ret = tps65941_buck_val2volt(ret);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ *uV = ret;
+ return 0;
+ }
+
+ /*
+ * Compute the delta voltage, find the slew rate and wait
+ * for the appropriate amount of time after voltage switch
+ */
+ if (*uV > ret)
+ delta = *uV - ret;
+ else
+ delta = ret - *uV;
+
+ slew = pmic_reg_read(dev->parent, uc_pdata->ctrl_reg + 1);
+ if (slew < 0)
+ return ret;
+
+ slew &= TP65941_BUCK_CONF_SLEW_MASK;
+ slew = tps65941_lookup_slew(slew);
+ if (slew <= 0)
+ return ret;
+
+ uwait = delta / slew;
+
+ hex = tps65941_buck_volt2val(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= 0x0;
+ ret = hex;
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+
+ udelay(uwait);
+
+ return ret;
+}
+
+static int tps65941_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ int ret;
+ unsigned int adr;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ adr = uc_pdata->ctrl_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ ret &= TPS65941_LDO_MODE_MASK;
+
+ if (ret)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ if (*enable)
+ ret |= TPS65941_LDO_MODE_MASK;
+ else
+ ret &= ~TPS65941_LDO_MODE_MASK;
+ ret = pmic_reg_write(dev->parent, adr, ret);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps65941_ldo_val2volt(int val)
+{
+ if (val > TPS65941_LDO_VOLT_MAX_HEX || val < TPS65941_LDO_VOLT_MIN_HEX)
+ return -EINVAL;
+ else if (val >= TPS65941_LDO_VOLT_MIN_HEX)
+ return 600000 + (val - TPS65941_LDO_VOLT_MIN_HEX) * 50000;
+ else
+ return -EINVAL;
+}
+
+static int tps65941_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ unsigned int hex, adr;
+ int ret;
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
+
+ adr = uc_pdata->volt_reg;
+
+ ret = pmic_reg_read(dev->parent, adr);
+ if (ret < 0)
+ return ret;
+
+ ret &= TPS65941_LDO_VOLT_MASK;
+ ret = tps65941_ldo_val2volt(ret);
+ if (ret < 0)
+ return ret;
+
+ if (op == PMIC_OP_GET) {
+ *uV = ret;
+ return 0;
+ }
+
+ hex = tps65941_buck_volt2val(*uV);
+ if (hex < 0)
+ return hex;
+
+ ret &= 0x0;
+ ret = hex;
+
+ ret = pmic_reg_write(dev->parent, adr, ret);
+
+ return ret;
+}
+
+static int tps65941_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int idx;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+
+ idx = dev->driver_data;
+ if (idx == 1 || idx == 2 || idx == 3 || idx == 4) {
+ debug("Single phase regulator\n");
+ } else {
+ printf("Wrong ID for regulator\n");
+ return -EINVAL;
+ }
+
+ uc_pdata->ctrl_reg = tps65941_ldo_ctrl[idx - 1];
+ uc_pdata->volt_reg = tps65941_ldo_vout[idx - 1];
+
+ return 0;
+}
+
+static int tps65941_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+ int idx;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ idx = dev->driver_data;
+ if (idx == 1 || idx == 2 || idx == 3 || idx == 4 || idx == 5) {
+ debug("Single phase regulator\n");
+ } else if (idx == 12) {
+ idx = 1;
+ } else if (idx == 34) {
+ idx = 3;
+ } else if (idx == 1234) {
+ idx = 1;
+ } else {
+ printf("Wrong ID for regulator\n");
+ return -EINVAL;
+ }
+
+ uc_pdata->ctrl_reg = tps65941_buck_ctrl[idx - 1];
+ uc_pdata->volt_reg = tps65941_buck_vout[idx - 1];
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps65941_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return tps65941_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = tps65941_ldo_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ return tps65941_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps65941_buck_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int buck_set_value(struct udevice *dev, int uV)
+{
+ return tps65941_buck_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = tps65941_buck_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ return tps65941_buck_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops tps65941_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+};
+
+U_BOOT_DRIVER(tps65941_ldo) = {
+ .name = TPS65941_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65941_ldo_ops,
+ .probe = tps65941_ldo_probe,
+};
+
+static const struct dm_regulator_ops tps65941_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+};
+
+U_BOOT_DRIVER(tps65941_buck) = {
+ .name = TPS65941_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65941_buck_ops,
+ .probe = tps65941_buck_probe,
+};