aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/power')
-rw-r--r--roms/u-boot/drivers/power/Kconfig388
-rw-r--r--roms/u-boot/drivers/power/Makefile24
-rw-r--r--roms/u-boot/drivers/power/acpi_pmc/Kconfig34
-rw-r--r--roms/u-boot/drivers/power/acpi_pmc/Makefile6
-rw-r--r--roms/u-boot/drivers/power/acpi_pmc/acpi-pmc-uclass.c237
-rw-r--r--roms/u-boot/drivers/power/acpi_pmc/pmc_emul.c247
-rw-r--r--roms/u-boot/drivers/power/acpi_pmc/sandbox.c98
-rw-r--r--roms/u-boot/drivers/power/axp152.c91
-rw-r--r--roms/u-boot/drivers/power/axp209.c242
-rw-r--r--roms/u-boot/drivers/power/axp221.c276
-rw-r--r--roms/u-boot/drivers/power/axp305.c83
-rw-r--r--roms/u-boot/drivers/power/axp809.c232
-rw-r--r--roms/u-boot/drivers/power/axp818.c268
-rw-r--r--roms/u-boot/drivers/power/battery/Makefile7
-rw-r--r--roms/u-boot/drivers/power/battery/bat_trats.c91
-rw-r--r--roms/u-boot/drivers/power/battery/bat_trats2.c65
-rw-r--r--roms/u-boot/drivers/power/domain/Kconfig75
-rw-r--r--roms/u-boot/drivers/power/domain/Makefile16
-rw-r--r--roms/u-boot/drivers/power/domain/bcm6328-power-domain.c80
-rw-r--r--roms/u-boot/drivers/power/domain/imx8-power-domain-legacy.c385
-rw-r--r--roms/u-boot/drivers/power/domain/imx8-power-domain.c89
-rw-r--r--roms/u-boot/drivers/power/domain/imx8m-power-domain.c145
-rw-r--r--roms/u-boot/drivers/power/domain/meson-ee-pwrc.c483
-rw-r--r--roms/u-boot/drivers/power/domain/meson-gx-pwrc-vpu.c338
-rw-r--r--roms/u-boot/drivers/power/domain/mtk-power-domain.c415
-rw-r--r--roms/u-boot/drivers/power/domain/power-domain-uclass.c168
-rw-r--r--roms/u-boot/drivers/power/domain/sandbox-power-domain-test.c55
-rw-r--r--roms/u-boot/drivers/power/domain/sandbox-power-domain.c105
-rw-r--r--roms/u-boot/drivers/power/domain/tegra186-power-domain.c94
-rw-r--r--roms/u-boot/drivers/power/domain/ti-sci-power-domain.c140
-rw-r--r--roms/u-boot/drivers/power/exynos-tmu.c347
-rw-r--r--roms/u-boot/drivers/power/ftpmu010.c87
-rw-r--r--roms/u-boot/drivers/power/fuel_gauge/Makefile6
-rw-r--r--roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c287
-rw-r--r--roms/u-boot/drivers/power/mfd/Makefile8
-rw-r--r--roms/u-boot/drivers/power/mfd/fg_max77693.c137
-rw-r--r--roms/u-boot/drivers/power/mfd/muic_max77693.c77
-rw-r--r--roms/u-boot/drivers/power/mfd/pmic_max77693.c96
-rw-r--r--roms/u-boot/drivers/power/mt6323.c38
-rw-r--r--roms/u-boot/drivers/power/palmas.c216
-rw-r--r--roms/u-boot/drivers/power/pmic/Kconfig334
-rw-r--r--roms/u-boot/drivers/power/pmic/Makefile43
-rw-r--r--roms/u-boot/drivers/power/pmic/act8846.c86
-rw-r--r--roms/u-boot/drivers/power/pmic/as3722.c178
-rw-r--r--roms/u-boot/drivers/power/pmic/as3722_gpio.c120
-rw-r--r--roms/u-boot/drivers/power/pmic/bd71837.c111
-rw-r--r--roms/u-boot/drivers/power/pmic/da9063.c131
-rw-r--r--roms/u-boot/drivers/power/pmic/fan53555.c87
-rw-r--r--roms/u-boot/drivers/power/pmic/i2c_pmic_emul.c166
-rw-r--r--roms/u-boot/drivers/power/pmic/lp873x.c82
-rw-r--r--roms/u-boot/drivers/power/pmic/lp87565.c85
-rw-r--r--roms/u-boot/drivers/power/pmic/max77686.c88
-rw-r--r--roms/u-boot/drivers/power/pmic/max8997.c58
-rw-r--r--roms/u-boot/drivers/power/pmic/max8998.c58
-rw-r--r--roms/u-boot/drivers/power/pmic/mc34708.c106
-rw-r--r--roms/u-boot/drivers/power/pmic/mp5416.c99
-rw-r--r--roms/u-boot/drivers/power/pmic/muic_max8997.c74
-rw-r--r--roms/u-boot/drivers/power/pmic/palmas.c100
-rw-r--r--roms/u-boot/drivers/power/pmic/pca9450.c95
-rw-r--r--roms/u-boot/drivers/power/pmic/pfuze100.c93
-rw-r--r--roms/u-boot/drivers/power/pmic/pm8916.c86
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic-uclass.c200
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_hi6553.c133
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_ltc3676.c31
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_mc34vr500.c31
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_pca9450.c31
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_pfuze100.c31
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_pfuze3000.c31
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_tps62362.c70
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_tps65217.c150
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_tps65218.c260
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_tps65910.c121
-rw-r--r--roms/u-boot/drivers/power/pmic/pmic_tps65910_dm.c96
-rw-r--r--roms/u-boot/drivers/power/pmic/rk8xx.c198
-rw-r--r--roms/u-boot/drivers/power/pmic/rn5t567.c64
-rw-r--r--roms/u-boot/drivers/power/pmic/s2mps11.c88
-rw-r--r--roms/u-boot/drivers/power/pmic/s5m8767.c92
-rw-r--r--roms/u-boot/drivers/power/pmic/sandbox.c76
-rw-r--r--roms/u-boot/drivers/power/pmic/stpmic1.c269
-rw-r--r--roms/u-boot/drivers/power/pmic/tps65090.c90
-rw-r--r--roms/u-boot/drivers/power/pmic/tps65941.c84
-rw-r--r--roms/u-boot/drivers/power/power_core.c222
-rw-r--r--roms/u-boot/drivers/power/power_dialog.c32
-rw-r--r--roms/u-boot/drivers/power/power_fsl.c57
-rw-r--r--roms/u-boot/drivers/power/power_i2c.c154
-rw-r--r--roms/u-boot/drivers/power/power_spi.c72
-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
-rw-r--r--roms/u-boot/drivers/power/sy8106a.c30
-rw-r--r--roms/u-boot/drivers/power/tps6586x.c252
-rw-r--r--roms/u-boot/drivers/power/twl4030.c221
-rw-r--r--roms/u-boot/drivers/power/twl6030.c310
121 files changed, 22569 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/power/Kconfig b/roms/u-boot/drivers/power/Kconfig
new file mode 100644
index 000000000..c5fbf1f83
--- /dev/null
+++ b/roms/u-boot/drivers/power/Kconfig
@@ -0,0 +1,388 @@
+menu "Power"
+
+source "drivers/power/acpi_pmc/Kconfig"
+
+source "drivers/power/domain/Kconfig"
+
+source "drivers/power/pmic/Kconfig"
+
+source "drivers/power/regulator/Kconfig"
+
+choice
+ prompt "Select Sunxi PMIC Variant"
+ depends on ARCH_SUNXI
+ default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
+ default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40
+ default AXP305_POWER if MACH_SUN50I_H616
+ default AXP818_POWER if MACH_SUN8I_A83T
+ default SUNXI_NO_PMIC if MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_V3S
+
+config SUNXI_NO_PMIC
+ bool "board without a pmic"
+ ---help---
+ Select this for boards which do not use a PMIC.
+
+config AXP152_POWER
+ bool "axp152 pmic support"
+ depends on MACH_SUN5I
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Select this to enable support for the axp152 pmic found on most
+ A10s boards.
+
+config AXP209_POWER
+ bool "axp209 pmic support"
+ depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I_V3S
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Select this to enable support for the axp209 pmic found on most
+ A10, A13 and A20 boards.
+
+config AXP221_POWER
+ bool "axp221 / axp223 pmic support"
+ depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Select this to enable support for the axp221/axp223 pmic found on most
+ A23 and A31 boards.
+
+config AXP305_POWER
+ bool "axp305 pmic support"
+ depends on MACH_SUN50I_H616
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Select this to enable support for the axp305 pmic found on most
+ H616 boards.
+
+config AXP809_POWER
+ bool "axp809 pmic support"
+ depends on MACH_SUN9I
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Say y here to enable support for the axp809 pmic found on A80 boards.
+
+config AXP818_POWER
+ bool "axp818 pmic support"
+ depends on MACH_SUN8I_A83T
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Say y here to enable support for the axp818 pmic found on
+ A83T dev board.
+
+config SY8106A_POWER
+ bool "SY8106A pmic support"
+ depends on MACH_SUNXI_H3_H5
+ ---help---
+ Select this to enable support for the SY8106A pmic found on some
+ H3 boards.
+
+endchoice
+
+config AXP_DCDC1_VOLT
+ int "axp pmic dcdc1 voltage"
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 3300 if AXP818_POWER || MACH_SUN8I_R40
+ default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I
+ ---help---
+ Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to
+ disable dcdc1. On A23 / A31 / A33 (axp221) boards dcdc1 is used for
+ generic 3.3V IO voltage for external devices like the lcd-panal and
+ sdcard interfaces, etc. On most boards dcdc1 is undervolted to 3.0V to
+ save battery. On A31 devices dcdc1 is also used for VCC-IO. On A83T
+ dcdc1 is used for VCC-IO, nand, usb0, sd , etc. On A80 dcdc1 normally
+ powers some of the pingroups, NAND/eMMC, SD/MMC, and USB OTG.
+
+config AXP_DCDC2_VOLT
+ int "axp pmic dcdc2 voltage"
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 900 if AXP818_POWER
+ default 1400 if AXP152_POWER || AXP209_POWER
+ default 1200 if MACH_SUN6I
+ default 1100 if MACH_SUN8I
+ default 0 if MACH_SUN9I
+ ---help---
+ Set the voltage (mV) to program the axp pmic dcdc2 at, set to 0 to
+ disable dcdc2.
+ On A10(s) / A13 / A20 boards dcdc2 is VDD-CPU and should be 1.4V.
+ On A31 boards dcdc2 is used for VDD-GPU and should be 1.2V.
+ On A23/A33 boards dcdc2 is used for VDD-SYS and should be 1.1V.
+ On A80 boards dcdc2 powers the GPU and can be left off.
+ On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V.
+ On R40 boards dcdc2 is VDD-CPU and should be 1.1V
+
+config AXP_DCDC3_VOLT
+ int "axp pmic dcdc3 voltage"
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 900 if AXP809_POWER || AXP818_POWER
+ default 1500 if AXP152_POWER
+ default 1250 if AXP209_POWER
+ default 1100 if MACH_SUN8I_R40
+ default 1200 if MACH_SUN6I || MACH_SUN8I
+ ---help---
+ Set the voltage (mV) to program the axp pmic dcdc3 at, set to 0 to
+ disable dcdc3.
+ On A10(s) / A13 / A20 boards with an axp209 dcdc3 is VDD-INT-DLL and
+ should be 1.25V.
+ On A10s boards with an axp152 dcdc3 is VCC-DRAM and should be 1.5V.
+ On A23 / A31 / A33 boards dcdc3 is VDD-CPU and should be 1.2V.
+ On A80 boards dcdc3 is used for VDD-CPUA(cluster 0) and should be 0.9V.
+ On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V.
+ On R40 boards dcdc3 is VDD-SYS and VDD-GPU and should be 1.1V.
+
+config AXP_DCDC4_VOLT
+ int "axp pmic dcdc4 voltage"
+ depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP305_POWER
+ default 1250 if AXP152_POWER
+ default 1200 if MACH_SUN6I
+ default 0 if MACH_SUN8I
+ default 900 if MACH_SUN9I
+ default 1500 if AXP305_POWER
+ ---help---
+ Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to
+ disable dcdc4.
+ On A10s boards with an axp152 dcdc4 is VDD-INT-DLL and should be 1.25V.
+ On A31 boards dcdc4 is used for VDD-SYS and should be 1.2V.
+ On A23 / A33 boards dcdc4 is unused and should be disabled.
+ On A80 boards dcdc4 powers VDD-SYS, HDMI, USB OTG and should be 0.9V.
+ On A83T boards dcdc4 is used for VDD-GPU.
+ On H616 boards dcdcd is used for VCC-DRAM.
+
+config AXP_DCDC5_VOLT
+ int "axp pmic dcdc5 voltage"
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 1500 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I
+ ---help---
+ Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to
+ disable dcdc5.
+ On A23 / A31 / A33 / A80 / A83T / R40 boards dcdc5 is VCC-DRAM and
+ should be 1.5V, 1.35V if DDR3L is used.
+
+config AXP_ALDO1_VOLT
+ int "axp pmic (a)ldo1 voltage"
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 0 if MACH_SUN6I || MACH_SUN8I_R40
+ default 1800 if MACH_SUN8I_A83T
+ default 3000 if MACH_SUN8I || MACH_SUN9I
+ ---help---
+ Set the voltage (mV) to program the axp pmic aldo1 at, set to 0 to
+ disable aldo1.
+ On A31 boards aldo1 is often used to power the wifi module.
+ On A23 / A33 boards aldo1 is used for VCC-IO and should be 3.0V.
+ On A80 boards aldo1 powers the USB hosts and should be 3.0V.
+ On A83T / H8 boards aldo1 is used for MIPI CSI, DSI, HDMI, EFUSE, and
+ should be 1.8V.
+
+config AXP_ALDO2_VOLT
+ int "axp pmic (a)ldo2 voltage"
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 3000 if AXP152_POWER || AXP209_POWER
+ default 0 if MACH_SUN6I || MACH_SUN9I
+ default 1800 if MACH_SUN8I_A83T
+ default 2500 if MACH_SUN8I
+ ---help---
+ Set the voltage (mV) to program the axp pmic aldo2 at, set to 0 to
+ disable aldo2.
+ On A10(s) / A13 / A20 boards aldo2 is AVCC and should be 3.0V.
+ On A31 boards aldo2 is typically unused and should be disabled.
+ On A31 boards aldo2 may be used for LPDDR2 then it should be 1.8V.
+ On A23 / A33 boards aldo2 is used for VDD-DLL and should be 2.5V.
+ On A80 boards aldo2 powers PB pingroup and camera IO and can be left off.
+ On A83T / H8 boards aldo2 powers VDD-DLL, VCC18-PLL, CPVDD, VDD18-ADC,
+ LPDDR2, and the codec. It should be 1.8V.
+
+config AXP_ALDO3_VOLT
+ int "axp pmic (a)ldo3 voltage"
+ depends on AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 0 if AXP209_POWER || MACH_SUN9I
+ default 3000 if MACH_SUN6I || MACH_SUN8I
+ ---help---
+ Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to
+ disable aldo3.
+ On A10(s) / A13 / A20 boards aldo3 should be 2.8V.
+ On A23 / A31 / A33 / R40 boards aldo3 is VCC-PLL and AVCC and should
+ be 3.0V.
+ On A80 boards aldo3 is normally not used.
+ On A83T / H8 boards aldo3 is AVCC, VCC-PL, and VCC-LED, and should be
+ 3.0V.
+
+choice
+ prompt "axp pmic (a)ldo3 voltage rate control"
+ depends on AXP209_POWER
+ default AXP_ALDO3_VOLT_SLOPE_NONE
+ ---help---
+ The AXP can slowly ramp up voltage to reduce the inrush current when
+ changing voltages.
+ Note, this does not apply when enabling/disabling LDO3. See
+ "axp pmic (a)ldo3 inrush quirk" below to enable a slew rate to limit
+ inrush current on broken board designs.
+
+config AXP_ALDO3_VOLT_SLOPE_NONE
+ bool "No voltage slope"
+ ---help---
+ Tries to reach the next voltage setting near instantaneously. Measurements
+ indicate that this is about 0.0167 V/uS.
+
+config AXP_ALDO3_VOLT_SLOPE_16
+ bool "1.6 mV per uS"
+ ---help---
+ Increases the voltage by 1.6 mV per uS until the final voltage has
+ been reached. Note that the scaling is in 25 mV steps and thus
+ the slew rate in reality is about 25 mV/31.250 uS.
+
+config AXP_ALDO3_VOLT_SLOPE_08
+ bool "0.8 mV per uS"
+ ---help---
+ Increases the voltage by 0.8 mV per uS until the final voltage has
+ been reached. Note that the scaling is in 25 mV steps however and thus
+ the slew rate in reality is about 25 mV/15.625 uS.
+ This is the slowest supported rate.
+
+endchoice
+
+config AXP_ALDO3_INRUSH_QUIRK
+ bool "axp pmic (a)ldo3 inrush quirk"
+ depends on AXP209_POWER
+ default n
+ ---help---
+ The reference design denotes a value of 4.7 uF for the output capacitor
+ of LDO3. Some boards have too high capacitance causing an inrush current
+ and resulting an AXP209 shutdown.
+
+config AXP_ALDO4_VOLT
+ int "axp pmic (a)ldo4 voltage"
+ depends on AXP209_POWER
+ default 0 if AXP209_POWER
+ ---help---
+ Set the voltage (mV) to program the axp pmic aldo4 at, set to 0 to
+ disable aldo4.
+ On A10(s) / A13 / A20 boards aldo4 should be 2.8V.
+
+config AXP_DLDO1_VOLT
+ int "axp pmic dldo1 voltage"
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp pmic dldo1 at, set to 0 to
+ disable dldo1. On sun6i (A31) boards with ethernet dldo1 is often used
+ to power the ethernet phy. On A23, A33 and A80 boards this is often
+ used to power the wifi.
+
+config AXP_DLDO2_VOLT
+ int "axp pmic dldo2 voltage"
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 3000 if MACH_SUN9I
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp pmic dldo2 at, set to 0 to
+ disable dldo2.
+ On A80 boards dldo2 normally powers the PL pins and should be 3.0V.
+
+config AXP_DLDO3_VOLT
+ int "axp pmic dldo3 voltage"
+ depends on AXP221_POWER || AXP818_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp pmic dldo3 at, set to 0 to
+ disable dldo3.
+
+config AXP_DLDO4_VOLT
+ int "axp pmic dldo4 voltage"
+ depends on AXP221_POWER || AXP818_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp pmic dldo4 at, set to 0 to
+ disable dldo4.
+
+config AXP_ELDO1_VOLT
+ int "axp pmic eldo1 voltage"
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp pmic eldo1 at, set to 0 to
+ disable eldo1.
+
+config AXP_ELDO2_VOLT
+ int "axp pmic eldo2 voltage"
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp pmic eldo2 at, set to 0 to
+ disable eldo2.
+
+config AXP_ELDO3_VOLT
+ int "axp pmic eldo3 voltage"
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ default 3000 if MACH_SUN9I
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp pmic eldo3 at, set to 0 to
+ disable eldo3. On some A31(s) tablets it might be used to supply
+ 1.2V for the SSD2828 chip (converter of parallel LCD interface
+ into MIPI DSI).
+ On A80 boards it powers the PM pingroup and should be 3.0V.
+
+config AXP_FLDO1_VOLT
+ int "axp pmic fldo1 voltage"
+ depends on AXP818_POWER
+ default 0 if MACH_SUN8I_A83T
+ ---help---
+ Set the voltage (mV) to program the axp pmic fldo1 at, set to 0 to
+ disable fldo1.
+ On A83T / H8 boards fldo1 is VCC-HSIC and should be 1.2V if HSIC is
+ used.
+
+config AXP_FLDO2_VOLT
+ int "axp pmic fldo2 voltage"
+ depends on AXP818_POWER
+ default 900 if MACH_SUN8I_A83T
+ ---help---
+ Set the voltage (mV) to program the axp pmic fldo2 at, set to 0 to
+ disable fldo2.
+ On A83T / H8 boards fldo2 is VCC-CPUS and should be 0.9V.
+
+config AXP_FLDO3_VOLT
+ int "axp pmic fldo3 voltage"
+ depends on AXP818_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp pmic fldo3 at, set to 0 to
+ disable fldo3.
+
+config AXP_SW_ON
+ bool "axp pmic sw on"
+ depends on AXP809_POWER || AXP818_POWER
+ default n
+ ---help---
+ Enable to turn on axp pmic sw.
+
+config SY8106A_VOUT1_VOLT
+ int "SY8106A pmic VOUT1 voltage"
+ depends on SY8106A_POWER
+ default 1200
+ ---help---
+ Set the voltage (mV) to program the SY8106A pmic VOUT1. This
+ is typically used to power the VDD-CPU and should be 1200mV.
+ Values can range from 680mV till 1950mV.
+
+config TWL4030_POWER
+ depends on OMAP34XX
+ bool "Enable driver for TI TWL4030 power management chip"
+ imply CMD_POWEROFF
+ ---help---
+ The TWL4030 in a combination audio CODEC/power management with
+ GPIO and it is commonly used with the OMAP3 family of processors
+
+config POWER_MT6323
+ bool "Poweroff driver for mediatek mt6323"
+ select CMD_POWEROFF
+ help
+ This adds poweroff driver for mt6323
+ this pmic is used on mt7623 / Bananapi R2
+
+endmenu
diff --git a/roms/u-boot/drivers/power/Makefile b/roms/u-boot/drivers/power/Makefile
new file mode 100644
index 000000000..0bef06920
--- /dev/null
+++ b/roms/u-boot/drivers/power/Makefile
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2009 Wind River Systems, Inc.
+# Tom Rix <Tom.Rix at windriver.com>
+
+obj-$(CONFIG_AXP152_POWER) += axp152.o
+obj-$(CONFIG_AXP209_POWER) += axp209.o
+obj-$(CONFIG_AXP221_POWER) += axp221.o
+obj-$(CONFIG_AXP305_POWER) += axp305.o
+obj-$(CONFIG_AXP809_POWER) += axp809.o
+obj-$(CONFIG_AXP818_POWER) += axp818.o
+obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
+obj-$(CONFIG_FTPMU010_POWER) += ftpmu010.o
+obj-$(CONFIG_SY8106A_POWER) += sy8106a.o
+obj-$(CONFIG_TPS6586X_POWER) += tps6586x.o
+obj-$(CONFIG_TWL4030_POWER) += twl4030.o
+obj-$(CONFIG_TWL6030_POWER) += twl6030.o
+obj-$(CONFIG_PALMAS_POWER) += palmas.o
+obj-$(CONFIG_POWER) += power_core.o
+obj-$(CONFIG_DIALOG_POWER) += power_dialog.o
+obj-$(CONFIG_POWER_FSL) += power_fsl.o
+obj-$(CONFIG_POWER_I2C) += power_i2c.o
+obj-$(CONFIG_POWER_SPI) += power_spi.o
+obj-$(CONFIG_POWER_MT6323) += mt6323.o
diff --git a/roms/u-boot/drivers/power/acpi_pmc/Kconfig b/roms/u-boot/drivers/power/acpi_pmc/Kconfig
new file mode 100644
index 000000000..fcd50e36c
--- /dev/null
+++ b/roms/u-boot/drivers/power/acpi_pmc/Kconfig
@@ -0,0 +1,34 @@
+config ACPI_PMC
+ bool "Power Manager (x86 PMC) support"
+ help
+ Enable support for an x86-style power-management controller which
+ provides features including checking whether the system started from
+ resume, powering off the system and enabling/disabling the reset
+ mechanism.
+
+config SPL_ACPI_PMC
+ bool "Power Manager (x86 PMC) support in SPL"
+ default y if ACPI_PMC
+ help
+ Enable support for an x86-style power-management controller which
+ provides features including checking whether the system started from
+ resume, powering off the system and enabling/disabling the reset
+ mechanism.
+
+config TPL_ACPI_PMC
+ bool "Power Manager (x86 PMC) support in TPL"
+ default y if ACPI_PMC
+ help
+ Enable support for an x86-style power-management controller which
+ provides features including checking whether the system started from
+ resume, powering off the system and enabling/disabling the reset
+ mechanism.
+
+config ACPI_PMC_SANDBOX
+ bool "Test power manager (PMC) for sandbox"
+ depends on ACPI_PMC && SANDBOX
+ help
+ This driver emulates a PMC (Power-Management Controller) so that
+ the uclass logic can be tested. You can use the 'pmc' command to
+ access information from the driver. It uses I/O access to read
+ from the PMC.
diff --git a/roms/u-boot/drivers/power/acpi_pmc/Makefile b/roms/u-boot/drivers/power/acpi_pmc/Makefile
new file mode 100644
index 000000000..115788f10
--- /dev/null
+++ b/roms/u-boot/drivers/power/acpi_pmc/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += acpi-pmc-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC_SANDBOX) += sandbox.o pmc_emul.o
diff --git a/roms/u-boot/drivers/power/acpi_pmc/acpi-pmc-uclass.c b/roms/u-boot/drivers/power/acpi_pmc/acpi-pmc-uclass.c
new file mode 100644
index 000000000..34446a34e
--- /dev/null
+++ b/roms/u-boot/drivers/power/acpi_pmc/acpi-pmc-uclass.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_ACPI_PMC
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <spl.h>
+#include <acpi/acpi_s3.h>
+#ifdef CONFIG_X86
+#include <asm/intel_pinctrl.h>
+#endif
+#include <asm/io.h>
+#include <power/acpi_pmc.h>
+
+struct tco_regs {
+ u32 tco_rld;
+ u32 tco_sts;
+ u32 tco1_cnt;
+ u32 tco_tmr;
+};
+
+enum {
+ TCO_STS_TIMEOUT = 1 << 3,
+ TCO_STS_SECOND_TO_STS = 1 << 17,
+ TCO1_CNT_HLT = 1 << 11,
+};
+
+#ifdef CONFIG_X86
+static int gpe0_shift(struct acpi_pmc_upriv *upriv, int regnum)
+{
+ return upriv->gpe0_dwx_shift_base + regnum * 4;
+}
+
+int pmc_gpe_init(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ struct udevice *itss;
+ u32 *dw;
+ u32 gpio_cfg_mask;
+ u32 gpio_cfg;
+ int ret, i;
+ u32 mask;
+
+ if (device_get_uclass_id(dev) != UCLASS_ACPI_PMC)
+ return log_msg_ret("uclass", -EPROTONOSUPPORT);
+ dw = upriv->gpe0_dw;
+ mask = upriv->gpe0_dwx_mask;
+ gpio_cfg_mask = 0;
+ for (i = 0; i < upriv->gpe0_count; i++) {
+ gpio_cfg_mask |= mask << gpe0_shift(upriv, i);
+ if (dw[i] & ~mask)
+ return log_msg_ret("Base GPE0 value", -EINVAL);
+ }
+
+ /*
+ * Route the GPIOs to the GPE0 block. Determine that all values
+ * are different and if they aren't, use the reset values.
+ */
+ if (dw[0] == dw[1] || dw[1] == dw[2]) {
+ if (spl_phase() > PHASE_TPL)
+ log_info("PMC: Using default GPE route");
+ gpio_cfg = readl(upriv->gpe_cfg);
+ for (i = 0; i < upriv->gpe0_count; i++)
+ dw[i] = gpio_cfg >> gpe0_shift(upriv, i);
+ } else {
+ gpio_cfg = 0;
+ for (i = 0; i < upriv->gpe0_count; i++)
+ gpio_cfg |= dw[i] << gpe0_shift(upriv, i);
+ clrsetbits_le32(upriv->gpe_cfg, gpio_cfg_mask, gpio_cfg);
+ }
+
+ /* Set the routes in the GPIO communities as well */
+ ret = uclass_first_device_err(UCLASS_IRQ, &itss);
+ if (ret)
+ return log_msg_ret("Cannot find itss", ret);
+ pinctrl_route_gpe(itss, dw[0], dw[1], dw[2]);
+
+ return 0;
+}
+#endif /* CONFIG_X86 */
+
+static void pmc_fill_pm_reg_info(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ int i;
+
+ upriv->pm1_sts = inw(upriv->acpi_base + PM1_STS);
+ upriv->pm1_en = inw(upriv->acpi_base + PM1_EN);
+ upriv->pm1_cnt = inw(upriv->acpi_base + PM1_CNT);
+
+ log_debug("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
+ upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
+
+ for (i = 0; i < GPE0_REG_MAX; i++) {
+ upriv->gpe0_sts[i] = inl(upriv->acpi_base + GPE0_STS + i * 4);
+ upriv->gpe0_en[i] = inl(upriv->acpi_base + GPE0_EN + i * 4);
+ log_debug("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
+ upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
+ }
+}
+
+int pmc_disable_tco_base(ulong tco_base)
+{
+ struct tco_regs *regs = (struct tco_regs *)tco_base;
+
+ debug("tco_base %lx = %x\n", (ulong)&regs->tco1_cnt, TCO1_CNT_HLT);
+ setio_32(&regs->tco1_cnt, TCO1_CNT_HLT);
+
+ return 0;
+}
+
+int pmc_init(struct udevice *dev)
+{
+ const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+ int ret;
+
+ pmc_fill_pm_reg_info(dev);
+ if (!ops->init)
+ return -ENOSYS;
+
+ ret = ops->init(dev);
+ if (ret)
+ return log_msg_ret("Failed to init pmc", ret);
+
+#ifdef DEBUG
+ pmc_dump_info(dev);
+#endif
+
+ return 0;
+}
+
+int pmc_prev_sleep_state(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+ int prev_sleep_state = ACPI_S0; /* Default to S0 */
+
+ if (upriv->pm1_sts & WAK_STS) {
+ switch (acpi_sleep_from_pm1(upriv->pm1_cnt)) {
+ case ACPI_S3:
+ if (IS_ENABLED(HAVE_ACPI_RESUME))
+ prev_sleep_state = ACPI_S3;
+ break;
+ case ACPI_S5:
+ prev_sleep_state = ACPI_S5;
+ break;
+ default:
+ break;
+ }
+
+ /* Clear SLP_TYP */
+ outl(upriv->pm1_cnt & ~SLP_TYP, upriv->acpi_base + PM1_CNT);
+ }
+
+ if (!ops->prev_sleep_state)
+ return prev_sleep_state;
+
+ return ops->prev_sleep_state(dev, prev_sleep_state);
+}
+
+int pmc_disable_tco(struct udevice *dev)
+{
+ const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+
+ pmc_fill_pm_reg_info(dev);
+ if (!ops->disable_tco)
+ return -ENOSYS;
+
+ return ops->disable_tco(dev);
+}
+
+int pmc_global_reset_set_enable(struct udevice *dev, bool enable)
+{
+ const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+
+ if (!ops->global_reset_set_enable)
+ return -ENOSYS;
+
+ return ops->global_reset_set_enable(dev, enable);
+}
+
+void pmc_dump_info(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ int i;
+
+ printf("Device: %s\n", dev->name);
+ printf("ACPI base %x, pmc_bar0 %p, pmc_bar2 %p, gpe_cfg %p\n",
+ upriv->acpi_base, upriv->pmc_bar0, upriv->pmc_bar2,
+ upriv->gpe_cfg);
+ printf("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
+ upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
+
+ for (i = 0; i < GPE0_REG_MAX; i++) {
+ printf("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
+ upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
+ }
+
+ printf("prsts: %08x\n", upriv->prsts);
+ printf("tco_sts: %04x %04x\n", upriv->tco1_sts, upriv->tco2_sts);
+ printf("gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n",
+ upriv->gen_pmcon1, upriv->gen_pmcon2, upriv->gen_pmcon3);
+}
+
+int pmc_ofdata_to_uc_plat(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ int ret;
+
+ ret = dev_read_u32(dev, "gpe0-dwx-mask", &upriv->gpe0_dwx_mask);
+ if (ret)
+ return log_msg_ret("no gpe0-dwx-mask", ret);
+ ret = dev_read_u32(dev, "gpe0-dwx-shift-base",
+ &upriv->gpe0_dwx_shift_base);
+ if (ret)
+ return log_msg_ret("no gpe0-dwx-shift-base", ret);
+ ret = dev_read_u32(dev, "gpe0-sts", &upriv->gpe0_sts_reg);
+ if (ret)
+ return log_msg_ret("no gpe0-sts", ret);
+ upriv->gpe0_sts_reg += upriv->acpi_base;
+ ret = dev_read_u32(dev, "gpe0-en", &upriv->gpe0_en_reg);
+ if (ret)
+ return log_msg_ret("no gpe0-en", ret);
+ upriv->gpe0_en_reg += upriv->acpi_base;
+
+ return 0;
+}
+
+UCLASS_DRIVER(acpi_pmc) = {
+ .id = UCLASS_ACPI_PMC,
+ .name = "power-mgr",
+ .per_device_auto = sizeof(struct acpi_pmc_upriv),
+};
diff --git a/roms/u-boot/drivers/power/acpi_pmc/pmc_emul.c b/roms/u-boot/drivers/power/acpi_pmc/pmc_emul.c
new file mode 100644
index 000000000..a61eb5bd8
--- /dev/null
+++ b/roms/u-boot/drivers/power/acpi_pmc/pmc_emul.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI emulation device for an x86 Power-Management Controller (PMC)
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <asm/test.h>
+#include <power/acpi_pmc.h>
+
+/**
+ * struct pmc_emul_plat - platform data for this device
+ *
+ * @command: Current PCI command value
+ * @bar: Current base address values
+ */
+struct pmc_emul_plat {
+ u16 command;
+ u32 bar[6];
+};
+
+enum {
+ MEMMAP_SIZE = 0x80,
+};
+
+static struct pci_bar {
+ int type;
+ u32 size;
+} barinfo[] = {
+ { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { PCI_BASE_ADDRESS_SPACE_IO, 256 },
+};
+
+struct pmc_emul_priv {
+ u8 regs[MEMMAP_SIZE];
+};
+
+static int sandbox_pmc_emul_read_config(const struct udevice *emul, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ struct pmc_emul_plat *plat = dev_get_plat(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ *valuep = plat->command;
+ break;
+ case PCI_HEADER_TYPE:
+ *valuep = 0;
+ break;
+ case PCI_VENDOR_ID:
+ *valuep = SANDBOX_PCI_VENDOR_ID;
+ break;
+ case PCI_DEVICE_ID:
+ *valuep = SANDBOX_PCI_PMC_EMUL_ID;
+ break;
+ case PCI_CLASS_DEVICE:
+ if (size == PCI_SIZE_8) {
+ *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
+ } else {
+ *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
+ SANDBOX_PCI_CLASS_SUB_CODE;
+ }
+ break;
+ case PCI_CLASS_CODE:
+ *valuep = SANDBOX_PCI_CLASS_CODE;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1:
+ case PCI_BASE_ADDRESS_2:
+ case PCI_BASE_ADDRESS_3:
+ case PCI_BASE_ADDRESS_4:
+ case PCI_BASE_ADDRESS_5: {
+ int barnum;
+ u32 *bar;
+
+ barnum = pci_offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
+ barinfo[barnum].size);
+ break;
+ }
+ case PCI_CAPABILITY_LIST:
+ *valuep = PCI_CAP_ID_PM_OFFSET;
+ break;
+ }
+
+ return 0;
+}
+
+static int sandbox_pmc_emul_write_config(struct udevice *emul, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ struct pmc_emul_plat *plat = dev_get_plat(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ plat->command = value;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1: {
+ int barnum;
+ u32 *bar;
+
+ barnum = pci_offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ debug("w bar %d=%lx\n", barnum, value);
+ *bar = value;
+ /* space indicator (bit#0) is read-only */
+ *bar |= barinfo[barnum].type;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_pmc_emul_find_bar(struct udevice *emul, unsigned int addr,
+ int *barnump, unsigned int *offsetp)
+{
+ struct pmc_emul_plat *plat = dev_get_plat(emul);
+ int barnum;
+
+ for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
+ unsigned int size = barinfo[barnum].size;
+ u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
+
+ if (addr >= base && addr < base + size) {
+ *barnump = barnum;
+ *offsetp = addr - base;
+ return 0;
+ }
+ }
+ *barnump = -1;
+
+ return -ENOENT;
+}
+
+static int sandbox_pmc_emul_read_io(struct udevice *dev, unsigned int addr,
+ ulong *valuep, enum pci_size_t size)
+{
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ if (barnum == 4)
+ *valuep = offset;
+ else if (barnum == 0)
+ *valuep = offset;
+
+ return 0;
+}
+
+static int sandbox_pmc_emul_write_io(struct udevice *dev, unsigned int addr,
+ ulong value, enum pci_size_t size)
+{
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sandbox_pmc_emul_map_physmem(struct udevice *dev,
+ phys_addr_t addr, unsigned long *lenp,
+ void **ptrp)
+{
+ struct pmc_emul_priv *priv = dev_get_priv(dev);
+ unsigned int offset, avail;
+ int barnum;
+ int ret;
+
+ ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ if (barnum == 0) {
+ *ptrp = priv->regs + offset;
+ avail = barinfo[0].size - offset;
+ if (avail > barinfo[0].size)
+ *lenp = 0;
+ else
+ *lenp = min(*lenp, (ulong)avail);
+
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static int sandbox_pmc_probe(struct udevice *dev)
+{
+ struct pmc_emul_priv *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < MEMMAP_SIZE; i++)
+ priv->regs[i] = i;
+
+ return 0;
+}
+
+static struct dm_pci_emul_ops sandbox_pmc_emul_emul_ops = {
+ .read_config = sandbox_pmc_emul_read_config,
+ .write_config = sandbox_pmc_emul_write_config,
+ .read_io = sandbox_pmc_emul_read_io,
+ .write_io = sandbox_pmc_emul_write_io,
+ .map_physmem = sandbox_pmc_emul_map_physmem,
+};
+
+static const struct udevice_id sandbox_pmc_emul_ids[] = {
+ { .compatible = "sandbox,pmc-emul" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_pmc_emul_emul) = {
+ .name = "sandbox_pmc_emul_emul",
+ .id = UCLASS_PCI_EMUL,
+ .of_match = sandbox_pmc_emul_ids,
+ .ops = &sandbox_pmc_emul_emul_ops,
+ .probe = sandbox_pmc_probe,
+ .priv_auto = sizeof(struct pmc_emul_priv),
+ .plat_auto = sizeof(struct pmc_emul_plat),
+};
+
+static struct pci_device_id sandbox_pmc_emul_supported[] = {
+ { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
+ {},
+};
+
+U_BOOT_PCI_DEVICE(sandbox_pmc_emul_emul, sandbox_pmc_emul_supported);
diff --git a/roms/u-boot/drivers/power/acpi_pmc/sandbox.c b/roms/u-boot/drivers/power/acpi_pmc/sandbox.c
new file mode 100644
index 000000000..8cf03f737
--- /dev/null
+++ b/roms/u-boot/drivers/power/acpi_pmc/sandbox.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox PMC for testing
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_ACPI_PMC
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/io.h>
+#include <power/acpi_pmc.h>
+
+#define GPIO_GPE_CFG 0x1050
+
+/* Memory mapped IO registers behind PMC_BASE_ADDRESS */
+#define PRSTS 0x1000
+#define GEN_PMCON1 0x1020
+#define GEN_PMCON2 0x1024
+#define GEN_PMCON3 0x1028
+
+/* Offset of TCO registers from ACPI base I/O address */
+#define TCO_REG_OFFSET 0x60
+#define TCO1_STS 0x64
+#define TCO2_STS 0x66
+#define TCO1_CNT 0x68
+#define TCO2_CNT 0x6a
+
+struct sandbox_pmc_priv {
+ ulong base;
+};
+
+static int sandbox_pmc_fill_power_state(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+ upriv->tco1_sts = inw(upriv->acpi_base + TCO1_STS);
+ upriv->tco2_sts = inw(upriv->acpi_base + TCO2_STS);
+
+ upriv->prsts = readl(upriv->pmc_bar0 + PRSTS);
+ upriv->gen_pmcon1 = readl(upriv->pmc_bar0 + GEN_PMCON1);
+ upriv->gen_pmcon2 = readl(upriv->pmc_bar0 + GEN_PMCON2);
+ upriv->gen_pmcon3 = readl(upriv->pmc_bar0 + GEN_PMCON3);
+
+ return 0;
+}
+
+static int sandbox_prev_sleep_state(struct udevice *dev, int prev_sleep_state)
+{
+ return prev_sleep_state;
+}
+
+static int sandbox_disable_tco(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+ pmc_disable_tco_base(upriv->acpi_base + TCO_REG_OFFSET);
+
+ return 0;
+}
+
+static int sandbox_pmc_probe(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ struct udevice *bus;
+ ulong base;
+
+ uclass_first_device(UCLASS_PCI, &bus);
+ base = dm_pci_read_bar32(dev, 0);
+ if (base == FDT_ADDR_T_NONE)
+ return log_msg_ret("No base address", -EINVAL);
+ upriv->pmc_bar0 = map_sysmem(base, 0x2000);
+ upriv->gpe_cfg = (u32 *)(upriv->pmc_bar0 + GPIO_GPE_CFG);
+
+ return pmc_ofdata_to_uc_plat(dev);
+}
+
+static struct acpi_pmc_ops sandbox_pmc_ops = {
+ .init = sandbox_pmc_fill_power_state,
+ .prev_sleep_state = sandbox_prev_sleep_state,
+ .disable_tco = sandbox_disable_tco,
+};
+
+static const struct udevice_id sandbox_pmc_ids[] = {
+ { .compatible = "sandbox,pmc" },
+ { }
+};
+
+U_BOOT_DRIVER(pmc_sandbox) = {
+ .name = "pmc_sandbox",
+ .id = UCLASS_ACPI_PMC,
+ .of_match = sandbox_pmc_ids,
+ .probe = sandbox_pmc_probe,
+ .ops = &sandbox_pmc_ops,
+ .priv_auto = sizeof(struct sandbox_pmc_priv),
+};
diff --git a/roms/u-boot/drivers/power/axp152.c b/roms/u-boot/drivers/power/axp152.c
new file mode 100644
index 000000000..d6e36125c
--- /dev/null
+++ b/roms/u-boot/drivers/power/axp152.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012
+ * Henrik Nordstrom <henrik@henriknordstrom.net>
+ */
+#include <common.h>
+#include <command.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+static u8 axp152_mvolt_to_target(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+ int rc;
+ u8 current, target;
+
+ target = axp152_mvolt_to_target(mvolt, 700, 2275, 25);
+
+ /* Do we really need to be this gentle? It has built-in voltage slope */
+ while ((rc = pmic_bus_read(AXP152_DCDC2_VOLTAGE, &current)) == 0 &&
+ current != target) {
+ if (current < target)
+ current++;
+ else
+ current--;
+ rc = pmic_bus_write(AXP152_DCDC2_VOLTAGE, current);
+ if (rc)
+ break;
+ }
+ return rc;
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+ u8 target = axp152_mvolt_to_target(mvolt, 700, 3500, 50);
+
+ return pmic_bus_write(AXP152_DCDC3_VOLTAGE, target);
+}
+
+int axp_set_dcdc4(unsigned int mvolt)
+{
+ u8 target = axp152_mvolt_to_target(mvolt, 700, 3500, 25);
+
+ return pmic_bus_write(AXP152_DCDC4_VOLTAGE, target);
+}
+
+int axp_set_aldo2(unsigned int mvolt)
+{
+ u8 target = axp152_mvolt_to_target(mvolt, 700, 3500, 100);
+
+ return pmic_bus_write(AXP152_LDO2_VOLTAGE, target);
+}
+
+int axp_init(void)
+{
+ u8 ver;
+ int rc;
+
+ rc = pmic_bus_init();
+ if (rc)
+ return rc;
+
+ rc = pmic_bus_read(AXP152_CHIP_VERSION, &ver);
+ if (rc)
+ return rc;
+
+ if (ver != 0x05)
+ return -EINVAL;
+
+ return 0;
+}
+
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP152_SHUTDOWN, AXP152_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/axp209.c b/roms/u-boot/drivers/power/axp209.c
new file mode 100644
index 000000000..ade531940
--- /dev/null
+++ b/roms/u-boot/drivers/power/axp209.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012
+ * Henrik Nordstrom <henrik@henriknordstrom.net>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_08
+# define AXP209_VRC_SLOPE AXP209_VRC_LDO3_800uV_uS
+#endif
+#ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_16
+# define AXP209_VRC_SLOPE AXP209_VRC_LDO3_1600uV_uS
+#endif
+#if defined CONFIG_AXP_ALDO3_VOLT_SLOPE_NONE || !defined AXP209_VRC_SLOPE
+# define AXP209_VRC_SLOPE 0x00
+#endif
+
+static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+ int rc;
+ u8 cfg, current;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+ AXP209_OUTPUT_CTRL_DCDC2);
+
+ rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2);
+ if (rc)
+ return rc;
+
+ cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
+
+ /* Do we really need to be this gentle? It has built-in voltage slope */
+ while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, &current)) == 0 &&
+ current != cfg) {
+ if (current < cfg)
+ current++;
+ else
+ current--;
+
+ rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+ u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
+ int rc;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+ AXP209_OUTPUT_CTRL_DCDC3);
+
+ rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg);
+ if (rc)
+ return rc;
+
+ return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3);
+}
+
+int axp_set_aldo2(unsigned int mvolt)
+{
+ int rc;
+ u8 cfg, reg;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+ AXP209_OUTPUT_CTRL_LDO2);
+
+ cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
+
+ rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
+ if (rc)
+ return rc;
+
+ reg |= AXP209_LDO24_LDO2_SET(reg, cfg);
+ rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
+ if (rc)
+ return rc;
+
+ return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2);
+}
+
+int axp_set_aldo3(unsigned int mvolt)
+{
+ u8 cfg;
+ int rc;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+ AXP209_OUTPUT_CTRL_LDO3);
+
+ /*
+ * Some boards have trouble reaching the target voltage without causing
+ * great inrush currents. To prevent this, boards can enable a certain
+ * slope to ramp up voltage. Note, this only works when changing an
+ * already active power rail. When toggling power on, the AXP ramps up
+ * steeply at 0.0167 V/uS.
+ */
+ rc = pmic_bus_read(AXP209_VRC_DCDC2_LDO3, &cfg);
+ cfg = AXP209_VRC_LDO3_SLOPE_SET(cfg, AXP209_VRC_SLOPE);
+ rc |= pmic_bus_write(AXP209_VRC_DCDC2_LDO3, cfg);
+
+ if (rc)
+ return rc;
+
+#ifdef CONFIG_AXP_ALDO3_INRUSH_QUIRK
+ /*
+ * On some boards, LDO3 has a too big capacitor installed. When
+ * turning on LDO3, this causes the AXP209 to shutdown on
+ * voltages over 1.9 volt. As a workaround, we enable LDO3
+ * first with the lowest possible voltage. If this still causes
+ * high inrush currents, the voltage slope should be increased.
+ */
+ rc = pmic_bus_read(AXP209_OUTPUT_CTRL, &cfg);
+ if (rc)
+ return rc;
+
+ if (!(cfg & AXP209_OUTPUT_CTRL_LDO3)) {
+ rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, 0x0); /* 0.7 Volt */
+ mdelay(1);
+ rc |= pmic_bus_setbits(AXP209_OUTPUT_CTRL,
+ AXP209_OUTPUT_CTRL_LDO3);
+
+ if (rc)
+ return rc;
+ }
+#endif
+
+ if (mvolt == -1) {
+ cfg = AXP209_LDO3_VOLTAGE_FROM_LDO3IN;
+ } else {
+ cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
+ cfg = AXP209_LDO3_VOLTAGE_SET(cfg);
+ }
+
+ rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
+ if (rc)
+ return rc;
+
+ return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
+}
+
+int axp_set_aldo4(unsigned int mvolt)
+{
+ int rc;
+ static const unsigned int vindex[] = {
+ 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
+ 2700, 2800, 3000, 3100, 3200, 3300
+ };
+ u8 cfg, reg;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+ AXP209_OUTPUT_CTRL_LDO4);
+
+ /* Translate mvolt to register cfg value, requested <= selected */
+ for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
+
+ rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
+ if (rc)
+ return rc;
+
+ reg |= AXP209_LDO24_LDO4_SET(reg, cfg);
+ rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
+ if (rc)
+ return rc;
+
+ return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
+}
+
+int axp_init(void)
+{
+ u8 ver;
+ int i, rc;
+
+ rc = pmic_bus_init();
+ if (rc)
+ return rc;
+
+ rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
+ if (rc)
+ return rc;
+
+ if ((ver & AXP209_CHIP_VERSION_MASK) != 0x1)
+ return -EINVAL;
+
+ /* Mask all interrupts */
+ for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
+ rc = pmic_bus_write(i, 0);
+ if (rc)
+ return rc;
+ }
+
+ /*
+ * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
+ * from android these are sometimes on.
+ */
+ rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
+ if (rc)
+ return rc;
+
+ rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
+ if (rc)
+ return rc;
+
+ rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/axp221.c b/roms/u-boot/drivers/power/axp221.c
new file mode 100644
index 000000000..3446fe736
--- /dev/null
+++ b/roms/u-boot/drivers/power/axp221.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AXP221 and AXP223 driver
+ *
+ * IMPORTANT when making changes to this file check that the registers
+ * used are the same for the axp221 and axp223.
+ *
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int axp_set_dcdc1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC1_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DCDC1SW_EN);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC1_EN);
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC2_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC2_EN);
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC3_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC3_EN);
+}
+
+int axp_set_dcdc4(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC4_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC4_EN);
+}
+
+int axp_set_dcdc5(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC5_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC5_EN);
+}
+
+int axp_set_aldo1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO1_EN);
+
+ ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO1_EN);
+}
+
+int axp_set_aldo2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO2_EN);
+
+ ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO2_EN);
+}
+
+int axp_set_aldo3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL3,
+ AXP221_OUTPUT_CTRL3_ALDO3_EN);
+
+ ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL3,
+ AXP221_OUTPUT_CTRL3_ALDO3_EN);
+}
+
+int axp_set_dldo(int dldo_num, unsigned int mvolt)
+{
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+ int ret;
+
+ if (dldo_num < 1 || dldo_num > 4)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+
+ ret = pmic_bus_write(AXP221_DLDO1_CTRL + (dldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+}
+
+int axp_set_eldo(int eldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (eldo_num < 1 || eldo_num > 3)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+
+ ret = pmic_bus_write(AXP221_ELDO1_CTRL + (eldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+}
+
+int axp_init(void)
+{
+ u8 axp_chip_id;
+ int ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
+ return -ENODEV;
+
+ /*
+ * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
+ * from android these are sometimes on.
+ */
+ ret = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int axp_get_sid(unsigned int *sid)
+{
+ u8 *dest = (u8 *)sid;
+ int i, ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_write(AXP221_PAGE, 1);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < 16; i++) {
+ ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
+ if (ret)
+ return ret;
+ }
+
+ pmic_bus_write(AXP221_PAGE, 0);
+
+ for (i = 0; i < 4; i++)
+ sid[i] = be32_to_cpu(sid[i]);
+
+ return 0;
+}
+
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP221_SHUTDOWN, AXP221_SHUTDOWN_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/axp305.c b/roms/u-boot/drivers/power/axp305.c
new file mode 100644
index 000000000..0191e4d42
--- /dev/null
+++ b/roms/u-boot/drivers/power/axp305.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AXP305 driver
+ *
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * Based on axp221.c
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+#define AXP305_DCDC4_1600MV_OFFSET 46
+
+static u8 axp305_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int axp_set_dcdc4(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (mvolt >= 1600)
+ cfg = AXP305_DCDC4_1600MV_OFFSET +
+ axp305_mvolt_to_cfg(mvolt, 1600, 3300, 100);
+ else
+ cfg = axp305_mvolt_to_cfg(mvolt, 600, 1500, 20);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP305_OUTPUT_CTRL1,
+ AXP305_OUTPUT_CTRL1_DCDCD_EN);
+
+ ret = pmic_bus_write(AXP305_DCDCD_VOLTAGE, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP305_OUTPUT_CTRL1,
+ AXP305_OUTPUT_CTRL1_DCDCD_EN);
+}
+
+int axp_init(void)
+{
+ u8 axp_chip_id;
+ int ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_read(AXP305_CHIP_VERSION, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ if ((axp_chip_id & AXP305_CHIP_VERSION_MASK) != 0x40)
+ return -ENODEV;
+
+ return ret;
+}
+
+#ifndef CONFIG_PSCI_RESET
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP305_SHUTDOWN, AXP305_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/drivers/power/axp809.c b/roms/u-boot/drivers/power/axp809.c
new file mode 100644
index 000000000..6323492b6
--- /dev/null
+++ b/roms/u-boot/drivers/power/axp809.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AXP809 driver based on AXP221 driver
+ *
+ *
+ * (C) Copyright 2016 Chen-Yu Tsai <wens@csie.org>
+ *
+ * Based on axp221.c
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+static u8 axp809_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int axp_set_dcdc1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp809_mvolt_to_cfg(mvolt, 1600, 3400, 100);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC1_EN);
+
+ ret = pmic_bus_write(AXP809_DCDC1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_DC1SW_EN);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC1_EN);
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC2_EN);
+
+ ret = pmic_bus_write(AXP809_DCDC2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC2_EN);
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1860, 20);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC3_EN);
+
+ ret = pmic_bus_write(AXP809_DCDC3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC3_EN);
+}
+
+int axp_set_dcdc4(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+ if (mvolt >= 1540)
+ cfg = 0x30 + axp809_mvolt_to_cfg(mvolt, 1800, 2600, 100);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC4_EN);
+
+ ret = pmic_bus_write(AXP809_DCDC5_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC4_EN);
+}
+
+int axp_set_dcdc5(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp809_mvolt_to_cfg(mvolt, 1000, 2550, 50);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC5_EN);
+
+ ret = pmic_bus_write(AXP809_DCDC5_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_DCDC5_EN);
+}
+
+int axp_set_aldo(int aldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (aldo_num < 1 || aldo_num > 3)
+ return -EINVAL;
+
+ if (mvolt == 0 && aldo_num == 3)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_ALDO3_EN);
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_ALDO1_EN << (aldo_num - 1));
+
+ cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
+ ret = pmic_bus_write(AXP809_ALDO1_CTRL + (aldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ if (aldo_num == 3)
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_ALDO3_EN);
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+ AXP809_OUTPUT_CTRL1_ALDO1_EN << (aldo_num - 1));
+}
+
+/* TODO: re-work other AXP drivers to consolidate ALDO functions. */
+int axp_set_aldo1(unsigned int mvolt)
+{
+ return axp_set_aldo(1, mvolt);
+}
+
+int axp_set_aldo2(unsigned int mvolt)
+{
+ return axp_set_aldo(2, mvolt);
+}
+
+int axp_set_aldo3(unsigned int mvolt)
+{
+ return axp_set_aldo(3, mvolt);
+}
+
+int axp_set_dldo(int dldo_num, unsigned int mvolt)
+{
+ u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
+ int ret;
+
+ if (dldo_num < 1 || dldo_num > 2)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+
+ if (dldo_num == 1 && mvolt > 3300)
+ cfg += 1 + axp809_mvolt_to_cfg(mvolt, 3400, 4200, 200);
+ ret = pmic_bus_write(AXP809_DLDO1_CTRL + (dldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+}
+
+int axp_set_eldo(int eldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (eldo_num < 1 || eldo_num > 3)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+
+ ret = pmic_bus_write(AXP809_ELDO1_CTRL + (eldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+}
+
+int axp_set_sw(bool on)
+{
+ if (on)
+ return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_SWOUT_EN);
+
+ return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
+ AXP809_OUTPUT_CTRL2_SWOUT_EN);
+}
+
+int axp_init(void)
+{
+ return pmic_bus_init();
+}
+
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP809_SHUTDOWN, AXP809_SHUTDOWN_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/axp818.c b/roms/u-boot/drivers/power/axp818.c
new file mode 100644
index 000000000..0531707c8
--- /dev/null
+++ b/roms/u-boot/drivers/power/axp818.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AXP818 driver based on AXP221 driver
+ *
+ *
+ * (C) Copyright 2015 Vishnu Patekar <vishnuptekar0510@gmail.com>
+ *
+ * Based on axp221.c
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+static u8 axp818_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int axp_set_dcdc1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp818_mvolt_to_cfg(mvolt, 1600, 3400, 100);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1,
+ AXP818_OUTPUT_CTRL1_DCDC1_EN);
+
+ ret = pmic_bus_write(AXP818_DCDC1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL1,
+ AXP818_OUTPUT_CTRL1_DCDC1_EN);
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (mvolt >= 1220)
+ cfg = 70 + axp818_mvolt_to_cfg(mvolt, 1220, 1300, 20);
+ else
+ cfg = axp818_mvolt_to_cfg(mvolt, 500, 1200, 10);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1,
+ AXP818_OUTPUT_CTRL1_DCDC2_EN);
+
+ ret = pmic_bus_write(AXP818_DCDC2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL1,
+ AXP818_OUTPUT_CTRL1_DCDC2_EN);
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (mvolt >= 1220)
+ cfg = 70 + axp818_mvolt_to_cfg(mvolt, 1220, 1300, 20);
+ else
+ cfg = axp818_mvolt_to_cfg(mvolt, 500, 1200, 10);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1,
+ AXP818_OUTPUT_CTRL1_DCDC3_EN);
+
+ ret = pmic_bus_write(AXP818_DCDC3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL1,
+ AXP818_OUTPUT_CTRL1_DCDC3_EN);
+}
+
+int axp_set_dcdc5(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (mvolt >= 1140)
+ cfg = 32 + axp818_mvolt_to_cfg(mvolt, 1140, 1840, 20);
+ else
+ cfg = axp818_mvolt_to_cfg(mvolt, 800, 1120, 10);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1,
+ AXP818_OUTPUT_CTRL1_DCDC5_EN);
+
+ ret = pmic_bus_write(AXP818_DCDC5_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL1,
+ AXP818_OUTPUT_CTRL1_DCDC5_EN);
+}
+
+int axp_set_aldo(int aldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (aldo_num < 1 || aldo_num > 3)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL3,
+ AXP818_OUTPUT_CTRL3_ALDO1_EN << (aldo_num - 1));
+
+ cfg = axp818_mvolt_to_cfg(mvolt, 700, 3300, 100);
+ ret = pmic_bus_write(AXP818_ALDO1_CTRL + (aldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL3,
+ AXP818_OUTPUT_CTRL3_ALDO1_EN << (aldo_num - 1));
+}
+
+/* TODO: re-work other AXP drivers to consolidate ALDO functions. */
+int axp_set_aldo1(unsigned int mvolt)
+{
+ return axp_set_aldo(1, mvolt);
+}
+
+int axp_set_aldo2(unsigned int mvolt)
+{
+ return axp_set_aldo(2, mvolt);
+}
+
+int axp_set_aldo3(unsigned int mvolt)
+{
+ return axp_set_aldo(3, mvolt);
+}
+
+int axp_set_dldo(int dldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (dldo_num < 1 || dldo_num > 4)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL2,
+ AXP818_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+
+ cfg = axp818_mvolt_to_cfg(mvolt, 700, 3300, 100);
+ if (dldo_num == 2 && mvolt > 3300)
+ cfg += 1 + axp818_mvolt_to_cfg(mvolt, 3400, 4200, 200);
+ ret = pmic_bus_write(AXP818_DLDO1_CTRL + (dldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL2,
+ AXP818_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+}
+
+int axp_set_eldo(int eldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (eldo_num < 1 || eldo_num > 3)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL2,
+ AXP818_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+
+ cfg = axp818_mvolt_to_cfg(mvolt, 700, 1900, 50);
+ ret = pmic_bus_write(AXP818_ELDO1_CTRL + (eldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL2,
+ AXP818_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+}
+
+int axp_set_fldo(int fldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (fldo_num < 1 || fldo_num > 3)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL3,
+ AXP818_OUTPUT_CTRL3_FLDO1_EN << (fldo_num - 1));
+
+ if (fldo_num < 3) {
+ cfg = axp818_mvolt_to_cfg(mvolt, 700, 1450, 50);
+ ret = pmic_bus_write(AXP818_FLDO1_CTRL + (fldo_num - 1), cfg);
+ } else {
+ /*
+ * Special case for FLDO3, which is DCDC5 / 2 or FLDOIN / 2
+ * Since FLDOIN is unknown, test against DCDC5.
+ */
+ if (mvolt * 2 == CONFIG_AXP_DCDC5_VOLT)
+ ret = pmic_bus_clrbits(AXP818_FLDO2_3_CTRL,
+ AXP818_FLDO2_3_CTRL_FLDO3_VOL);
+ else
+ ret = pmic_bus_setbits(AXP818_FLDO2_3_CTRL,
+ AXP818_FLDO2_3_CTRL_FLDO3_VOL);
+ }
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL3,
+ AXP818_OUTPUT_CTRL3_FLDO1_EN << (fldo_num - 1));
+}
+
+int axp_set_sw(bool on)
+{
+ if (on)
+ return pmic_bus_setbits(AXP818_OUTPUT_CTRL2,
+ AXP818_OUTPUT_CTRL2_SW_EN);
+
+ return pmic_bus_clrbits(AXP818_OUTPUT_CTRL2,
+ AXP818_OUTPUT_CTRL2_SW_EN);
+}
+
+int axp_init(void)
+{
+ u8 axp_chip_id;
+ int ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_read(AXP818_CHIP_ID, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ if (!(axp_chip_id == 0x51))
+ return -ENODEV;
+ else
+ return ret;
+
+ return 0;
+}
+
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP818_SHUTDOWN, AXP818_SHUTDOWN_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/battery/Makefile b/roms/u-boot/drivers/power/battery/Makefile
new file mode 100644
index 000000000..370923a6e
--- /dev/null
+++ b/roms/u-boot/drivers/power/battery/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2012 Samsung Electronics
+# Lukasz Majewski <l.majewski@samsung.com>
+
+obj-$(CONFIG_POWER_BATTERY_TRATS) += bat_trats.o
+obj-$(CONFIG_POWER_BATTERY_TRATS2) += bat_trats2.o
diff --git a/roms/u-boot/drivers/power/battery/bat_trats.c b/roms/u-boot/drivers/power/battery/bat_trats.c
new file mode 100644
index 000000000..54b2bf91e
--- /dev/null
+++ b/roms/u-boot/drivers/power/battery/bat_trats.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ */
+
+#include <common.h>
+#include <console.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <power/pmic.h>
+#include <power/battery.h>
+#include <power/max8997_pmic.h>
+#include <errno.h>
+
+static struct battery battery_trats;
+
+static int power_battery_charge(struct pmic *bat)
+{
+ struct power_battery *p_bat = bat->pbat;
+ struct battery *battery = p_bat->bat;
+ int k;
+
+ if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450))
+ return -1;
+
+ for (k = 0; bat->chrg->chrg_bat_present(p_bat->chrg) &&
+ bat->chrg->chrg_type(p_bat->muic) &&
+ battery->state_of_chrg < 100; k++) {
+ udelay(2000000);
+ if (!(k % 5))
+ puts(".");
+ bat->fg->fg_battery_update(p_bat->fg, bat);
+
+ if (k == 200) {
+ debug(" %d [V]", battery->voltage_uV);
+ puts("\n");
+ k = 0;
+ }
+
+ if (ctrlc()) {
+ printf("\nCharging disabled on request.\n");
+ goto exit;
+ }
+ }
+ exit:
+ bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_DISABLE, 0);
+
+ return 0;
+}
+
+static int power_battery_init_trats(struct pmic *bat_,
+ struct pmic *fg_,
+ struct pmic *chrg_,
+ struct pmic *muic_)
+{
+ bat_->pbat->fg = fg_;
+ bat_->pbat->chrg = chrg_;
+ bat_->pbat->muic = muic_;
+
+ bat_->fg = fg_->fg;
+ bat_->chrg = chrg_->chrg;
+ bat_->chrg->chrg_type = muic_->chrg->chrg_type;
+ return 0;
+}
+
+static struct power_battery power_bat_trats = {
+ .bat = &battery_trats,
+ .battery_init = power_battery_init_trats,
+ .battery_charge = power_battery_charge,
+};
+
+int power_bat_init(unsigned char bus)
+{
+ static const char name[] = "BAT_TRATS";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board BAT init\n");
+
+ p->interface = PMIC_NONE;
+ p->name = name;
+ p->bus = bus;
+
+ p->pbat = &power_bat_trats;
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/battery/bat_trats2.c b/roms/u-boot/drivers/power/battery/bat_trats2.c
new file mode 100644
index 000000000..1172970d1
--- /dev/null
+++ b/roms/u-boot/drivers/power/battery/bat_trats2.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Piotr Wilczek <p.wilczek@samsung.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/battery.h>
+#include <power/max77693_pmic.h>
+#include <errno.h>
+
+static struct battery battery_trats;
+
+static int power_battery_charge(struct pmic *bat)
+{
+ struct power_battery *p_bat = bat->pbat;
+
+ if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int power_battery_init_trats2(struct pmic *bat_,
+ struct pmic *fg_,
+ struct pmic *chrg_,
+ struct pmic *muic_)
+{
+ bat_->pbat->fg = fg_;
+ bat_->pbat->chrg = chrg_;
+ bat_->pbat->muic = muic_;
+
+ bat_->fg = fg_->fg;
+ bat_->chrg = chrg_->chrg;
+ bat_->chrg->chrg_type = muic_->chrg->chrg_type;
+ return 0;
+}
+
+static struct power_battery power_bat_trats2 = {
+ .bat = &battery_trats,
+ .battery_init = power_battery_init_trats2,
+ .battery_charge = power_battery_charge,
+};
+
+int power_bat_init(unsigned char bus)
+{
+ static const char name[] = "BAT_TRATS2";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board BAT init\n");
+
+ p->interface = PMIC_NONE;
+ p->name = name;
+ p->bus = bus;
+
+ p->pbat = &power_bat_trats2;
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/domain/Kconfig b/roms/u-boot/drivers/power/domain/Kconfig
new file mode 100644
index 000000000..a0fd98075
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/Kconfig
@@ -0,0 +1,75 @@
+menu "Power Domain Support"
+
+config POWER_DOMAIN
+ bool "Enable power domain support using Driver Model"
+ depends on DM && OF_CONTROL
+ help
+ Enable support for the power domain driver class. Many SoCs allow
+ power to be applied to or removed from portions of the SoC (power
+ domains). This may be used to save power. This API provides the
+ means to control such power management hardware.
+
+config BCM6328_POWER_DOMAIN
+ bool "Enable the BCM6328 power domain driver"
+ depends on POWER_DOMAIN && ARCH_BMIPS
+ help
+ Enable support for manipulating BCM6345 power domains via MMIO
+ mapped registers.
+
+config IMX8_POWER_DOMAIN
+ bool "Enable i.MX8 power domain driver"
+ depends on ARCH_IMX8
+ help
+ Enable support for manipulating NXP i.MX8 on-SoC power domains via IPC
+ requests to the SCU.
+
+config IMX8M_POWER_DOMAIN
+ bool "Enable i.MX8M power domain driver"
+ depends on POWER_DOMAIN && ARCH_IMX8M
+ help
+ Enable support for manipulating NXP i.MX8M on-SoC power domains via
+ requests to the ATF.
+
+config MTK_POWER_DOMAIN
+ bool "Enable the MediaTek power domain driver"
+ depends on POWER_DOMAIN && ARCH_MEDIATEK
+ help
+ Enable support for manipulating MediaTek power domains via MMIO
+ mapped registers.
+
+config MESON_GX_VPU_POWER_DOMAIN
+ bool "Enable Amlogic Meson GX VPU power domain driver"
+ depends on POWER_DOMAIN && ARCH_MESON
+ help
+ Enable support for manipulating Amlogic Meson GX Video Processing
+ Unit power domain.
+
+config MESON_EE_POWER_DOMAIN
+ bool "Enable Amlogic Everything-Else power domain driver"
+ depends on POWER_DOMAIN && ARCH_MESON
+ help
+ Enable support for manipulating Amlogic Meson Everything-Else power
+ domains.
+
+config SANDBOX_POWER_DOMAIN
+ bool "Enable the sandbox power domain test driver"
+ depends on POWER_DOMAIN && SANDBOX
+ help
+ Enable support for a test power domain driver implementation, which
+ simply accepts requests to power on/off various HW modules without
+ actually doing anything beyond a little error checking.
+
+config TEGRA186_POWER_DOMAIN
+ bool "Enable Tegra186 BPMP-based power domain driver"
+ depends on TEGRA186_BPMP
+ help
+ Enable support for manipulating Tegra's on-SoC power domains via IPC
+ requests to the BPMP (Boot and Power Management Processor).
+
+config TI_SCI_POWER_DOMAIN
+ bool "Enable the TI SCI-based power domain driver"
+ depends on POWER_DOMAIN && TI_SCI_PROTOCOL
+ help
+ Generic power domain implementation for TI devices implementing the
+ TI SCI protocol.
+endmenu
diff --git a/roms/u-boot/drivers/power/domain/Makefile b/roms/u-boot/drivers/power/domain/Makefile
new file mode 100644
index 000000000..45bf9f638
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/Makefile
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2016, NVIDIA CORPORATION.
+#
+
+obj-$(CONFIG_$(SPL_)POWER_DOMAIN) += power-domain-uclass.o
+obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
+obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o
+obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o
+obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o
+obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o
+obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o
+obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
+obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
+obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
+obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
diff --git a/roms/u-boot/drivers/power/domain/bcm6328-power-domain.c b/roms/u-boot/drivers/power/domain/bcm6328-power-domain.c
new file mode 100644
index 000000000..6e720e079
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/bcm6328-power-domain.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#define MAX_DOMAINS 32
+
+struct bcm6328_power_domain {
+ void __iomem *regs;
+};
+
+static int bcm6328_power_domain_request(struct power_domain *power_domain)
+{
+ if (power_domain->id >= MAX_DOMAINS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int bcm6328_power_domain_free(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int bcm6328_power_domain_on(struct power_domain *power_domain)
+{
+ struct bcm6328_power_domain *priv = dev_get_priv(power_domain->dev);
+
+ clrbits_be32(priv->regs, BIT(power_domain->id));
+
+ return 0;
+}
+
+static int bcm6328_power_domain_off(struct power_domain *power_domain)
+{
+ struct bcm6328_power_domain *priv = dev_get_priv(power_domain->dev);
+
+ setbits_be32(priv->regs, BIT(power_domain->id));
+
+ return 0;
+}
+
+static int bcm6328_power_domain_probe(struct udevice *dev)
+{
+ struct bcm6328_power_domain *priv = dev_get_priv(dev);
+
+ priv->regs = dev_remap_addr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct udevice_id bcm6328_power_domain_ids[] = {
+ { .compatible = "brcm,bcm6328-power-domain" },
+ { /* sentinel */ }
+};
+
+struct power_domain_ops bcm6328_power_domain_ops = {
+ .rfree = bcm6328_power_domain_free,
+ .off = bcm6328_power_domain_off,
+ .on = bcm6328_power_domain_on,
+ .request = bcm6328_power_domain_request,
+};
+
+U_BOOT_DRIVER(bcm6328_power_domain) = {
+ .name = "bcm6328_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = bcm6328_power_domain_ids,
+ .ops = &bcm6328_power_domain_ops,
+ .priv_auto = sizeof(struct bcm6328_power_domain),
+ .probe = bcm6328_power_domain_probe,
+};
diff --git a/roms/u-boot/drivers/power/domain/imx8-power-domain-legacy.c b/roms/u-boot/drivers/power/domain/imx8-power-domain-legacy.c
new file mode 100644
index 000000000..e2fae2dbc
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/imx8-power-domain-legacy.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2017 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/power-domain.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+#include <dm/uclass-internal.h>
+#include <asm/arch/sci/sci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct imx8_power_domain_priv {
+ bool state_on;
+};
+
+static bool check_device_power_off(struct udevice *dev,
+ const char *permanent_on_devices[],
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!strcmp(dev->name, permanent_on_devices[i]))
+ return false;
+ }
+
+ return true;
+}
+
+void imx8_power_off_pd_devices(const char *permanent_on_devices[], int size)
+{
+ struct udevice *dev;
+ struct power_domain pd;
+
+ for (uclass_find_first_device(UCLASS_POWER_DOMAIN, &dev); dev;
+ uclass_find_next_device(&dev)) {
+ if (!device_active(dev))
+ continue;
+ /*
+ * Power off active pd devices except the permanent
+ * power on devices
+ */
+ if (check_device_power_off(dev, permanent_on_devices, size)) {
+ pd.dev = dev;
+ power_domain_off(&pd);
+ }
+ }
+}
+
+int imx8_power_domain_lookup_name(const char *name,
+ struct power_domain *power_domain)
+{
+ struct udevice *dev;
+ struct power_domain_ops *ops;
+ int ret;
+
+ debug("%s(power_domain=%p name=%s)\n", __func__, power_domain, name);
+
+ ret = uclass_get_device_by_name(UCLASS_POWER_DOMAIN, name, &dev);
+ if (ret) {
+ printf("%s fail: %s, ret = %d\n", __func__, name, ret);
+ return ret;
+ }
+
+ ops = (struct power_domain_ops *)dev->driver->ops;
+ power_domain->dev = dev;
+ ret = ops->request(power_domain);
+ if (ret) {
+ debug("ops->request() failed: %d\n", ret);
+ return ret;
+ }
+
+ debug("%s ok: %s\n", __func__, dev->name);
+
+ return 0;
+}
+
+static int imx8_power_domain_request(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return 0;
+}
+
+static int imx8_power_domain_free(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return 0;
+}
+
+static int imx8_power_domain_on(struct power_domain *power_domain)
+{
+ struct udevice *dev = power_domain->dev;
+ struct imx8_power_domain_plat *pdata;
+ struct imx8_power_domain_priv *ppriv;
+ sc_err_t ret;
+ int err;
+
+ struct power_domain parent_domain;
+ struct udevice *parent = dev_get_parent(dev);
+
+ /* Need to power on parent node first */
+ if (device_get_uclass_id(parent) == UCLASS_POWER_DOMAIN) {
+ parent_domain.dev = parent;
+ err = imx8_power_domain_on(&parent_domain);
+ if (err)
+ return err;
+ }
+
+ pdata = (struct imx8_power_domain_plat *)dev_get_plat(dev);
+ ppriv = (struct imx8_power_domain_priv *)dev_get_priv(dev);
+
+ debug("%s(power_domain=%s) resource_id %d\n", __func__, dev->name,
+ pdata->resource_id);
+
+ /* Already powered on */
+ if (ppriv->state_on)
+ return 0;
+
+ if (pdata->resource_id != SC_R_NONE) {
+ if (!sc_rm_is_resource_owned(-1, pdata->resource_id))
+ printf("%s [%d] not owned by curr partition\n", dev->name, pdata->resource_id);
+
+ ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id,
+ SC_PM_PW_MODE_ON);
+ if (ret) {
+ printf("Error: %s Power up failed! (error = %d)\n",
+ dev->name, ret);
+ return -EIO;
+ }
+ }
+
+ ppriv->state_on = true;
+ debug("%s is powered on\n", dev->name);
+
+ return 0;
+}
+
+static int imx8_power_domain_off_node(struct power_domain *power_domain)
+{
+ struct udevice *dev = power_domain->dev;
+ struct udevice *child;
+ struct imx8_power_domain_priv *ppriv;
+ struct imx8_power_domain_priv *child_ppriv;
+ struct imx8_power_domain_plat *pdata;
+ sc_err_t ret;
+
+ ppriv = dev_get_priv(dev);
+ pdata = dev_get_plat(dev);
+
+ debug("%s, %s, state_on %d\n", __func__, dev->name, ppriv->state_on);
+
+ /* Already powered off */
+ if (!ppriv->state_on)
+ return 0;
+
+ /* Check if all subnodes are off */
+ for (device_find_first_child(dev, &child);
+ child;
+ device_find_next_child(&child)) {
+ if (device_active(child)) {
+ child_ppriv =
+ (struct imx8_power_domain_priv *)dev_get_priv(child);
+ if (child_ppriv->state_on)
+ return -EPERM;
+ }
+ }
+
+ if (pdata->resource_id != SC_R_NONE) {
+ ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id,
+ SC_PM_PW_MODE_OFF);
+ if (ret) {
+ if (!sc_rm_is_resource_owned(-1, pdata->resource_id)) {
+ printf("%s not owned by curr partition %d\n", dev->name, pdata->resource_id);
+ return 0;
+ }
+ printf("Error: %s Power off failed! (error = %d)\n",
+ dev->name, ret);
+ return -EIO;
+ }
+ }
+
+ ppriv->state_on = false;
+ debug("%s is powered off\n", dev->name);
+
+ return 0;
+}
+
+static int imx8_power_domain_off_parentnodes(struct power_domain *power_domain)
+{
+ struct udevice *dev = power_domain->dev;
+ struct udevice *parent = dev_get_parent(dev);
+ struct udevice *child;
+ struct imx8_power_domain_priv *ppriv;
+ struct imx8_power_domain_priv *child_ppriv;
+ struct imx8_power_domain_plat *pdata;
+ sc_err_t ret;
+ struct power_domain parent_pd;
+
+ if (device_get_uclass_id(parent) == UCLASS_POWER_DOMAIN) {
+ pdata =
+ (struct imx8_power_domain_plat *)dev_get_plat(parent);
+ ppriv = (struct imx8_power_domain_priv *)dev_get_priv(parent);
+
+ debug("%s, %s, state_on %d\n", __func__, parent->name,
+ ppriv->state_on);
+
+ /* Already powered off */
+ if (!ppriv->state_on)
+ return 0;
+
+ /*
+ * Check if all sibling nodes are off. If yes,
+ * power off parent
+ */
+ for (device_find_first_child(parent, &child); child;
+ device_find_next_child(&child)) {
+ if (device_active(child)) {
+ child_ppriv = (struct imx8_power_domain_priv *)
+ dev_get_priv(child);
+ /* Find a power on sibling */
+ if (child_ppriv->state_on) {
+ debug("sibling %s, state_on %d\n",
+ child->name,
+ child_ppriv->state_on);
+ return 0;
+ }
+ }
+ }
+
+ /* power off parent */
+ if (pdata->resource_id != SC_R_NONE) {
+ ret = sc_pm_set_resource_power_mode(-1,
+ pdata->resource_id,
+ SC_PM_PW_MODE_OFF);
+ if (ret) {
+ printf("%s Power off failed! (error = %d)\n",
+ parent->name, ret);
+ return -EIO;
+ }
+ }
+
+ ppriv->state_on = false;
+ debug("%s is powered off\n", parent->name);
+
+ parent_pd.dev = parent;
+ imx8_power_domain_off_parentnodes(&parent_pd);
+ }
+
+ return 0;
+}
+
+static int imx8_power_domain_off(struct power_domain *power_domain)
+{
+ int ret;
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ /* Turn off the node */
+ ret = imx8_power_domain_off_node(power_domain);
+ if (ret) {
+ debug("Can't power off the node of dev %s, ret = %d\n",
+ power_domain->dev->name, ret);
+ return ret;
+ }
+
+ /* Turn off parent nodes, if sibling nodes are all off */
+ ret = imx8_power_domain_off_parentnodes(power_domain);
+ if (ret) {
+ printf("Failed to power off parent nodes of dev %s, ret = %d\n",
+ power_domain->dev->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx8_power_domain_of_xlate(struct power_domain *power_domain,
+ struct ofnode_phandle_args *args)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ /* Do nothing to the xlate, since we don't have args used */
+
+ return 0;
+}
+
+static int imx8_power_domain_bind(struct udevice *dev)
+{
+ int offset;
+ const char *name;
+ int ret = 0;
+
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ offset = dev_of_offset(dev);
+ for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0;
+ offset = fdt_next_subnode(gd->fdt_blob, offset)) {
+ /* Bind the subnode to this driver */
+ name = fdt_get_name(gd->fdt_blob, offset, NULL);
+
+ ret = device_bind_with_driver_data(dev, dev->driver, name,
+ dev->driver_data,
+ offset_to_ofnode(offset),
+ NULL);
+
+ if (ret == -ENODEV)
+ printf("Driver '%s' refuses to bind\n",
+ dev->driver->name);
+
+ if (ret)
+ printf("Error binding driver '%s': %d\n",
+ dev->driver->name, ret);
+ }
+
+ return 0;
+}
+
+static int imx8_power_domain_probe(struct udevice *dev)
+{
+ struct imx8_power_domain_priv *ppriv;
+
+ debug("%s(dev=%s)\n", __func__, dev->name);
+
+ ppriv = (struct imx8_power_domain_priv *)dev_get_priv(dev);
+
+ /* Set default to power off */
+ if (ppriv)
+ ppriv->state_on = false;
+
+ return 0;
+}
+
+static int imx8_power_domain_of_to_plat(struct udevice *dev)
+{
+ int reg;
+ struct imx8_power_domain_plat *pdata = dev_get_plat(dev);
+
+ reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
+ if (reg == -1) {
+ debug("%s: Invalid resource id %d\n", __func__, reg);
+ return -EINVAL;
+ }
+ pdata->resource_id = (sc_rsrc_t)reg;
+
+ debug("%s resource_id %d\n", __func__, pdata->resource_id);
+
+ return 0;
+}
+
+static const struct udevice_id imx8_power_domain_ids[] = {
+ { .compatible = "nxp,imx8-pd" },
+ { }
+};
+
+struct power_domain_ops imx8_power_domain_ops = {
+ .request = imx8_power_domain_request,
+ .rfree = imx8_power_domain_free,
+ .on = imx8_power_domain_on,
+ .off = imx8_power_domain_off,
+ .of_xlate = imx8_power_domain_of_xlate,
+};
+
+U_BOOT_DRIVER(imx8_power_domain) = {
+ .name = "imx8_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = imx8_power_domain_ids,
+ .bind = imx8_power_domain_bind,
+ .probe = imx8_power_domain_probe,
+ .of_to_plat = imx8_power_domain_of_to_plat,
+ .plat_auto = sizeof(struct imx8_power_domain_plat),
+ .priv_auto = sizeof(struct imx8_power_domain_priv),
+ .ops = &imx8_power_domain_ops,
+ .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/roms/u-boot/drivers/power/domain/imx8-power-domain.c b/roms/u-boot/drivers/power/domain/imx8-power-domain.c
new file mode 100644
index 000000000..6461ab23d
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/imx8-power-domain.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#define DEBUG
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <asm/arch/power-domain.h>
+#include <asm/arch/sci/sci.h>
+
+static int imx8_power_domain_request(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return 0;
+}
+
+static int imx8_power_domain_free(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return 0;
+}
+
+static int imx8_power_domain_on(struct power_domain *power_domain)
+{
+ u32 resource_id = power_domain->id;
+ int ret;
+
+ debug("%s: resource_id %u\n", __func__, resource_id);
+
+ ret = sc_pm_set_resource_power_mode(-1, resource_id, SC_PM_PW_MODE_ON);
+ if (ret) {
+ printf("Error: %u Power up failed! (error = %d)\n",
+ resource_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx8_power_domain_off(struct power_domain *power_domain)
+{
+ u32 resource_id = power_domain->id;
+ int ret;
+
+ debug("%s: resource_id %u\n", __func__, resource_id);
+
+ ret = sc_pm_set_resource_power_mode(-1, resource_id, SC_PM_PW_MODE_OFF);
+ if (ret) {
+ printf("Error: %u Power off failed! (error = %d)\n",
+ resource_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx8_power_domain_probe(struct udevice *dev)
+{
+ debug("%s(dev=%s)\n", __func__, dev->name);
+
+ return 0;
+}
+
+static const struct udevice_id imx8_power_domain_ids[] = {
+ { .compatible = "fsl,imx8qxp-scu-pd" },
+ { .compatible = "fsl,scu-pd" },
+ { }
+};
+
+struct power_domain_ops imx8_power_domain_ops_v2 = {
+ .request = imx8_power_domain_request,
+ .rfree = imx8_power_domain_free,
+ .on = imx8_power_domain_on,
+ .off = imx8_power_domain_off,
+};
+
+U_BOOT_DRIVER(imx8_power_domain_v2) = {
+ .name = "imx8_power_domain_v2",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = imx8_power_domain_ids,
+ .probe = imx8_power_domain_probe,
+ .ops = &imx8_power_domain_ops_v2,
+};
diff --git a/roms/u-boot/drivers/power/domain/imx8m-power-domain.c b/roms/u-boot/drivers/power/domain/imx8m-power-domain.c
new file mode 100644
index 000000000..5d34bc129
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/imx8m-power-domain.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2017 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/power-domain.h>
+#include <asm/mach-imx/sys_proto.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+#include <imx_sip.h>
+#include <linux/arm-smccc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int imx8m_power_domain_request(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int imx8m_power_domain_free(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int imx8m_power_domain_on(struct power_domain *power_domain)
+{
+ struct udevice *dev = power_domain->dev;
+ struct imx8m_power_domain_plat *pdata;
+
+ pdata = dev_get_plat(dev);
+
+ if (pdata->resource_id < 0)
+ return -EINVAL;
+
+ if (pdata->has_pd)
+ power_domain_on(&pdata->pd);
+
+ arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN,
+ pdata->resource_id, 1, 0, 0, 0, 0, NULL);
+
+ return 0;
+}
+
+static int imx8m_power_domain_off(struct power_domain *power_domain)
+{
+ struct udevice *dev = power_domain->dev;
+ struct imx8m_power_domain_plat *pdata;
+ pdata = dev_get_plat(dev);
+
+ if (pdata->resource_id < 0)
+ return -EINVAL;
+
+ arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN,
+ pdata->resource_id, 0, 0, 0, 0, 0, NULL);
+
+ if (pdata->has_pd)
+ power_domain_off(&pdata->pd);
+
+ return 0;
+}
+
+static int imx8m_power_domain_of_xlate(struct power_domain *power_domain,
+ struct ofnode_phandle_args *args)
+{
+ return 0;
+}
+
+static int imx8m_power_domain_bind(struct udevice *dev)
+{
+ int offset;
+ const char *name;
+ int ret = 0;
+
+ offset = dev_of_offset(dev);
+ for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0;
+ offset = fdt_next_subnode(gd->fdt_blob, offset)) {
+ /* Bind the subnode to this driver */
+ name = fdt_get_name(gd->fdt_blob, offset, NULL);
+
+ ret = device_bind_with_driver_data(dev, dev->driver, name,
+ dev->driver_data,
+ offset_to_ofnode(offset),
+ NULL);
+
+ if (ret == -ENODEV)
+ printf("Driver '%s' refuses to bind\n",
+ dev->driver->name);
+
+ if (ret)
+ printf("Error binding driver '%s': %d\n",
+ dev->driver->name, ret);
+ }
+
+ return 0;
+}
+
+static int imx8m_power_domain_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static int imx8m_power_domain_of_to_plat(struct udevice *dev)
+{
+ struct imx8m_power_domain_plat *pdata = dev_get_plat(dev);
+
+ pdata->resource_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "reg", -1);
+
+ if (!power_domain_get(dev, &pdata->pd))
+ pdata->has_pd = 1;
+
+ return 0;
+}
+
+static const struct udevice_id imx8m_power_domain_ids[] = {
+ { .compatible = "fsl,imx8mq-gpc" },
+ { .compatible = "fsl,imx8mm-gpc" },
+ { .compatible = "fsl,imx8mn-gpc" },
+ { }
+};
+
+struct power_domain_ops imx8m_power_domain_ops = {
+ .request = imx8m_power_domain_request,
+ .rfree = imx8m_power_domain_free,
+ .on = imx8m_power_domain_on,
+ .off = imx8m_power_domain_off,
+ .of_xlate = imx8m_power_domain_of_xlate,
+};
+
+U_BOOT_DRIVER(imx8m_power_domain) = {
+ .name = "imx8m_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = imx8m_power_domain_ids,
+ .bind = imx8m_power_domain_bind,
+ .probe = imx8m_power_domain_probe,
+ .of_to_plat = imx8m_power_domain_of_to_plat,
+ .plat_auto = sizeof(struct imx8m_power_domain_plat),
+ .ops = &imx8m_power_domain_ops,
+};
diff --git a/roms/u-boot/drivers/power/domain/meson-ee-pwrc.c b/roms/u-boot/drivers/power/domain/meson-ee-pwrc.c
new file mode 100644
index 000000000..a4d50e701
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/meson-ee-pwrc.c
@@ -0,0 +1,483 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <reset.h>
+#include <clk.h>
+#include <dt-bindings/power/meson-axg-power.h>
+#include <dt-bindings/power/meson-g12a-power.h>
+#include <dt-bindings/power/meson-gxbb-power.h>
+#include <dt-bindings/power/meson-sm1-power.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+/* AO Offsets */
+
+#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
+#define AO_RTI_GEN_PWR_ISO0 (0x3b << 2)
+
+/* HHI Offsets */
+
+#define HHI_MEM_PD_REG0 (0x40 << 2)
+#define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
+#define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
+#define HHI_VPU_MEM_PD_REG3 (0x43 << 2)
+#define HHI_VPU_MEM_PD_REG4 (0x44 << 2)
+#define HHI_AUDIO_MEM_PD_REG0 (0x45 << 2)
+#define HHI_NANOQ_MEM_PD_REG0 (0x46 << 2)
+#define HHI_NANOQ_MEM_PD_REG1 (0x47 << 2)
+#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
+
+struct meson_ee_pwrc;
+struct meson_ee_pwrc_domain;
+
+struct meson_ee_pwrc_mem_domain {
+ unsigned int reg;
+ unsigned int mask;
+};
+
+struct meson_ee_pwrc_top_domain {
+ unsigned int sleep_reg;
+ unsigned int sleep_mask;
+ unsigned int iso_reg;
+ unsigned int iso_mask;
+};
+
+struct meson_ee_pwrc_domain_desc {
+ char *name;
+ unsigned int reset_names_count;
+ unsigned int clk_names_count;
+ struct meson_ee_pwrc_top_domain *top_pd;
+ unsigned int mem_pd_count;
+ struct meson_ee_pwrc_mem_domain *mem_pd;
+ bool (*get_power)(struct power_domain *power_domain);
+};
+
+struct meson_ee_pwrc_domain_data {
+ unsigned int count;
+ struct meson_ee_pwrc_domain_desc *domains;
+};
+
+/* TOP Power Domains */
+
+static struct meson_ee_pwrc_top_domain gx_pwrc_vpu = {
+ .sleep_reg = AO_RTI_GEN_PWR_SLEEP0,
+ .sleep_mask = BIT(8),
+ .iso_reg = AO_RTI_GEN_PWR_SLEEP0,
+ .iso_mask = BIT(9),
+};
+
+#define SM1_EE_PD(__bit) \
+ { \
+ .sleep_reg = AO_RTI_GEN_PWR_SLEEP0, \
+ .sleep_mask = BIT(__bit), \
+ .iso_reg = AO_RTI_GEN_PWR_ISO0, \
+ .iso_mask = BIT(__bit), \
+ }
+
+static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8);
+static struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16);
+static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);
+static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);
+static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
+
+/* Memory PD Domains */
+
+#define VPU_MEMPD(__reg) \
+ { __reg, GENMASK(1, 0) }, \
+ { __reg, GENMASK(3, 2) }, \
+ { __reg, GENMASK(5, 4) }, \
+ { __reg, GENMASK(7, 6) }, \
+ { __reg, GENMASK(9, 8) }, \
+ { __reg, GENMASK(11, 10) }, \
+ { __reg, GENMASK(13, 12) }, \
+ { __reg, GENMASK(15, 14) }, \
+ { __reg, GENMASK(17, 16) }, \
+ { __reg, GENMASK(19, 18) }, \
+ { __reg, GENMASK(21, 20) }, \
+ { __reg, GENMASK(23, 22) }, \
+ { __reg, GENMASK(25, 24) }, \
+ { __reg, GENMASK(27, 26) }, \
+ { __reg, GENMASK(29, 28) }, \
+ { __reg, GENMASK(31, 30) }
+
+#define VPU_HHI_MEMPD(__reg) \
+ { __reg, BIT(8) }, \
+ { __reg, BIT(9) }, \
+ { __reg, BIT(10) }, \
+ { __reg, BIT(11) }, \
+ { __reg, BIT(12) }, \
+ { __reg, BIT(13) }, \
+ { __reg, BIT(14) }, \
+ { __reg, BIT(15) }
+
+static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
+ VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
+};
+
+static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
+ VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
+};
+
+static struct meson_ee_pwrc_mem_domain gxbb_pwrc_mem_vpu[] = {
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
+ VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
+};
+
+static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_eth[] = {
+ { HHI_MEM_PD_REG0, GENMASK(3, 2) },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG3),
+ { HHI_VPU_MEM_PD_REG4, GENMASK(1, 0) },
+ { HHI_VPU_MEM_PD_REG4, GENMASK(3, 2) },
+ { HHI_VPU_MEM_PD_REG4, GENMASK(5, 4) },
+ { HHI_VPU_MEM_PD_REG4, GENMASK(7, 6) },
+ VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = {
+ { HHI_NANOQ_MEM_PD_REG0, 0xff },
+ { HHI_NANOQ_MEM_PD_REG1, 0xff },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = {
+ { HHI_MEM_PD_REG0, GENMASK(31, 30) },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = {
+ { HHI_MEM_PD_REG0, GENMASK(29, 26) },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
+ { HHI_MEM_PD_REG0, GENMASK(25, 18) },
+};
+
+static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {
+ { HHI_MEM_PD_REG0, GENMASK(5, 4) },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
+ { HHI_MEM_PD_REG0, GENMASK(5, 4) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(3, 2) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(5, 4) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(7, 6) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(13, 12) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(15, 14) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(17, 16) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(19, 18) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(21, 20) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(23, 22) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(25, 24) },
+ { HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },
+};
+
+#define VPU_PD(__name, __top_pd, __mem, __get_power, __resets, __clks) \
+ { \
+ .name = __name, \
+ .reset_names_count = __resets, \
+ .clk_names_count = __clks, \
+ .top_pd = __top_pd, \
+ .mem_pd_count = ARRAY_SIZE(__mem), \
+ .mem_pd = __mem, \
+ .get_power = __get_power, \
+ }
+
+#define TOP_PD(__name, __top_pd, __mem, __get_power) \
+ { \
+ .name = __name, \
+ .top_pd = __top_pd, \
+ .mem_pd_count = ARRAY_SIZE(__mem), \
+ .mem_pd = __mem, \
+ .get_power = __get_power, \
+ }
+
+#define MEM_PD(__name, __mem) \
+ TOP_PD(__name, NULL, __mem, NULL)
+
+static bool pwrc_ee_get_power(struct power_domain *power_domain);
+
+static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
+ [PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
+ pwrc_ee_get_power, 11, 2),
+ [PWRC_G12A_ETH_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth),
+};
+
+static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
+ [PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,
+ pwrc_ee_get_power, 5, 2),
+ [PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth),
+ [PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),
+};
+
+static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {
+ [PWRC_GXBB_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, gxbb_pwrc_mem_vpu,
+ pwrc_ee_get_power, 12, 2),
+ [PWRC_GXBB_ETHERNET_MEM_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth),
+};
+
+static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {
+ [PWRC_SM1_VPU_ID] = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu,
+ pwrc_ee_get_power, 11, 2),
+ [PWRC_SM1_NNA_ID] = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna,
+ pwrc_ee_get_power),
+ [PWRC_SM1_USB_ID] = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb,
+ pwrc_ee_get_power),
+ [PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie,
+ pwrc_ee_get_power),
+ [PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d,
+ pwrc_ee_get_power),
+ [PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio),
+ [PWRC_SM1_ETH_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth),
+};
+
+struct meson_ee_pwrc_priv {
+ struct regmap *regmap_ao;
+ struct regmap *regmap_hhi;
+ struct reset_ctl_bulk resets;
+ struct clk_bulk clks;
+ const struct meson_ee_pwrc_domain_data *data;
+};
+
+static bool pwrc_ee_get_power(struct power_domain *power_domain)
+{
+ struct meson_ee_pwrc_priv *priv = dev_get_priv(power_domain->dev);
+ struct meson_ee_pwrc_domain_desc *pwrc_domain;
+ u32 reg;
+
+ pwrc_domain = &priv->data->domains[power_domain->id];
+
+ regmap_read(priv->regmap_ao,
+ pwrc_domain->top_pd->sleep_reg, &reg);
+
+ return (reg & pwrc_domain->top_pd->sleep_mask);
+}
+
+static int meson_ee_pwrc_request(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int meson_ee_pwrc_free(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int meson_ee_pwrc_off(struct power_domain *power_domain)
+{
+ struct meson_ee_pwrc_priv *priv = dev_get_priv(power_domain->dev);
+ struct meson_ee_pwrc_domain_desc *pwrc_domain;
+ int i;
+
+ pwrc_domain = &priv->data->domains[power_domain->id];
+
+ if (pwrc_domain->top_pd)
+ regmap_update_bits(priv->regmap_ao,
+ pwrc_domain->top_pd->sleep_reg,
+ pwrc_domain->top_pd->sleep_mask,
+ pwrc_domain->top_pd->sleep_mask);
+ udelay(20);
+
+ for (i = 0 ; i < pwrc_domain->mem_pd_count ; ++i)
+ regmap_update_bits(priv->regmap_hhi,
+ pwrc_domain->mem_pd[i].reg,
+ pwrc_domain->mem_pd[i].mask,
+ pwrc_domain->mem_pd[i].mask);
+
+ udelay(20);
+
+ if (pwrc_domain->top_pd)
+ regmap_update_bits(priv->regmap_ao,
+ pwrc_domain->top_pd->iso_reg,
+ pwrc_domain->top_pd->iso_mask,
+ pwrc_domain->top_pd->iso_mask);
+
+ if (pwrc_domain->clk_names_count) {
+ mdelay(20);
+ clk_disable_bulk(&priv->clks);
+ }
+
+ return 0;
+}
+
+static int meson_ee_pwrc_on(struct power_domain *power_domain)
+{
+ struct meson_ee_pwrc_priv *priv = dev_get_priv(power_domain->dev);
+ struct meson_ee_pwrc_domain_desc *pwrc_domain;
+ int i, ret;
+
+ pwrc_domain = &priv->data->domains[power_domain->id];
+
+ if (pwrc_domain->top_pd)
+ regmap_update_bits(priv->regmap_ao,
+ pwrc_domain->top_pd->sleep_reg,
+ pwrc_domain->top_pd->sleep_mask, 0);
+ udelay(20);
+
+ for (i = 0 ; i < pwrc_domain->mem_pd_count ; ++i)
+ regmap_update_bits(priv->regmap_hhi,
+ pwrc_domain->mem_pd[i].reg,
+ pwrc_domain->mem_pd[i].mask, 0);
+
+ udelay(20);
+
+ if (pwrc_domain->reset_names_count) {
+ ret = reset_assert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+ }
+
+ if (pwrc_domain->top_pd)
+ regmap_update_bits(priv->regmap_ao,
+ pwrc_domain->top_pd->iso_reg,
+ pwrc_domain->top_pd->iso_mask, 0);
+
+ if (pwrc_domain->reset_names_count) {
+ ret = reset_deassert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+ }
+
+ if (pwrc_domain->clk_names_count)
+ return clk_enable_bulk(&priv->clks);
+
+ return 0;
+}
+
+static int meson_ee_pwrc_of_xlate(struct power_domain *power_domain,
+ struct ofnode_phandle_args *args)
+{
+ struct meson_ee_pwrc_priv *priv = dev_get_priv(power_domain->dev);
+
+ /* #power-domain-cells is 1 */
+
+ if (args->args_count < 1) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ power_domain->id = args->args[0];
+
+ if (power_domain->id >= priv->data->count) {
+ debug("Invalid domain ID: %lu\n", power_domain->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct power_domain_ops meson_ee_pwrc_ops = {
+ .rfree = meson_ee_pwrc_free,
+ .off = meson_ee_pwrc_off,
+ .on = meson_ee_pwrc_on,
+ .request = meson_ee_pwrc_request,
+ .of_xlate = meson_ee_pwrc_of_xlate,
+};
+
+static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
+ .count = ARRAY_SIZE(g12a_pwrc_domains),
+ .domains = g12a_pwrc_domains,
+};
+
+static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {
+ .count = ARRAY_SIZE(axg_pwrc_domains),
+ .domains = axg_pwrc_domains,
+};
+
+static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {
+ .count = ARRAY_SIZE(gxbb_pwrc_domains),
+ .domains = gxbb_pwrc_domains,
+};
+
+static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = {
+ .count = ARRAY_SIZE(sm1_pwrc_domains),
+ .domains = sm1_pwrc_domains,
+};
+
+static const struct udevice_id meson_ee_pwrc_ids[] = {
+ {
+ .compatible = "amlogic,meson-g12a-pwrc",
+ .data = (unsigned long)&meson_ee_g12a_pwrc_data,
+ },
+ {
+ .compatible = "amlogic,meson-gxbb-pwrc",
+ .data = (unsigned long)&meson_ee_gxbb_pwrc_data,
+ },
+ {
+ .compatible = "amlogic,meson-axg-pwrc",
+ .data = (unsigned long)&meson_ee_axg_pwrc_data,
+ },
+ {
+ .compatible = "amlogic,meson-sm1-pwrc",
+ .data = (unsigned long)&meson_ee_sm1_pwrc_data,
+ },
+ { }
+};
+
+static int meson_ee_pwrc_probe(struct udevice *dev)
+{
+ struct meson_ee_pwrc_priv *priv = dev_get_priv(dev);
+ u32 ao_phandle;
+ ofnode ao_node;
+ int ret;
+
+ priv->data = (void *)dev_get_driver_data(dev);
+ if (!priv->data)
+ return -EINVAL;
+
+ priv->regmap_hhi = syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
+ if (IS_ERR(priv->regmap_hhi))
+ return PTR_ERR(priv->regmap_hhi);
+
+ ret = ofnode_read_u32(dev_ofnode(dev), "amlogic,ao-sysctrl",
+ &ao_phandle);
+ if (ret)
+ return ret;
+
+ ao_node = ofnode_get_by_phandle(ao_phandle);
+ if (!ofnode_valid(ao_node))
+ return -EINVAL;
+
+ priv->regmap_ao = syscon_node_to_regmap(ao_node);
+ if (IS_ERR(priv->regmap_ao))
+ return PTR_ERR(priv->regmap_ao);
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret)
+ return ret;
+
+ ret = clk_get_bulk(dev, &priv->clks);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(meson_ee_pwrc) = {
+ .name = "meson_ee_pwrc",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = meson_ee_pwrc_ids,
+ .probe = meson_ee_pwrc_probe,
+ .ops = &meson_ee_pwrc_ops,
+ .priv_auto = sizeof(struct meson_ee_pwrc_priv),
+};
diff --git a/roms/u-boot/drivers/power/domain/meson-gx-pwrc-vpu.c b/roms/u-boot/drivers/power/domain/meson-gx-pwrc-vpu.c
new file mode 100644
index 000000000..eb94af2cf
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/meson-gx-pwrc-vpu.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Amlogic Meson VPU Power Domain Controller driver
+ *
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <reset.h>
+#include <clk.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+enum {
+ VPU_PWRC_COMPATIBLE_GX = 0,
+ VPU_PWRC_COMPATIBLE_G12A = 1,
+};
+
+/* AO Offsets */
+
+#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
+
+#define GEN_PWR_VPU_HDMI BIT(8)
+#define GEN_PWR_VPU_HDMI_ISO BIT(9)
+
+/* HHI Offsets */
+
+#define HHI_MEM_PD_REG0 (0x40 << 2)
+#define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
+#define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
+#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
+
+struct meson_gx_pwrc_vpu_priv {
+ struct regmap *regmap_ao;
+ struct regmap *regmap_hhi;
+ struct reset_ctl_bulk resets;
+ struct clk_bulk clks;
+};
+
+static int meson_pwrc_vpu_request(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int meson_pwrc_vpu_free(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain)
+{
+ struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
+ int i, ret;
+
+ regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VPU_HDMI, 0);
+ udelay(20);
+
+ /* Power Up Memories */
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+ 0x3 << i, 0);
+ udelay(5);
+ }
+
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+ 0x3 << i, 0);
+ udelay(5);
+ }
+
+ for (i = 8; i < 16; i++) {
+ regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
+ BIT(i), 0);
+ udelay(5);
+ }
+ udelay(20);
+
+ ret = reset_assert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VPU_HDMI_ISO, 0);
+
+ ret = reset_deassert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+
+ ret = clk_enable_bulk(&priv->clks);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int meson_g12a_pwrc_vpu_on(struct power_domain *power_domain)
+{
+ struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
+ int i, ret;
+
+ regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VPU_HDMI, 0);
+ udelay(20);
+
+ /* Power Up Memories */
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+ 0x3 << i, 0);
+ udelay(5);
+ }
+
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+ 0x3 << i, 0);
+ udelay(5);
+ }
+
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
+ 0x3 << i, 0);
+ udelay(5);
+ }
+
+ for (i = 8; i < 16; i++) {
+ regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
+ BIT(i), 0);
+ udelay(5);
+ }
+ udelay(20);
+
+ ret = reset_assert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VPU_HDMI_ISO, 0);
+
+ ret = reset_deassert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+
+ ret = clk_enable_bulk(&priv->clks);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int meson_pwrc_vpu_on(struct power_domain *power_domain)
+{
+ unsigned int compat = dev_get_driver_data(power_domain->dev);
+
+ switch (compat) {
+ case VPU_PWRC_COMPATIBLE_GX:
+ return meson_gx_pwrc_vpu_on(power_domain);
+ case VPU_PWRC_COMPATIBLE_G12A:
+ return meson_g12a_pwrc_vpu_on(power_domain);
+ }
+
+ return -EINVAL;
+}
+
+static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain)
+{
+ struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
+ int i;
+
+ regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
+ udelay(20);
+
+ /* Power Down Memories */
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+ 0x3 << i, 0x3 << i);
+ udelay(5);
+ }
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+ 0x3 << i, 0x3 << i);
+ udelay(5);
+ }
+ for (i = 8; i < 16; i++) {
+ regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
+ BIT(i), BIT(i));
+ udelay(5);
+ }
+ udelay(20);
+
+ regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
+ mdelay(20);
+
+ clk_disable_bulk(&priv->clks);
+
+ return 0;
+}
+
+static int meson_g12a_pwrc_vpu_off(struct power_domain *power_domain)
+{
+ struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
+ int i;
+
+ regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
+ udelay(20);
+
+ /* Power Down Memories */
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+ 0x3 << i, 0x3 << i);
+ udelay(5);
+ }
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+ 0x3 << i, 0x3 << i);
+ udelay(5);
+ }
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
+ 0x3 << i, 0x3 << i);
+ udelay(5);
+ }
+ for (i = 8; i < 16; i++) {
+ regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
+ BIT(i), BIT(i));
+ udelay(5);
+ }
+ udelay(20);
+
+ regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
+ mdelay(20);
+
+ clk_disable_bulk(&priv->clks);
+
+ return 0;
+}
+
+static int meson_pwrc_vpu_off(struct power_domain *power_domain)
+{
+ unsigned int compat = dev_get_driver_data(power_domain->dev);
+
+ switch (compat) {
+ case VPU_PWRC_COMPATIBLE_GX:
+ return meson_gx_pwrc_vpu_off(power_domain);
+ case VPU_PWRC_COMPATIBLE_G12A:
+ return meson_g12a_pwrc_vpu_off(power_domain);
+ }
+
+ return -EINVAL;
+}
+
+static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain,
+ struct ofnode_phandle_args *args)
+{
+ /* #power-domain-cells is 0 */
+
+ if (args->args_count != 0) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct power_domain_ops meson_gx_pwrc_vpu_ops = {
+ .rfree = meson_pwrc_vpu_free,
+ .off = meson_pwrc_vpu_off,
+ .on = meson_pwrc_vpu_on,
+ .request = meson_pwrc_vpu_request,
+ .of_xlate = meson_pwrc_vpu_of_xlate,
+};
+
+static const struct udevice_id meson_gx_pwrc_vpu_ids[] = {
+ {
+ .compatible = "amlogic,meson-gx-pwrc-vpu",
+ .data = VPU_PWRC_COMPATIBLE_GX,
+ },
+ {
+ .compatible = "amlogic,meson-g12a-pwrc-vpu",
+ .data = VPU_PWRC_COMPATIBLE_G12A,
+ },
+ { }
+};
+
+static int meson_gx_pwrc_vpu_probe(struct udevice *dev)
+{
+ struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev);
+ u32 hhi_phandle;
+ ofnode hhi_node;
+ int ret;
+
+ priv->regmap_ao = syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
+ if (IS_ERR(priv->regmap_ao))
+ return PTR_ERR(priv->regmap_ao);
+
+ ret = ofnode_read_u32(dev_ofnode(dev), "amlogic,hhi-sysctrl",
+ &hhi_phandle);
+ if (ret)
+ return ret;
+
+ hhi_node = ofnode_get_by_phandle(hhi_phandle);
+ if (!ofnode_valid(hhi_node))
+ return -EINVAL;
+
+ priv->regmap_hhi = syscon_node_to_regmap(hhi_node);
+ if (IS_ERR(priv->regmap_hhi))
+ return PTR_ERR(priv->regmap_hhi);
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret)
+ return ret;
+
+ ret = clk_get_bulk(dev, &priv->clks);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(meson_gx_pwrc_vpu) = {
+ .name = "meson_gx_pwrc_vpu",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = meson_gx_pwrc_vpu_ids,
+ .probe = meson_gx_pwrc_vpu_probe,
+ .ops = &meson_gx_pwrc_vpu_ops,
+ .priv_auto = sizeof(struct meson_gx_pwrc_vpu_priv),
+};
diff --git a/roms/u-boot/drivers/power/domain/mtk-power-domain.c b/roms/u-boot/drivers/power/domain/mtk-power-domain.c
new file mode 100644
index 000000000..ca2ded00e
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/mtk-power-domain.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+
+#include <dt-bindings/power/mt7623-power.h>
+#include <dt-bindings/power/mt7629-power.h>
+
+#define SPM_EN (0xb16 << 16 | 0x1)
+#define SPM_VDE_PWR_CON 0x0210
+#define SPM_MFG_PWR_CON 0x0214
+#define SPM_ISP_PWR_CON 0x0238
+#define SPM_DIS_PWR_CON 0x023c
+#define SPM_CONN_PWR_CON 0x0280
+#define SPM_BDP_PWR_CON 0x029c
+#define SPM_ETH_PWR_CON 0x02a0
+#define SPM_HIF_PWR_CON 0x02a4
+#define SPM_IFR_MSC_PWR_CON 0x02a8
+#define SPM_ETHSYS_PWR_CON 0x2e0
+#define SPM_HIF0_PWR_CON 0x2e4
+#define SPM_HIF1_PWR_CON 0x2e8
+#define SPM_PWR_STATUS 0x60c
+#define SPM_PWR_STATUS_2ND 0x610
+
+#define PWR_RST_B_BIT BIT(0)
+#define PWR_ISO_BIT BIT(1)
+#define PWR_ON_BIT BIT(2)
+#define PWR_ON_2ND_BIT BIT(3)
+#define PWR_CLK_DIS_BIT BIT(4)
+
+#define PWR_STATUS_CONN BIT(1)
+#define PWR_STATUS_DISP BIT(3)
+#define PWR_STATUS_MFG BIT(4)
+#define PWR_STATUS_ISP BIT(5)
+#define PWR_STATUS_VDEC BIT(7)
+#define PWR_STATUS_BDP BIT(14)
+#define PWR_STATUS_ETH BIT(15)
+#define PWR_STATUS_HIF BIT(16)
+#define PWR_STATUS_IFR_MSC BIT(17)
+#define PWR_STATUS_ETHSYS BIT(24)
+#define PWR_STATUS_HIF0 BIT(25)
+#define PWR_STATUS_HIF1 BIT(26)
+
+/* Infrasys configuration */
+#define INFRA_TOPDCM_CTRL 0x10
+#define INFRA_TOPAXI_PROT_EN 0x220
+#define INFRA_TOPAXI_PROT_STA1 0x228
+
+#define DCM_TOP_EN BIT(0)
+
+enum scp_domain_type {
+ SCPSYS_MT7622,
+ SCPSYS_MT7623,
+ SCPSYS_MT7629,
+};
+
+struct scp_domain;
+
+struct scp_domain_data {
+ struct scp_domain *scpd;
+ u32 sta_mask;
+ int ctl_offs;
+ u32 sram_pdn_bits;
+ u32 sram_pdn_ack_bits;
+ u32 bus_prot_mask;
+};
+
+struct scp_domain {
+ void __iomem *base;
+ void __iomem *infracfg;
+ enum scp_domain_type type;
+ struct scp_domain_data *data;
+};
+
+static struct scp_domain_data scp_domain_mt7623[] = {
+ [MT7623_POWER_DOMAIN_CONN] = {
+ .sta_mask = PWR_STATUS_CONN,
+ .ctl_offs = SPM_CONN_PWR_CON,
+ .bus_prot_mask = BIT(8) | BIT(2),
+ },
+ [MT7623_POWER_DOMAIN_DISP] = {
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = SPM_DIS_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .bus_prot_mask = BIT(2),
+ },
+ [MT7623_POWER_DOMAIN_MFG] = {
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = SPM_MFG_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT7623_POWER_DOMAIN_VDEC] = {
+ .sta_mask = PWR_STATUS_VDEC,
+ .ctl_offs = SPM_VDE_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT7623_POWER_DOMAIN_ISP] = {
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = SPM_ISP_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ },
+ [MT7623_POWER_DOMAIN_BDP] = {
+ .sta_mask = PWR_STATUS_BDP,
+ .ctl_offs = SPM_BDP_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ },
+ [MT7623_POWER_DOMAIN_ETH] = {
+ .sta_mask = PWR_STATUS_ETH,
+ .ctl_offs = SPM_ETH_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT7623_POWER_DOMAIN_HIF] = {
+ .sta_mask = PWR_STATUS_HIF,
+ .ctl_offs = SPM_HIF_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT7623_POWER_DOMAIN_IFR_MSC] = {
+ .sta_mask = PWR_STATUS_IFR_MSC,
+ .ctl_offs = SPM_IFR_MSC_PWR_CON,
+ },
+};
+
+static struct scp_domain_data scp_domain_mt7629[] = {
+ [MT7629_POWER_DOMAIN_ETHSYS] = {
+ .sta_mask = PWR_STATUS_ETHSYS,
+ .ctl_offs = SPM_ETHSYS_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .bus_prot_mask = (BIT(3) | BIT(17)),
+ },
+ [MT7629_POWER_DOMAIN_HIF0] = {
+ .sta_mask = PWR_STATUS_HIF0,
+ .ctl_offs = SPM_HIF0_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .bus_prot_mask = GENMASK(25, 24),
+ },
+ [MT7629_POWER_DOMAIN_HIF1] = {
+ .sta_mask = PWR_STATUS_HIF1,
+ .ctl_offs = SPM_HIF1_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .bus_prot_mask = GENMASK(28, 26),
+ },
+};
+
+/**
+ * This function enables the bus protection bits for disabled power
+ * domains so that the system does not hang when some unit accesses the
+ * bus while in power down.
+ */
+static int mtk_infracfg_set_bus_protection(void __iomem *infracfg,
+ u32 mask)
+{
+ u32 val;
+
+ clrsetbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask, mask);
+
+ return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val,
+ (val & mask) == mask, 100);
+}
+
+static int mtk_infracfg_clear_bus_protection(void __iomem *infracfg,
+ u32 mask)
+{
+ u32 val;
+
+ clrbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask);
+
+ return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val,
+ !(val & mask), 100);
+}
+
+static int scpsys_domain_is_on(struct scp_domain_data *data)
+{
+ struct scp_domain *scpd = data->scpd;
+ u32 sta = readl(scpd->base + SPM_PWR_STATUS) &
+ data->sta_mask;
+ u32 sta2 = readl(scpd->base + SPM_PWR_STATUS_2ND) &
+ data->sta_mask;
+
+ /*
+ * A domain is on when both status bits are set. If only one is set
+ * return an error. This happens while powering up a domain
+ */
+ if (sta && sta2)
+ return true;
+ if (!sta && !sta2)
+ return false;
+
+ return -EINVAL;
+}
+
+static int scpsys_power_on(struct power_domain *power_domain)
+{
+ struct scp_domain *scpd = dev_get_priv(power_domain->dev);
+ struct scp_domain_data *data = &scpd->data[power_domain->id];
+ void __iomem *ctl_addr = scpd->base + data->ctl_offs;
+ u32 pdn_ack = data->sram_pdn_ack_bits;
+ u32 val;
+ int ret, tmp;
+
+ writel(SPM_EN, scpd->base);
+
+ val = readl(ctl_addr);
+ val |= PWR_ON_BIT;
+ writel(val, ctl_addr);
+
+ val |= PWR_ON_2ND_BIT;
+ writel(val, ctl_addr);
+
+ ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, tmp > 0,
+ 100);
+ if (ret < 0)
+ return ret;
+
+ val &= ~PWR_CLK_DIS_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~PWR_ISO_BIT;
+ writel(val, ctl_addr);
+
+ val |= PWR_RST_B_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~data->sram_pdn_bits;
+ writel(val, ctl_addr);
+
+ ret = readl_poll_timeout(ctl_addr, tmp, !(tmp & pdn_ack), 100);
+ if (ret < 0)
+ return ret;
+
+ if (data->bus_prot_mask) {
+ ret = mtk_infracfg_clear_bus_protection(scpd->infracfg,
+ data->bus_prot_mask);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int scpsys_power_off(struct power_domain *power_domain)
+{
+ struct scp_domain *scpd = dev_get_priv(power_domain->dev);
+ struct scp_domain_data *data = &scpd->data[power_domain->id];
+ void __iomem *ctl_addr = scpd->base + data->ctl_offs;
+ u32 pdn_ack = data->sram_pdn_ack_bits;
+ u32 val;
+ int ret, tmp;
+
+ if (data->bus_prot_mask) {
+ ret = mtk_infracfg_set_bus_protection(scpd->infracfg,
+ data->bus_prot_mask);
+ if (ret)
+ return ret;
+ }
+
+ val = readl(ctl_addr);
+ val |= data->sram_pdn_bits;
+ writel(val, ctl_addr);
+
+ ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack,
+ 100);
+ if (ret < 0)
+ return ret;
+
+ val |= PWR_ISO_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~PWR_RST_B_BIT;
+ writel(val, ctl_addr);
+
+ val |= PWR_CLK_DIS_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~PWR_ON_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~PWR_ON_2ND_BIT;
+ writel(val, ctl_addr);
+
+ ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, !tmp, 100);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int scpsys_power_request(struct power_domain *power_domain)
+{
+ struct scp_domain *scpd = dev_get_priv(power_domain->dev);
+ struct scp_domain_data *data;
+
+ data = &scpd->data[power_domain->id];
+ data->scpd = scpd;
+
+ return 0;
+}
+
+static int scpsys_power_free(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int mtk_power_domain_hook(struct udevice *dev)
+{
+ struct scp_domain *scpd = dev_get_priv(dev);
+
+ scpd->type = (enum scp_domain_type)dev_get_driver_data(dev);
+
+ switch (scpd->type) {
+ case SCPSYS_MT7623:
+ scpd->data = scp_domain_mt7623;
+ break;
+ case SCPSYS_MT7622:
+ case SCPSYS_MT7629:
+ scpd->data = scp_domain_mt7629;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_power_domain_probe(struct udevice *dev)
+{
+ struct ofnode_phandle_args args;
+ struct scp_domain *scpd = dev_get_priv(dev);
+ struct regmap *regmap;
+ struct clk_bulk bulk;
+ int err;
+
+ scpd->base = dev_read_addr_ptr(dev);
+ if (!scpd->base)
+ return -ENOENT;
+
+ err = mtk_power_domain_hook(dev);
+ if (err)
+ return err;
+
+ /* get corresponding syscon phandle */
+ err = dev_read_phandle_with_args(dev, "infracfg", NULL, 0, 0, &args);
+ if (err)
+ return err;
+
+ regmap = syscon_node_to_regmap(args.node);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ scpd->infracfg = regmap_get_range(regmap, 0);
+ if (!scpd->infracfg)
+ return -ENOENT;
+
+ /* enable Infra DCM */
+ setbits_le32(scpd->infracfg + INFRA_TOPDCM_CTRL, DCM_TOP_EN);
+
+ err = clk_get_bulk(dev, &bulk);
+ if (err)
+ return err;
+
+ return clk_enable_bulk(&bulk);
+}
+
+static const struct udevice_id mtk_power_domain_ids[] = {
+ {
+ .compatible = "mediatek,mt7622-scpsys",
+ .data = SCPSYS_MT7622,
+ },
+ {
+ .compatible = "mediatek,mt7623-scpsys",
+ .data = SCPSYS_MT7623,
+ },
+ {
+ .compatible = "mediatek,mt7629-scpsys",
+ .data = SCPSYS_MT7629,
+ },
+ { /* sentinel */ }
+};
+
+struct power_domain_ops mtk_power_domain_ops = {
+ .rfree = scpsys_power_free,
+ .off = scpsys_power_off,
+ .on = scpsys_power_on,
+ .request = scpsys_power_request,
+};
+
+U_BOOT_DRIVER(mtk_power_domain) = {
+ .name = "mtk_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .ops = &mtk_power_domain_ops,
+ .probe = mtk_power_domain_probe,
+ .of_match = mtk_power_domain_ids,
+ .priv_auto = sizeof(struct scp_domain),
+};
diff --git a/roms/u-boot/drivers/power/domain/power-domain-uclass.c b/roms/u-boot/drivers/power/domain/power-domain-uclass.c
new file mode 100644
index 000000000..af829db9d
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/power-domain-uclass.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain.h>
+#include <power-domain-uclass.h>
+#include <dm/device-internal.h>
+
+static inline struct power_domain_ops *power_domain_dev_ops(struct udevice *dev)
+{
+ return (struct power_domain_ops *)dev->driver->ops;
+}
+
+static int power_domain_of_xlate_default(struct power_domain *power_domain,
+ struct ofnode_phandle_args *args)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ if (args->args_count != 1) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ power_domain->id = args->args[0];
+
+ return 0;
+}
+
+int power_domain_get_by_index(struct udevice *dev,
+ struct power_domain *power_domain, int index)
+{
+ struct ofnode_phandle_args args;
+ int ret;
+ struct udevice *dev_power_domain;
+ struct power_domain_ops *ops;
+
+ debug("%s(dev=%p, power_domain=%p)\n", __func__, dev, power_domain);
+
+ ret = dev_read_phandle_with_args(dev, "power-domains",
+ "#power-domain-cells", 0, index,
+ &args);
+ if (ret) {
+ debug("%s: dev_read_phandle_with_args failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_ofnode(UCLASS_POWER_DOMAIN, args.node,
+ &dev_power_domain);
+ if (ret) {
+ debug("%s: uclass_get_device_by_ofnode failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ops = power_domain_dev_ops(dev_power_domain);
+
+ power_domain->dev = dev_power_domain;
+ if (ops->of_xlate)
+ ret = ops->of_xlate(power_domain, &args);
+ else
+ ret = power_domain_of_xlate_default(power_domain, &args);
+ if (ret) {
+ debug("of_xlate() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = ops->request(power_domain);
+ if (ret) {
+ debug("ops->request() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int power_domain_get(struct udevice *dev, struct power_domain *power_domain)
+{
+ return power_domain_get_by_index(dev, power_domain, 0);
+}
+
+int power_domain_free(struct power_domain *power_domain)
+{
+ struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return ops->rfree(power_domain);
+}
+
+int power_domain_on(struct power_domain *power_domain)
+{
+ struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return ops->on(power_domain);
+}
+
+int power_domain_off(struct power_domain *power_domain)
+{
+ struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return ops->off(power_domain);
+}
+
+#if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA))
+static int dev_power_domain_ctrl(struct udevice *dev, bool on)
+{
+ struct power_domain pd;
+ int i, count, ret = 0;
+
+ count = dev_count_phandle_with_args(dev, "power-domains",
+ "#power-domain-cells", 0);
+ for (i = 0; i < count; i++) {
+ ret = power_domain_get_by_index(dev, &pd, i);
+ if (ret)
+ return ret;
+ if (on)
+ ret = power_domain_on(&pd);
+ else
+ ret = power_domain_off(&pd);
+ }
+
+ /*
+ * For platforms with parent and child power-domain devices
+ * we may not run device_remove() on the power-domain parent
+ * because it will result in removing its children and switching
+ * off their power-domain parent. So we will get here again and
+ * again and will be stuck in an endless loop.
+ */
+ if (!on && dev_get_parent(dev) == pd.dev &&
+ device_get_uclass_id(dev) == UCLASS_POWER_DOMAIN)
+ return ret;
+
+ /*
+ * power_domain_get() bound the device, thus
+ * we must remove it again to prevent unbinding
+ * active devices (which would result in unbind
+ * error).
+ */
+ if (count > 0 && !on)
+ device_remove(pd.dev, DM_REMOVE_NORMAL);
+
+ return ret;
+}
+
+int dev_power_domain_on(struct udevice *dev)
+{
+ return dev_power_domain_ctrl(dev, true);
+}
+
+int dev_power_domain_off(struct udevice *dev)
+{
+ return dev_power_domain_ctrl(dev, false);
+}
+#endif
+
+UCLASS_DRIVER(power_domain) = {
+ .id = UCLASS_POWER_DOMAIN,
+ .name = "power_domain",
+};
diff --git a/roms/u-boot/drivers/power/domain/sandbox-power-domain-test.c b/roms/u-boot/drivers/power/domain/sandbox-power-domain-test.c
new file mode 100644
index 000000000..1bf52f1d8
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/sandbox-power-domain-test.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <power-domain.h>
+#include <asm/io.h>
+#include <asm/power-domain.h>
+
+struct sandbox_power_domain_test {
+ struct power_domain pd;
+};
+
+int sandbox_power_domain_test_get(struct udevice *dev)
+{
+ struct sandbox_power_domain_test *sbrt = dev_get_priv(dev);
+
+ return power_domain_get(dev, &sbrt->pd);
+}
+
+int sandbox_power_domain_test_on(struct udevice *dev)
+{
+ struct sandbox_power_domain_test *sbrt = dev_get_priv(dev);
+
+ return power_domain_on(&sbrt->pd);
+}
+
+int sandbox_power_domain_test_off(struct udevice *dev)
+{
+ struct sandbox_power_domain_test *sbrt = dev_get_priv(dev);
+
+ return power_domain_off(&sbrt->pd);
+}
+
+int sandbox_power_domain_test_free(struct udevice *dev)
+{
+ struct sandbox_power_domain_test *sbrt = dev_get_priv(dev);
+
+ return power_domain_free(&sbrt->pd);
+}
+
+static const struct udevice_id sandbox_power_domain_test_ids[] = {
+ { .compatible = "sandbox,power-domain-test" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_power_domain_test) = {
+ .name = "sandbox_power_domain_test",
+ .id = UCLASS_MISC,
+ .of_match = sandbox_power_domain_test_ids,
+ .priv_auto = sizeof(struct sandbox_power_domain_test),
+};
diff --git a/roms/u-boot/drivers/power/domain/sandbox-power-domain.c b/roms/u-boot/drivers/power/domain/sandbox-power-domain.c
new file mode 100644
index 000000000..04a071044
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/sandbox-power-domain.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <asm/io.h>
+#include <asm/power-domain.h>
+
+#define SANDBOX_POWER_DOMAINS 3
+
+struct sandbox_power_domain {
+ bool on[SANDBOX_POWER_DOMAINS];
+};
+
+static int sandbox_power_domain_request(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ if (power_domain->id >= SANDBOX_POWER_DOMAINS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sandbox_power_domain_free(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return 0;
+}
+
+static int sandbox_power_domain_on(struct power_domain *power_domain)
+{
+ struct sandbox_power_domain *sbr = dev_get_priv(power_domain->dev);
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ sbr->on[power_domain->id] = true;
+
+ return 0;
+}
+
+static int sandbox_power_domain_off(struct power_domain *power_domain)
+{
+ struct sandbox_power_domain *sbr = dev_get_priv(power_domain->dev);
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ sbr->on[power_domain->id] = false;
+
+ return 0;
+}
+
+static int sandbox_power_domain_bind(struct udevice *dev)
+{
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ return 0;
+}
+
+static int sandbox_power_domain_probe(struct udevice *dev)
+{
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ return 0;
+}
+
+static const struct udevice_id sandbox_power_domain_ids[] = {
+ { .compatible = "sandbox,power-domain" },
+ { }
+};
+
+struct power_domain_ops sandbox_power_domain_ops = {
+ .request = sandbox_power_domain_request,
+ .rfree = sandbox_power_domain_free,
+ .on = sandbox_power_domain_on,
+ .off = sandbox_power_domain_off,
+};
+
+U_BOOT_DRIVER(sandbox_power_domain) = {
+ .name = "sandbox_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = sandbox_power_domain_ids,
+ .bind = sandbox_power_domain_bind,
+ .probe = sandbox_power_domain_probe,
+ .priv_auto = sizeof(struct sandbox_power_domain),
+ .ops = &sandbox_power_domain_ops,
+};
+
+int sandbox_power_domain_query(struct udevice *dev, unsigned long id)
+{
+ struct sandbox_power_domain *sbr = dev_get_priv(dev);
+
+ debug("%s(dev=%p, id=%ld)\n", __func__, dev, id);
+
+ if (id >= SANDBOX_POWER_DOMAINS)
+ return -EINVAL;
+
+ return sbr->on[id];
+}
diff --git a/roms/u-boot/drivers/power/domain/tegra186-power-domain.c b/roms/u-boot/drivers/power/domain/tegra186-power-domain.c
new file mode 100644
index 000000000..707735cf8
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/tegra186-power-domain.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <misc.h>
+#include <power-domain-uclass.h>
+#include <asm/arch-tegra/bpmp_abi.h>
+#include <linux/bitops.h>
+
+#define UPDATE BIT(0)
+#define ON BIT(1)
+
+static int tegra186_power_domain_request(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__,
+ power_domain, power_domain->dev, power_domain->id);
+
+ return 0;
+}
+
+static int tegra186_power_domain_free(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__,
+ power_domain, power_domain->dev, power_domain->id);
+
+ return 0;
+}
+
+static int tegra186_power_domain_common(struct power_domain *power_domain,
+ bool on)
+{
+ struct mrq_pg_update_state_request req;
+ int on_state = on ? ON : 0;
+ int ret;
+
+ req.partition_id = power_domain->id;
+ req.logic_state = UPDATE | on_state;
+ req.sram_state = UPDATE | on_state;
+ /*
+ * Drivers manage their own clocks so they don't get out of sync, and
+ * since some power domains have many clocks, only a subset of which
+ * are actually needed depending on use-case.
+ */
+ req.clock_state = UPDATE;
+
+ ret = misc_call(power_domain->dev->parent, MRQ_PG_UPDATE_STATE, &req,
+ sizeof(req), NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tegra186_power_domain_on(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__,
+ power_domain, power_domain->dev, power_domain->id);
+
+ return tegra186_power_domain_common(power_domain, true);
+}
+
+static int tegra186_power_domain_off(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__,
+ power_domain, power_domain->dev, power_domain->id);
+
+ return tegra186_power_domain_common(power_domain, false);
+}
+
+struct power_domain_ops tegra186_power_domain_ops = {
+ .request = tegra186_power_domain_request,
+ .rfree = tegra186_power_domain_free,
+ .on = tegra186_power_domain_on,
+ .off = tegra186_power_domain_off,
+};
+
+static int tegra186_power_domain_probe(struct udevice *dev)
+{
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(tegra186_power_domain) = {
+ .name = "tegra186_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .probe = tegra186_power_domain_probe,
+ .ops = &tegra186_power_domain_ops,
+};
diff --git a/roms/u-boot/drivers/power/domain/ti-sci-power-domain.c b/roms/u-boot/drivers/power/domain/ti-sci-power-domain.c
new file mode 100644
index 000000000..f18e45617
--- /dev/null
+++ b/roms/u-boot/drivers/power/domain/ti-sci-power-domain.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments System Control Interface (TI SCI) power domain driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Andreas Dannenberg <dannenberg@ti.com>
+ *
+ * Loosely based on Linux kernel ti_sci_pm_domains.c...
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+/**
+ * struct ti_sci_power_domain_data - pm domain controller information structure
+ * @sci: TI SCI handle used for communication with system controller
+ */
+struct ti_sci_power_domain_data {
+ const struct ti_sci_handle *sci;
+};
+
+static int ti_sci_power_domain_probe(struct udevice *dev)
+{
+ struct ti_sci_power_domain_data *data = dev_get_priv(dev);
+
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ if (!data)
+ return -ENOMEM;
+
+ /* Store handle for communication with the system controller */
+ data->sci = ti_sci_get_handle(dev);
+ if (IS_ERR(data->sci))
+ return PTR_ERR(data->sci);
+
+ return 0;
+}
+
+static int ti_sci_power_domain_request(struct power_domain *pd)
+{
+ debug("%s(pd=%p)\n", __func__, pd);
+ return 0;
+}
+
+static int ti_sci_power_domain_free(struct power_domain *pd)
+{
+ debug("%s(pd=%p)\n", __func__, pd);
+ return 0;
+}
+
+static int ti_sci_power_domain_on(struct power_domain *pd)
+{
+ struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
+ const struct ti_sci_handle *sci = data->sci;
+ const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
+ u8 flags = (uintptr_t)pd->priv;
+ int ret;
+
+ debug("%s(pd=%p)\n", __func__, pd);
+
+ if (flags & TI_SCI_PD_EXCLUSIVE)
+ ret = dops->get_device_exclusive(sci, pd->id);
+ else
+ ret = dops->get_device(sci, pd->id);
+
+ if (ret)
+ dev_err(pd->dev, "%s: get_device(%lu) failed (%d)\n",
+ __func__, pd->id, ret);
+
+ return ret;
+}
+
+static int ti_sci_power_domain_off(struct power_domain *pd)
+{
+ struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
+ const struct ti_sci_handle *sci = data->sci;
+ const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
+ int ret;
+
+ debug("%s(pd=%p)\n", __func__, pd);
+
+ ret = dops->put_device(sci, pd->id);
+ if (ret)
+ dev_err(pd->dev, "%s: put_device(%lu) failed (%d)\n",
+ __func__, pd->id, ret);
+
+ return ret;
+}
+
+static int ti_sci_power_domain_of_xlate(struct power_domain *pd,
+ struct ofnode_phandle_args *args)
+{
+ u8 flags;
+
+ debug("%s(power_domain=%p)\n", __func__, pd);
+
+ if (args->args_count < 1) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ pd->id = args->args[0];
+ /* By default request for device exclusive */
+ flags = TI_SCI_PD_EXCLUSIVE;
+ if (args->args_count == 2)
+ flags = args->args[1] & TI_SCI_PD_EXCLUSIVE;
+ pd->priv = (void *)(uintptr_t)flags;
+
+ return 0;
+}
+
+static const struct udevice_id ti_sci_power_domain_of_match[] = {
+ { .compatible = "ti,sci-pm-domain" },
+ { /* sentinel */ }
+};
+
+static struct power_domain_ops ti_sci_power_domain_ops = {
+ .request = ti_sci_power_domain_request,
+ .rfree = ti_sci_power_domain_free,
+ .on = ti_sci_power_domain_on,
+ .off = ti_sci_power_domain_off,
+ .of_xlate = ti_sci_power_domain_of_xlate,
+};
+
+U_BOOT_DRIVER(ti_sci_pm_domains) = {
+ .name = "ti-sci-pm-domains",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = ti_sci_power_domain_of_match,
+ .probe = ti_sci_power_domain_probe,
+ .priv_auto = sizeof(struct ti_sci_power_domain_data),
+ .ops = &ti_sci_power_domain_ops,
+};
diff --git a/roms/u-boot/drivers/power/exynos-tmu.c b/roms/u-boot/drivers/power/exynos-tmu.c
new file mode 100644
index 000000000..4fba7b527
--- /dev/null
+++ b/roms/u-boot/drivers/power/exynos-tmu.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Akshay Saraswat <akshay.s@samsung.com>
+ *
+ * EXYNOS - Thermal Management Unit
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <tmu.h>
+#include <asm/arch/tmu.h>
+#include <asm/arch/power.h>
+
+#define TRIMINFO_RELOAD 1
+#define CORE_EN 1
+#define THERM_TRIP_EN (1 << 12)
+
+#define INTEN_RISE0 1
+#define INTEN_RISE1 (1 << 4)
+#define INTEN_RISE2 (1 << 8)
+#define INTEN_FALL0 (1 << 16)
+#define INTEN_FALL1 (1 << 20)
+#define INTEN_FALL2 (1 << 24)
+
+#define TRIM_INFO_MASK 0xff
+
+#define INTCLEAR_RISE0 1
+#define INTCLEAR_RISE1 (1 << 4)
+#define INTCLEAR_RISE2 (1 << 8)
+#define INTCLEAR_FALL0 (1 << 16)
+#define INTCLEAR_FALL1 (1 << 20)
+#define INTCLEAR_FALL2 (1 << 24)
+#define INTCLEARALL (INTCLEAR_RISE0 | INTCLEAR_RISE1 | \
+ INTCLEAR_RISE2 | INTCLEAR_FALL0 | \
+ INTCLEAR_FALL1 | INTCLEAR_FALL2)
+
+/* Tmeperature threshold values for various thermal events */
+struct temperature_params {
+ /* minimum value in temperature code range */
+ unsigned min_val;
+ /* maximum value in temperature code range */
+ unsigned max_val;
+ /* temperature threshold to start warning */
+ unsigned start_warning;
+ /* temperature threshold CPU tripping */
+ unsigned start_tripping;
+ /* temperature threshold for HW tripping */
+ unsigned hardware_tripping;
+};
+
+/* Pre-defined values and thresholds for calibration of current temperature */
+struct tmu_data {
+ /* pre-defined temperature thresholds */
+ struct temperature_params ts;
+ /* pre-defined efuse range minimum value */
+ unsigned efuse_min_value;
+ /* pre-defined efuse value for temperature calibration */
+ unsigned efuse_value;
+ /* pre-defined efuse range maximum value */
+ unsigned efuse_max_value;
+ /* current temperature sensing slope */
+ unsigned slope;
+};
+
+/* TMU device specific details and status */
+struct tmu_info {
+ /* base Address for the TMU */
+ struct exynos5_tmu_reg *tmu_base;
+ /* mux Address for the TMU */
+ int tmu_mux;
+ /* pre-defined values for calibration and thresholds */
+ struct tmu_data data;
+ /* value required for triminfo_25 calibration */
+ unsigned te1;
+ /* value required for triminfo_85 calibration */
+ unsigned te2;
+ /* Value for measured data calibration */
+ int dc_value;
+ /* enum value indicating status of the TMU */
+ int tmu_state;
+};
+
+/* Global struct tmu_info variable to store init values */
+static struct tmu_info gbl_info;
+
+/*
+ * Get current temperature code from register,
+ * then calculate and calibrate it's value
+ * in degree celsius.
+ *
+ * @return current temperature of the chip as sensed by TMU
+ */
+static int get_cur_temp(struct tmu_info *info)
+{
+ struct exynos5_tmu_reg *reg = info->tmu_base;
+ ulong start;
+ int cur_temp = 0;
+
+ /*
+ * Temperature code range between min 25 and max 125.
+ * May run more than once for first call as initial sensing
+ * has not yet happened.
+ */
+ if (info->tmu_state == TMU_STATUS_NORMAL) {
+ start = get_timer(0);
+ do {
+ cur_temp = readl(&reg->current_temp) & 0xff;
+ } while ((cur_temp == 0) || (get_timer(start) > 100));
+ }
+
+ if (cur_temp == 0)
+ return cur_temp;
+
+ /* Calibrate current temperature */
+ cur_temp = cur_temp - info->te1 + info->dc_value;
+
+ return cur_temp;
+}
+
+/*
+ * Monitors status of the TMU device and exynos temperature
+ *
+ * @param temp pointer to the current temperature value
+ * @return enum tmu_status_t value, code indicating event to execute
+ */
+enum tmu_status_t tmu_monitor(int *temp)
+{
+ int cur_temp;
+ struct tmu_data *data = &gbl_info.data;
+
+ if (gbl_info.tmu_state == TMU_STATUS_INIT)
+ return TMU_STATUS_INIT;
+
+ /* Read current temperature of the SOC */
+ cur_temp = get_cur_temp(&gbl_info);
+
+ if (!cur_temp)
+ goto out;
+
+ *temp = cur_temp;
+
+ /* Temperature code lies between min 25 and max 125 */
+ if ((cur_temp >= data->ts.start_tripping) &&
+ (cur_temp <= data->ts.max_val))
+ return TMU_STATUS_TRIPPED;
+
+ if (cur_temp >= data->ts.start_warning)
+ return TMU_STATUS_WARNING;
+
+ if ((cur_temp < data->ts.start_warning) &&
+ (cur_temp >= data->ts.min_val))
+ return TMU_STATUS_NORMAL;
+
+ out:
+ /* Temperature code does not lie between min 25 and max 125 */
+ gbl_info.tmu_state = TMU_STATUS_INIT;
+ debug("EXYNOS_TMU: Thermal reading failed\n");
+ return TMU_STATUS_INIT;
+}
+
+/*
+ * Get TMU specific pre-defined values from FDT
+ *
+ * @param info pointer to the tmu_info struct
+ * @param blob FDT blob
+ * @return int value, 0 for success
+ */
+static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ fdt_addr_t addr;
+ int node;
+ int error = 0;
+
+ /* Get the node from FDT for TMU */
+ node = fdtdec_next_compatible(blob, 0,
+ COMPAT_SAMSUNG_EXYNOS_TMU);
+ if (node < 0) {
+ debug("EXYNOS_TMU: No node for tmu in device tree\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Get the pre-defined TMU specific values from FDT.
+ * All of these are expected to be correct otherwise
+ * miscalculation of register values in tmu_setup_parameters
+ * may result in misleading current temperature.
+ */
+ addr = fdtdec_get_addr(blob, node, "reg");
+ if (addr == FDT_ADDR_T_NONE) {
+ debug("%s: Missing tmu-base\n", __func__);
+ return -ENODEV;
+ }
+ info->tmu_base = (struct exynos5_tmu_reg *)addr;
+
+ /* Optional field. */
+ info->tmu_mux = fdtdec_get_int(blob,
+ node, "samsung,mux", -1);
+ /* Take default value as per the user manual b(110) */
+ if (info->tmu_mux == -1)
+ info->tmu_mux = 0x6;
+
+ info->data.ts.min_val = fdtdec_get_int(blob,
+ node, "samsung,min-temp", -1);
+ error |= (info->data.ts.min_val == -1);
+ info->data.ts.max_val = fdtdec_get_int(blob,
+ node, "samsung,max-temp", -1);
+ error |= (info->data.ts.max_val == -1);
+ info->data.ts.start_warning = fdtdec_get_int(blob,
+ node, "samsung,start-warning", -1);
+ error |= (info->data.ts.start_warning == -1);
+ info->data.ts.start_tripping = fdtdec_get_int(blob,
+ node, "samsung,start-tripping", -1);
+ error |= (info->data.ts.start_tripping == -1);
+ info->data.ts.hardware_tripping = fdtdec_get_int(blob,
+ node, "samsung,hw-tripping", -1);
+ error |= (info->data.ts.hardware_tripping == -1);
+ info->data.efuse_min_value = fdtdec_get_int(blob,
+ node, "samsung,efuse-min-value", -1);
+ error |= (info->data.efuse_min_value == -1);
+ info->data.efuse_value = fdtdec_get_int(blob,
+ node, "samsung,efuse-value", -1);
+ error |= (info->data.efuse_value == -1);
+ info->data.efuse_max_value = fdtdec_get_int(blob,
+ node, "samsung,efuse-max-value", -1);
+ error |= (info->data.efuse_max_value == -1);
+ info->data.slope = fdtdec_get_int(blob,
+ node, "samsung,slope", -1);
+ error |= (info->data.slope == -1);
+ info->dc_value = fdtdec_get_int(blob,
+ node, "samsung,dc-value", -1);
+ error |= (info->dc_value == -1);
+
+ if (error) {
+ debug("fail to get tmu node properties\n");
+ return -EINVAL;
+ }
+#else
+ /* Non DT support may never be added. Just in case */
+ return -ENODEV;
+#endif
+
+ return 0;
+}
+
+/*
+ * Calibrate and calculate threshold values and
+ * enable interrupt levels
+ *
+ * @param info pointer to the tmu_info struct
+ */
+static void tmu_setup_parameters(struct tmu_info *info)
+{
+ unsigned te_code, con;
+ unsigned warning_code, trip_code, hwtrip_code;
+ unsigned cooling_temp;
+ unsigned rising_value;
+ struct tmu_data *data = &info->data;
+ struct exynos5_tmu_reg *reg = info->tmu_base;
+
+ /* Must reload for reading efuse value from triminfo register */
+ writel(TRIMINFO_RELOAD, &reg->triminfo_control);
+
+ /* Get the compensation parameter */
+ te_code = readl(&reg->triminfo);
+ info->te1 = te_code & TRIM_INFO_MASK;
+ info->te2 = ((te_code >> 8) & TRIM_INFO_MASK);
+
+ if ((data->efuse_min_value > info->te1) ||
+ (info->te1 > data->efuse_max_value)
+ || (info->te2 != 0))
+ info->te1 = data->efuse_value;
+
+ /* Get RISING & FALLING Threshold value */
+ warning_code = data->ts.start_warning
+ + info->te1 - info->dc_value;
+ trip_code = data->ts.start_tripping
+ + info->te1 - info->dc_value;
+ hwtrip_code = data->ts.hardware_tripping
+ + info->te1 - info->dc_value;
+
+ cooling_temp = 0;
+
+ rising_value = ((warning_code << 8) |
+ (trip_code << 16) |
+ (hwtrip_code << 24));
+
+ /* Set interrupt level */
+ writel(rising_value, &reg->threshold_temp_rise);
+ writel(cooling_temp, &reg->threshold_temp_fall);
+
+ /*
+ * Init TMU control tuning parameters
+ * [28:24] VREF - Voltage reference
+ * [15:13] THERM_TRIP_MODE - Tripping mode
+ * [12] THERM_TRIP_EN - Thermal tripping enable
+ * [11:8] BUF_SLOPE_SEL - Gain of amplifier
+ * [6] THERM_TRIP_BY_TQ_EN - Tripping by TQ pin
+ */
+ writel(data->slope, &reg->tmu_control);
+
+ writel(INTCLEARALL, &reg->intclear);
+
+ /* TMU core enable */
+ con = readl(&reg->tmu_control);
+ con |= THERM_TRIP_EN | CORE_EN | (info->tmu_mux << 20);
+
+ writel(con, &reg->tmu_control);
+
+ /* Enable HW thermal trip */
+ set_hw_thermal_trip();
+
+ /* LEV1 LEV2 interrupt enable */
+ writel(INTEN_RISE1 | INTEN_RISE2, &reg->inten);
+}
+
+/*
+ * Initialize TMU device
+ *
+ * @param blob FDT blob
+ * @return int value, 0 for success
+ */
+int tmu_init(const void *blob)
+{
+ gbl_info.tmu_state = TMU_STATUS_INIT;
+ if (get_tmu_fdt_values(&gbl_info, blob) < 0)
+ goto ret;
+
+ tmu_setup_parameters(&gbl_info);
+ gbl_info.tmu_state = TMU_STATUS_NORMAL;
+ret:
+ return gbl_info.tmu_state;
+}
diff --git a/roms/u-boot/drivers/power/ftpmu010.c b/roms/u-boot/drivers/power/ftpmu010.c
new file mode 100644
index 000000000..9a48b3655
--- /dev/null
+++ b/roms/u-boot/drivers/power/ftpmu010.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * Copyright (C) 2010 Andes Technology Corporation
+ * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
+ * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/ftpmu010.h>
+
+/* OSCC: OSC Control Register */
+void ftpmu010_32768osc_enable(void)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int oscc;
+
+ /* enable the 32768Hz oscillator */
+ oscc = readl(&pmu->OSCC);
+ oscc &= ~(FTPMU010_OSCC_OSCL_OFF | FTPMU010_OSCC_OSCL_TRI);
+ writel(oscc, &pmu->OSCC);
+
+ /* wait until ready */
+ while (!(readl(&pmu->OSCC) & FTPMU010_OSCC_OSCL_STABLE))
+ ;
+
+ /* select 32768Hz oscillator */
+ oscc = readl(&pmu->OSCC);
+ oscc |= FTPMU010_OSCC_OSCL_RTCLSEL;
+ writel(oscc, &pmu->OSCC);
+}
+
+/* MFPSR: Multi-Function Port Setting Register */
+void ftpmu010_mfpsr_select_dev(unsigned int dev)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int mfpsr;
+
+ mfpsr = readl(&pmu->MFPSR);
+ mfpsr |= dev;
+ writel(mfpsr, &pmu->MFPSR);
+}
+
+void ftpmu010_mfpsr_diselect_dev(unsigned int dev)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int mfpsr;
+
+ mfpsr = readl(&pmu->MFPSR);
+ mfpsr &= ~dev;
+ writel(mfpsr, &pmu->MFPSR);
+}
+
+/* PDLLCR0: PLL/DLL Control Register 0 */
+void ftpmu010_dlldis_disable(void)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int pdllcr0;
+
+ pdllcr0 = readl(&pmu->PDLLCR0);
+ pdllcr0 |= FTPMU010_PDLLCR0_DLLDIS;
+ writel(pdllcr0, &pmu->PDLLCR0);
+}
+
+void ftpmu010_sdram_clk_disable(unsigned int cr0)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int pdllcr0;
+
+ pdllcr0 = readl(&pmu->PDLLCR0);
+ pdllcr0 |= FTPMU010_PDLLCR0_HCLKOUTDIS(cr0);
+ writel(pdllcr0, &pmu->PDLLCR0);
+}
+
+/* SDRAMHTC: SDRAM Signal Hold Time Control */
+void ftpmu010_sdramhtc_set(unsigned int val)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int sdramhtc;
+
+ sdramhtc = readl(&pmu->SDRAMHTC);
+ sdramhtc |= val;
+ writel(sdramhtc, &pmu->SDRAMHTC);
+}
diff --git a/roms/u-boot/drivers/power/fuel_gauge/Makefile b/roms/u-boot/drivers/power/fuel_gauge/Makefile
new file mode 100644
index 000000000..ca2df9475
--- /dev/null
+++ b/roms/u-boot/drivers/power/fuel_gauge/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2012 Samsung Electronics
+# Lukasz Majewski <l.majewski@samsung.com>
+
+obj-$(CONFIG_POWER_FG_MAX17042) += fg_max17042.o
diff --git a/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c b/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c
new file mode 100644
index 000000000..a395d587a
--- /dev/null
+++ b/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <power/pmic.h>
+#include <power/max17042_fg.h>
+#include <i2c.h>
+#include <power/max8997_pmic.h>
+#include <power/power_chrg.h>
+#include <power/battery.h>
+#include <power/fg_battery_cell_params.h>
+#include <errno.h>
+
+static int fg_write_regs(struct pmic *p, u8 addr, u16 *data, int num)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < num; i++, addr++) {
+ ret = pmic_reg_write(p, addr, *(data + i));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fg_read_regs(struct pmic *p, u8 addr, u16 *data, int num)
+{
+ unsigned int dat;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < num; i++, addr++) {
+ ret = pmic_reg_read(p, addr, &dat);
+ if (ret)
+ return ret;
+
+ *(data + i) = (u16)dat;
+ }
+
+ return 0;
+}
+
+static int fg_write_and_verify(struct pmic *p, u8 addr, u16 data)
+{
+ unsigned int val = data;
+ int ret = 0;
+
+ ret |= pmic_reg_write(p, addr, val);
+ ret |= pmic_reg_read(p, addr, &val);
+
+ if (ret)
+ return ret;
+
+ if (((u16) val) == data)
+ return 0;
+
+ return -1;
+}
+
+static void por_fuelgauge_init(struct pmic *p)
+{
+ u16 r_data0[16], r_data1[16], r_data2[16];
+ u32 rewrite_count = 5;
+ u32 check_count;
+ u32 lock_count;
+ u32 i = 0;
+ u32 val;
+ s32 ret = 0;
+ char *status_msg;
+
+ /* Delay 500 ms */
+ mdelay(500);
+ /* Initilize Configuration */
+ pmic_reg_write(p, MAX17042_CONFIG, 0x2310);
+
+rewrite_model:
+ check_count = 5;
+ lock_count = 5;
+
+ if (!rewrite_count--) {
+ status_msg = "init failed!";
+ goto error;
+ }
+
+ /* Unlock Model Access */
+ pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
+ pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
+
+ /* Write/Read/Verify the Custom Model */
+ ret = fg_write_regs(p, MAX17042_MODEL1, cell_character0,
+ ARRAY_SIZE(cell_character0));
+ if (ret)
+ goto rewrite_model;
+
+ ret = fg_write_regs(p, MAX17042_MODEL2, cell_character1,
+ ARRAY_SIZE(cell_character1));
+ if (ret)
+ goto rewrite_model;
+
+ ret = fg_write_regs(p, MAX17042_MODEL3, cell_character2,
+ ARRAY_SIZE(cell_character2));
+ if (ret)
+ goto rewrite_model;
+
+check_model:
+ if (!check_count--) {
+ if (rewrite_count)
+ goto rewrite_model;
+ else
+ status_msg = "check failed!";
+
+ goto error;
+ }
+
+ ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
+ if (ret)
+ goto check_model;
+
+ ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
+ if (ret)
+ goto check_model;
+
+ ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
+ if (ret)
+ goto check_model;
+
+ for (i = 0; i < 16; i++) {
+ if ((cell_character0[i] != r_data0[i])
+ || (cell_character1[i] != r_data1[i])
+ || (cell_character2[i] != r_data2[i]))
+ goto rewrite_model;
+ }
+
+lock_model:
+ if (!lock_count--) {
+ if (rewrite_count)
+ goto rewrite_model;
+ else
+ status_msg = "lock failed!";
+
+ goto error;
+ }
+
+ /* Lock model access */
+ pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_LOCK1);
+ pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_LOCK2);
+
+ /* Verify the model access is locked */
+ ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
+ if (ret)
+ goto lock_model;
+
+ ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
+ if (ret)
+ goto lock_model;
+
+ ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
+ if (ret)
+ goto lock_model;
+
+ for (i = 0; i < ARRAY_SIZE(r_data0); i++) {
+ /* Check if model locked */
+ if (r_data0[i] || r_data1[i] || r_data2[i])
+ goto lock_model;
+ }
+
+ /* Write Custom Parameters */
+ fg_write_and_verify(p, MAX17042_RCOMP0, RCOMP0);
+ fg_write_and_verify(p, MAX17042_TEMPCO, TempCo);
+
+ /* Delay at least 350mS */
+ mdelay(350);
+
+ /* Initialization Complete */
+ pmic_reg_read(p, MAX17042_STATUS, &val);
+ /* Write and Verify Status with POR bit Cleared */
+ fg_write_and_verify(p, MAX17042_STATUS, val & ~MAX17042_POR);
+
+ /* Delay at least 350 ms */
+ mdelay(350);
+
+ status_msg = "OK!";
+error:
+ debug("%s: model init status: %s\n", p->name, status_msg);
+ return;
+}
+
+static int power_update_battery(struct pmic *p, struct pmic *bat)
+{
+ struct power_battery *pb = bat->pbat;
+ unsigned int val;
+ int ret = 0;
+
+ if (pmic_probe(p)) {
+ puts("Can't find max17042 fuel gauge\n");
+ return -ENODEV;
+ }
+
+ ret |= pmic_reg_read(p, MAX17042_VFSOC, &val);
+ pb->bat->state_of_chrg = (val >> 8);
+
+ pmic_reg_read(p, MAX17042_VCELL, &val);
+ debug("vfsoc: 0x%x\n", val);
+ pb->bat->voltage_uV = ((val & 0xFFUL) >> 3) + ((val & 0xFF00) >> 3);
+ pb->bat->voltage_uV = (pb->bat->voltage_uV * 625);
+
+ pmic_reg_read(p, 0x05, &val);
+ pb->bat->capacity = val >> 2;
+
+ return ret;
+}
+
+static int power_check_battery(struct pmic *p, struct pmic *bat)
+{
+ struct power_battery *pb = bat->pbat;
+ unsigned int val;
+ int ret = 0;
+
+ if (pmic_probe(p)) {
+ puts("Can't find max17042 fuel gauge\n");
+ return -ENODEV;
+ }
+
+ ret |= pmic_reg_read(p, MAX17042_STATUS, &val);
+ debug("fg status: 0x%x\n", val);
+
+ if (val & MAX17042_POR)
+ por_fuelgauge_init(p);
+
+ ret |= pmic_reg_read(p, MAX17042_VERSION, &val);
+ pb->bat->version = val;
+
+ power_update_battery(p, bat);
+ debug("fg ver: 0x%x\n", pb->bat->version);
+ printf("BAT: state_of_charge(SOC):%d%%\n",
+ pb->bat->state_of_chrg);
+
+ printf(" voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
+ pb->bat->voltage_uV / 1000000,
+ pb->bat->voltage_uV % 1000000,
+ pb->bat->capacity);
+
+ if (pb->bat->voltage_uV > 3850000)
+ pb->bat->state = EXT_SOURCE;
+ else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5)
+ pb->bat->state = CHARGE;
+ else
+ pb->bat->state = NORMAL;
+
+ return ret;
+}
+
+static struct power_fg power_fg_ops = {
+ .fg_battery_check = power_check_battery,
+ .fg_battery_update = power_update_battery,
+};
+
+int power_fg_init(unsigned char bus)
+{
+ static const char name[] = "MAX17042_FG";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board Fuel Gauge init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = FG_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX17042_I2C_ADDR;
+ p->hw.i2c.tx_num = 2;
+ p->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG;
+ p->bus = bus;
+
+ p->fg = &power_fg_ops;
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/mfd/Makefile b/roms/u-boot/drivers/power/mfd/Makefile
new file mode 100644
index 000000000..a8eb7f81e
--- /dev/null
+++ b/roms/u-boot/drivers/power/mfd/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2013 Samsung Electronics
+# Piotr Wilczek <p.wilczek@samsung.com>
+
+obj-$(CONFIG_POWER_PMIC_MAX77693) += pmic_max77693.o
+obj-$(CONFIG_POWER_MUIC_MAX77693) += muic_max77693.o
+obj-$(CONFIG_POWER_FG_MAX77693) += fg_max77693.o
diff --git a/roms/u-boot/drivers/power/mfd/fg_max77693.c b/roms/u-boot/drivers/power/mfd/fg_max77693.c
new file mode 100644
index 000000000..983a6d4a2
--- /dev/null
+++ b/roms/u-boot/drivers/power/mfd/fg_max77693.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Piotr Wilczek <p.wilczek@samsung.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/max77693_fg.h>
+#include <i2c.h>
+#include <power/power_chrg.h>
+#include <power/battery.h>
+#include <power/fg_battery_cell_params.h>
+#include <errno.h>
+
+static int max77693_get_vcell(u32 *vcell)
+{
+ u16 value;
+ u8 ret;
+
+ ret = i2c_read(MAX77693_FUEL_I2C_ADDR, MAX77693_VCELL, 1,
+ (u8 *)&value, 2);
+ if (ret)
+ return ret;
+
+ *vcell = (u32)(value >> 3);
+ *vcell = *vcell * 625;
+
+ return 0;
+}
+
+static int max77693_get_soc(u32 *soc)
+{
+ u16 value;
+ u8 ret;
+
+ ret = i2c_read(MAX77693_FUEL_I2C_ADDR, MAX77693_VFSOC, 1,
+ (u8 *)&value, 2);
+ if (ret)
+ return ret;
+
+ *soc = (u32)(value >> 8);
+
+ return 0;
+}
+
+static int power_update_battery(struct pmic *p, struct pmic *bat)
+{
+ struct power_battery *pb = bat->pbat;
+ int ret;
+
+ if (pmic_probe(p)) {
+ puts("Can't find max77693 fuel gauge\n");
+ return -ENODEV;
+ }
+
+ ret = max77693_get_soc(&pb->bat->state_of_chrg);
+ if (ret)
+ return ret;
+
+ max77693_get_vcell(&pb->bat->voltage_uV);
+
+ return 0;
+}
+
+static int power_check_battery(struct pmic *p, struct pmic *bat)
+{
+ struct power_battery *pb = bat->pbat;
+ unsigned int val;
+ int ret = 0;
+
+ if (pmic_probe(p)) {
+ puts("Can't find max77693 fuel gauge\n");
+ return -ENODEV;
+ }
+
+ ret = pmic_reg_read(p, MAX77693_STATUS, &val);
+ if (ret)
+ return ret;
+ debug("fg status: 0x%x\n", val);
+
+ ret = pmic_reg_read(p, MAX77693_VERSION, &pb->bat->version);
+ if (ret)
+ return ret;
+
+ ret = power_update_battery(p, bat);
+ if (ret)
+ return ret;
+ debug("fg ver: 0x%x\n", pb->bat->version);
+ printf("BAT: state_of_charge(SOC):%d%%\n",
+ pb->bat->state_of_chrg);
+
+ printf(" voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
+ pb->bat->voltage_uV / 1000000,
+ pb->bat->voltage_uV % 1000000,
+ pb->bat->capacity);
+
+ if (pb->bat->voltage_uV > 3850000)
+ pb->bat->state = EXT_SOURCE;
+ else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5)
+ pb->bat->state = CHARGE;
+ else
+ pb->bat->state = NORMAL;
+
+ return 0;
+}
+
+static struct power_fg power_fg_ops = {
+ .fg_battery_check = power_check_battery,
+ .fg_battery_update = power_update_battery,
+};
+
+int power_fg_init(unsigned char bus)
+{
+ static const char name[] = "MAX77693_FG";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board Fuel Gauge init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = FG_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX77693_FUEL_I2C_ADDR;
+ p->hw.i2c.tx_num = 2;
+ p->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG;
+ p->bus = bus;
+
+ p->fg = &power_fg_ops;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/mfd/muic_max77693.c b/roms/u-boot/drivers/power/mfd/muic_max77693.c
new file mode 100644
index 000000000..36ee44b9a
--- /dev/null
+++ b/roms/u-boot/drivers/power/mfd/muic_max77693.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Piotr Wilczek <p.wilczek@samsung.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/power_chrg.h>
+#include <power/max77693_muic.h>
+#include <i2c.h>
+#include <errno.h>
+
+static int power_chrg_get_type(struct pmic *p)
+{
+ unsigned int val;
+ unsigned int charge_type, charger;
+
+ /* if probe failed, return cable none */
+ if (pmic_probe(p))
+ return CHARGER_NO;
+
+ pmic_reg_read(p, MAX77693_MUIC_STATUS2, &val);
+
+ charge_type = val & MAX77693_MUIC_CHG_MASK;
+
+ switch (charge_type) {
+ case MAX77693_MUIC_CHG_NO:
+ charger = CHARGER_NO;
+ break;
+ case MAX77693_MUIC_CHG_USB:
+ case MAX77693_MUIC_CHG_USB_D:
+ charger = CHARGER_USB;
+ break;
+ case MAX77693_MUIC_CHG_TA:
+ case MAX77693_MUIC_CHG_TA_1A:
+ charger = CHARGER_TA;
+ break;
+ case MAX77693_MUIC_CHG_TA_500:
+ charger = CHARGER_TA_500;
+ break;
+ default:
+ charger = CHARGER_UNKNOWN;
+ break;
+ }
+
+ return charger;
+}
+
+static struct power_chrg power_chrg_muic_ops = {
+ .chrg_type = power_chrg_get_type,
+};
+
+int power_muic_init(unsigned int bus)
+{
+ static const char name[] = "MAX77693_MUIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board Micro USB Interface Controller init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = MUIC_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX77693_MUIC_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ p->chrg = &power_chrg_muic_ops;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/mfd/pmic_max77693.c b/roms/u-boot/drivers/power/mfd/pmic_max77693.c
new file mode 100644
index 000000000..e32a9722a
--- /dev/null
+++ b/roms/u-boot/drivers/power/mfd/pmic_max77693.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Piotr Wilczek <p.wilczek@samsung.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/max77693_pmic.h>
+#include <i2c.h>
+#include <errno.h>
+
+static int max77693_charger_state(struct pmic *p, int state, int current)
+{
+ unsigned int val;
+
+ if (pmic_probe(p))
+ return -ENODEV;
+
+ /* unlock write capability */
+ val = MAX77693_CHG_UNLOCK;
+ pmic_reg_write(p, MAX77693_CHG_CNFG_06, val);
+
+ if (state == PMIC_CHARGER_DISABLE) {
+ puts("Disable the charger.\n");
+ pmic_reg_read(p, MAX77693_CHG_CNFG_00, &val);
+ val &= ~0x01;
+ pmic_reg_write(p, MAX77693_CHG_CNFG_00, val);
+ return -ENOTSUPP;
+ }
+
+ if (current < CHARGER_MIN_CURRENT || current > CHARGER_MAX_CURRENT) {
+ printf("%s: Wrong charge current: %d [mA]\n",
+ __func__, current);
+ return -EINVAL;
+ }
+
+ /* set charging current */
+ pmic_reg_read(p, MAX77693_CHG_CNFG_02, &val);
+ val &= ~MAX77693_CHG_CC;
+ val |= current * 10 / 333; /* 0.1A/3 steps */
+ pmic_reg_write(p, MAX77693_CHG_CNFG_02, val);
+
+ /* enable charging */
+ val = MAX77693_CHG_MODE_ON;
+ pmic_reg_write(p, MAX77693_CHG_CNFG_00, val);
+
+ /* check charging current */
+ pmic_reg_read(p, MAX77693_CHG_CNFG_02, &val);
+ val &= 0x3f;
+ printf("Enable the charger @ %d [mA]\n", val * 333 / 10);
+
+ return 0;
+}
+
+static int max77693_charger_bat_present(struct pmic *p)
+{
+ unsigned int val;
+
+ if (pmic_probe(p))
+ return -ENODEV;
+
+ pmic_reg_read(p, MAX77693_CHG_INT_OK, &val);
+
+ return !(val & MAX77693_CHG_DETBAT);
+}
+
+static struct power_chrg power_chrg_pmic_ops = {
+ .chrg_bat_present = max77693_charger_bat_present,
+ .chrg_state = max77693_charger_state,
+};
+
+int pmic_init_max77693(unsigned char bus)
+{
+ static const char name[] = "MAX77693_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board PMIC init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX77693_PMIC_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ p->chrg = &power_chrg_pmic_ops;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/mt6323.c b/roms/u-boot/drivers/power/mt6323.c
new file mode 100644
index 000000000..354817a03
--- /dev/null
+++ b/roms/u-boot/drivers/power/mt6323.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Frank Wunderlich <frank-w@public-files.de>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#define PWRAP_BASE 0x1000d000
+#define PWRAP_WACS2_CMD 0x9c
+
+#define PWRAP_CALC(adr, wdata) ((1 << 31) | (((adr) >> 1) << 16) | (wdata))
+
+#define MT6323_PWRC_BASE 0x8000
+#define RTC_BBPU 0x0000
+#define RTC_BBPU_KEY (0x43 << 8)
+#define RTC_WRTGR 0x003c
+
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ u32 addr, val;
+
+ addr = PWRAP_BASE + PWRAP_WACS2_CMD;
+ val = PWRAP_CALC(MT6323_PWRC_BASE + RTC_BBPU, RTC_BBPU_KEY);
+ writel(val, addr);
+
+ mdelay(10);
+
+ val = PWRAP_CALC(MT6323_PWRC_BASE + RTC_WRTGR, 1);
+ writel(val, addr);
+
+ // wait some time and then print error
+ mdelay(10000);
+ printf("Failed to power off!!!\n");
+ return 1;
+}
diff --git a/roms/u-boot/drivers/power/palmas.c b/roms/u-boot/drivers/power/palmas.c
new file mode 100644
index 000000000..bf9173949
--- /dev/null
+++ b/roms/u-boot/drivers/power/palmas.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012-2013
+ * Texas Instruments, <www.ti.com>
+ */
+#include <config.h>
+#include <palmas.h>
+
+void palmas_init_settings(void)
+{
+#ifdef CONFIG_PALMAS_SMPS7_FPWM
+ int err;
+ /*
+ * Set SMPS7 (1.8 V I/O supply on platforms with TWL6035/37) to
+ * forced PWM mode. This reduces noise (but affects efficiency).
+ */
+ u8 val = SMPS_MODE_SLP_FPWM | SMPS_MODE_ACT_FPWM;
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS7_CTRL, val);
+ if (err)
+ printf("palmas: could not force PWM for SMPS7: err = %d\n",
+ err);
+#endif
+}
+
+#if defined(CONFIG_OMAP54XX)
+int lp873x_mmc1_poweron_ldo(uint voltage)
+{
+ if (palmas_i2c_write_u8(LP873X_LDO1_ADDR, LP873X_LDO1_VOLTAGE,
+ voltage)) {
+ printf("lp873x: could not set LDO1 voltage.\n");
+ return 1;
+ }
+ /* TURN ON LDO1 */
+ if (palmas_i2c_write_u8(LP873X_LDO1_ADDR, LP873X_LDO1_CTRL,
+ LP873X_LDO_CTRL_EN | LP873X_LDO_CTRL_RDIS_EN)) {
+ printf("lp873x: could not turn on LDO1.\n");
+ return 1;
+ }
+ return 0;
+
+}
+#endif
+
+int palmas_mmc1_poweron_ldo(uint ldo_volt, uint ldo_ctrl, uint voltage)
+{
+ u8 val = 0;
+
+#if defined(CONFIG_DRA7XX)
+ int ret;
+
+ ret = palmas_i2c_write_u8(TPS65903X_CHIP_P1, ldo_volt, voltage);
+ if (ret) {
+ printf("tps65903x: could not set LDO1 voltage.\n");
+ return ret;
+ }
+ /* TURN ON LDO1 */
+ val = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ ret = palmas_i2c_write_u8(TPS65903X_CHIP_P1, ldo_ctrl, val);
+ if (ret) {
+ printf("tps65903x: could not turn on LDO1.\n");
+ return ret;
+ }
+ return 0;
+#else
+ /*
+ * We assume that this is a OMAP543X + TWL603X board:
+ * Set TWL6035/37 LDO9 to 3.0 V
+ */
+ val = LDO_VOLT_3V0;
+ return twl603x_mmc1_set_ldo9(val);
+#endif
+}
+
+/*
+ * On some OMAP5 + TWL603X hardware the SD card socket and LDO9_IN are
+ * powered by an external 3.3 V regulator, while the output of LDO9
+ * supplies VDDS_SDCARD for the OMAP5 interface only. This implies that
+ * LDO9 could be set to 'bypass' mode when required (e.g. for 3.3 V cards).
+ */
+int twl603x_mmc1_set_ldo9(u8 vsel)
+{
+ u8 cval = 0, vval = 0; /* Off by default */
+ int err;
+
+ if (vsel) {
+ /* Turn on */
+ if (vsel > LDO_VOLT_3V3) {
+ /* Put LDO9 in bypass */
+ cval = LDO9_BYP_EN | RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ vval = LDO_VOLT_3V3;
+ } else {
+ cval = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ vval = vsel & 0x3f;
+ }
+ }
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, LDO9_VOLTAGE, vval);
+ if (err) {
+ printf("twl603x: could not set LDO9 %s: err = %d\n",
+ vsel > LDO_VOLT_3V3 ? "bypass" : "voltage", err);
+ return err;
+ }
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, LDO9_CTRL, cval);
+ if (err)
+ printf("twl603x: could not turn %s LDO9: err = %d\n",
+ cval ? "on" : "off", err);
+ return err;
+}
+
+#ifdef CONFIG_PALMAS_AUDPWR
+/*
+ * Turn audio codec power and 32 kHz clock on/off. Use for
+ * testing OMAP543X + TWL603X + TWL604X boards only.
+ */
+int twl603x_audio_power(u8 on)
+{
+ u8 cval = 0, vval = 0, c32k = 0;
+ int err;
+
+ if (on) {
+ vval = SMPS_VOLT_2V1;
+ cval = SMPS_MODE_SLP_AUTO | SMPS_MODE_ACT_AUTO;
+ c32k = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ }
+ /* Set SMPS9 to 2.1 V (for TWL604x), or to 0 (off) */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS9_VOLTAGE, vval);
+ if (err) {
+ printf("twl603x: could not set SMPS9 voltage: err = %d\n",
+ err);
+ return err;
+ }
+ /* Turn on or off SMPS9 */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS9_CTRL, cval);
+ if (err) {
+ printf("twl603x: could not turn SMPS9 %s: err = %d\n",
+ cval ? "on" : "off", err);
+ return err;
+ }
+ /* Output 32 kHz clock on or off */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, CLK32KGAUDIO_CTRL, c32k);
+ if (err)
+ printf("twl603x: could not turn CLK32KGAUDIO %s: err = %d\n",
+ c32k ? "on" : "off", err);
+ return err;
+}
+#endif
+
+#ifdef CONFIG_PALMAS_USB_SS_PWR
+/**
+ * @brief palmas_enable_ss_ldo - Configure EVM board specific configurations
+ * for the USB Super speed SMPS10 regulator.
+ *
+ * @return 0
+ */
+int palmas_enable_ss_ldo(void)
+{
+ /* Enable smps10 regulator */
+ return palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS10_CTRL,
+ SMPS10_MODE_ACTIVE_D);
+}
+#endif
+
+/*
+ * Enable/disable back-up battery (or super cap) charging on TWL6035/37.
+ * Please use defined BB_xxx values.
+ */
+int twl603x_enable_bb_charge(u8 bb_fields)
+{
+ u8 val = bb_fields & 0x0f;
+ int err;
+
+ val |= (VRTC_EN_SLP | VRTC_EN_OFF | VRTC_PWEN);
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, BB_VRTC_CTRL, val);
+ if (err)
+ printf("twl603x: could not set BB_VRTC_CTRL to 0x%02x: err = %d\n",
+ val, err);
+ return err;
+}
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+int palmas_i2c_write_u8(u8 chip_no, u8 reg, u8 val)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev);
+ if (ret) {
+ pr_err("unable to get I2C bus. ret %d\n", ret);
+ return ret;
+ }
+ ret = dm_i2c_reg_write(dev, reg, val);
+ if (ret) {
+ pr_err("writing to palmas failed. ret %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+int palmas_i2c_read_u8(u8 chip_no, u8 reg, u8 *valp)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev);
+ if (ret) {
+ pr_err("unable to get I2C bus. ret %d\n", ret);
+ return ret;
+ }
+ ret = dm_i2c_reg_read(dev, reg);
+ if (ret < 0) {
+ pr_err("reading from palmas failed. ret %d\n", ret);
+ return ret;
+ }
+ *valp = (u8)ret;
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/drivers/power/pmic/Kconfig b/roms/u-boot/drivers/power/pmic/Kconfig
new file mode 100644
index 000000000..583fd3ddc
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/Kconfig
@@ -0,0 +1,334 @@
+config DM_PMIC
+ bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)"
+ depends on DM
+ ---help---
+ This config enables the driver-model PMIC support.
+ UCLASS_PMIC - designed to provide an I/O interface for PMIC devices.
+ For the multi-function PMIC devices, this can be used as parent I/O
+ device for each IC's interface. Then, each children uses its parent
+ for read/write. For detailed description, please refer to the files:
+ - 'drivers/power/pmic/pmic-uclass.c'
+ - 'include/power/pmic.h'
+
+config PMIC_CHILDREN
+ bool "Allow child devices for PMICs"
+ depends on DM_PMIC
+ default y
+ ---help---
+ This allows PMICs to support child devices (such as regulators) in
+ SPL. This adds quite a bit of code so if you are not using this
+ feature you can turn it off. Most likely you should turn it on for
+ U-Boot proper.
+
+config SPL_PMIC_CHILDREN
+ bool "Allow child devices for PMICs in SPL"
+ depends on DM_PMIC
+ default y
+ ---help---
+ This allows PMICs to support child devices (such as regulators) in
+ SPL. This adds quite a bit of code so if you are not using this
+ feature you can turn it off. In this case you may need a 'back door'
+ to call your regulator code (e.g. see rk8xx.c for direct functions
+ for use in SPL).
+
+config PMIC_ACT8846
+ bool "Enable support for the active-semi 8846 PMIC"
+ depends on DM_PMIC && DM_I2C
+ ---help---
+ This PMIC includes 4 DC/DC step-down buck regulators and 8 low-dropout
+ regulators (LDOs). It also provides some GPIO, reset and battery
+ functions. It uses an I2C interface and is designed for use with
+ tablets and smartphones.
+
+config DM_PMIC_DA9063
+ bool "Enable Driver Model for the Dialog DA9063 PMIC"
+ depends on DM_PMIC
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC DA9063. The driver implements read/write operations.
+
+config SPL_DM_PMIC_DA9063
+ bool "Enable Driver Model for the Dialog DA9063 PMIC in SPL"
+ depends on DM_PMIC && SPL
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC DA9063. The driver implements read/write operations.
+
+config PMIC_AS3722
+ bool "Enable support for the Austria Micro Systems (AMS) AS7322 PMIC"
+ help
+ The AS3722 includes 7 DC/DC buck convertors, 11 low-noise LDOs, a
+ real-time clock, GPIOs, ADC and a few other features. It uses an I2C
+ interface and is designs to cover most of the power managementment
+ required for a tablets or laptop.
+
+config DM_PMIC_BD71837
+ bool "Enable Driver Model for PMIC BD71837"
+ depends on DM_PMIC
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC BD71837. The driver implements read/write operations.
+
+config SPL_DM_PMIC_BD71837
+ bool "Enable Driver Model for PMIC BD71837 in SPL stage"
+ depends on DM_PMIC
+ help
+ This config enables implementation of driver-model pmic uclass
+ features for PMIC BD71837. The driver implements read/write
+ operations.
+
+config DM_PMIC_FAN53555
+ bool "Enable support for OnSemi FAN53555"
+ depends on DM_PMIC && DM_REGULATOR && DM_I2C
+ select DM_REGULATOR_FAN53555
+ help
+ This config enables implementation of driver-model PMIC
+ 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 read/write operations for use with the FAN53555
+ regulator driver and binds the regulator driver to its node.
+
+config DM_PMIC_MP5416
+ bool "Enable Driver Model for PMIC MP5416"
+ depends on DM_PMIC
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC MP5416. The driver implements read/write operations.
+
+config SPL_DM_PMIC_MP5416
+ bool "Enable Driver Model for PMIC MP5416 in SPL stage"
+ depends on DM_PMIC
+ help
+ This config enables implementation of driver-model pmic uclass
+ features for PMIC MP5416. The driver implements read/write
+ operations.
+
+config DM_PMIC_PCA9450
+ bool "Enable Driver Model for PMIC PCA9450"
+ depends on DM_PMIC
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC PCA9450. The driver implements read/write operations.
+
+config SPL_DM_PMIC_PCA9450
+ bool "Enable Driver Model for PMIC PCA9450"
+ depends on DM_PMIC
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC PCA9450 in SPL. The driver implements read/write operations.
+
+config DM_PMIC_PFUZE100
+ bool "Enable Driver Model for PMIC PFUZE100"
+ depends on DM_PMIC
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC PFUZE100. The driver implements read/write operations.
+
+config SPL_DM_PMIC_PFUZE100
+ bool "Enable Driver Model for PMIC PFUZE100 in SPL"
+ depends on DM_PMIC
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC PFUZE100 in SPL. The driver implements read/write operations.
+
+config DM_PMIC_MAX77686
+ bool "Enable Driver Model for PMIC MAX77686"
+ depends on DM_PMIC
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC MAX77686. The driver implements read/write operations.
+
+config DM_PMIC_MAX8998
+ bool "Enable Driver Model for PMIC MAX8998"
+ depends on DM_PMIC
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC MAX8998. The driver implements read/write operations.
+
+config DM_PMIC_MC34708
+ bool "Enable Driver Model for PMIC MC34708"
+ depends on DM_PMIC
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC MC34708. The driver implements read/write operations.
+
+config PMIC_MAX8997
+ bool "Enable Driver Model for PMIC MAX8997"
+ depends on DM_PMIC
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC MAX8997. The driver implements read/write operations.
+ This is a Power Management IC with RTC, Fuel Gauge, MUIC control on Chip.
+ - 21x LDOs
+ - 12x GPIOs
+ - Haptic Motor driver
+ - RTC with two alarms
+ - Fueal Gauge and One backup battery charger
+ - MUIC
+ - Others
+
+config PMIC_PM8916
+ bool "Enable Driver Model for Qualcomm PM8916 PMIC"
+ depends on DM_PMIC
+ ---help---
+ The PM8916 is a PMIC connected to one (or several) processors
+ with SPMI bus. It has 2 slaves with several peripherals:
+ - 18x LDO
+ - 4x GPIO
+ - Power and Reset buttons
+ - Watchdog
+ - RTC
+ - Vibrator drivers
+ - Others
+
+ Driver binding info: doc/device-tree-bindings/pmic/pm8916.txt
+
+config PMIC_RK8XX
+ bool "Enable support for Rockchip PMIC RK8XX"
+ depends on DM_PMIC
+ ---help---
+ The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs,
+ an RTC and two low Rds (resistance (drain to source)) switches. It is
+ accessed via an I2C interface. The device is used with Rockchip SoCs.
+ This driver implements register read/write operations.
+
+config PMIC_S2MPS11
+ bool "Enable Driver Model for PMIC Samsung S2MPS11"
+ depends on DM_PMIC
+ ---help---
+ The Samsung S2MPS11 PMIC provides:
+ - 38 adjustable LDO regulators
+ - 9 High-Efficiency Buck Converters
+ - 1 BuckBoost Converter
+ - RTC with two alarms
+ - Backup battery charger
+ - I2C Configuration Interface
+ This driver provides access to I/O interface only.
+ Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
+
+config DM_PMIC_SANDBOX
+ bool "Enable Driver Model for emulated Sandbox PMIC"
+ depends on DM_PMIC
+ ---help---
+ Enable the driver for Sandbox PMIC emulation. The emulated PMIC device
+ depends on two drivers:
+ - sandbox PMIC I/O driver - implements dm pmic operations
+ - sandbox PMIC i2c emul driver - emulates the PMIC's I2C transmission
+
+ A detailed information can be found in header: '<power/sandbox_pmic.h>'
+
+ 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)
+
+ Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt
+
+config PMIC_S5M8767
+ bool "Enable Driver Model for the Samsung S5M8767 PMIC"
+ depends on DM_PMIC
+ ---help---
+ The S5M8767 PMIC provides a large array of LDOs and BUCKs for use
+ as a SoC power controller. It also provides 32KHz clock outputs. This
+ driver provides basic register access and sets up the attached
+ regulators if regulator support is enabled.
+
+config PMIC_RN5T567
+ bool "Enable driver for Ricoh RN5T567 PMIC"
+ depends on DM_PMIC
+ ---help---
+ The RN5T567 is a PMIC with 4 step-down DC/DC converters, 5 LDO
+ regulators Real-Time Clock and 4 GPIOs. This driver provides
+ register access only.
+
+config PMIC_TPS65090
+ bool "Enable driver for Texas Instruments TPS65090 PMIC"
+ depends on DM_PMIC
+ ---help---
+ The TPS65090 is a PMIC containing several LDOs, DC to DC convertors,
+ FETs and a battery charger. This driver provides register access
+ only, and you can enable the regulator/charger drivers separately if
+ required.
+
+config PMIC_PALMAS
+ bool "Enable driver for Texas Instruments PALMAS PMIC"
+ depends on DM_PMIC
+ ---help---
+ The PALMAS is a PMIC containing several LDOs, SMPS.
+ This driver binds the pmic children.
+
+config PMIC_LP873X
+ bool "Enable driver for Texas Instruments LP873X PMIC"
+ depends on DM_PMIC
+ ---help---
+ The LP873X is a PMIC containing couple of LDOs and couple of SMPS.
+ This driver binds the pmic children.
+
+config PMIC_LP87565
+ bool "Enable driver for Texas Instruments LP87565 PMIC"
+ depends on DM_PMIC
+ ---help---
+ The LP87565 is a PMIC containing a bunch of SMPS.
+ This driver binds the pmic children.
+
+config POWER_MC34VR500
+ bool "Enable driver for Freescale MC34VR500 PMIC"
+ ---help---
+ The MC34VR500 is used in conjunction with the FSL T1 and LS1 series
+ SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed
+ via an I2C interface.
+
+config DM_PMIC_TPS65910
+ bool "Enable driver for Texas Instruments TPS65910 PMIC"
+ depends on DM_PMIC
+ ---help---
+ The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost
+ DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO
+ pmic children.
+
+config PMIC_STPMIC1
+ bool "Enable support for STMicroelectronics STPMIC1 PMIC"
+ depends on DM_PMIC && DM_I2C
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF && !ARM_PSCI_FW
+ ---help---
+ The STPMIC1 PMIC provides 4 BUCKs, 6 LDOs, 1 VREF and 2 power switches.
+ It is accessed via an I2C interface. The device is used with STM32MP1
+ SoCs. This driver implements register read/write operations.
+
+config SPL_PMIC_PALMAS
+ bool "Enable driver for Texas Instruments PALMAS PMIC"
+ depends on DM_PMIC
+ help
+ The PALMAS is a PMIC containing several LDOs, SMPS.
+ This driver binds the pmic children in SPL.
+
+config SPL_PMIC_LP873X
+ bool "Enable driver for Texas Instruments LP873X PMIC"
+ depends on DM_PMIC
+ help
+ The LP873X is a PMIC containing couple of LDOs and couple of SMPS.
+ This driver binds the pmic children in SPL.
+
+config SPL_PMIC_LP87565
+ bool "Enable driver for Texas Instruments LP87565 PMIC"
+ depends on DM_PMIC
+ help
+ The LP87565 is a PMIC containing a bunch of SMPS.
+ This driver binds the pmic children in SPL.
+
+config PMIC_TPS65941
+ bool "Enable driver for Texas Instruments TPS65941 PMIC"
+ depends on DM_PMIC
+ help
+ The TPS65941 is a PMIC containing a bunch of SMPS & LDOs.
+ This driver binds the pmic children.
diff --git a/roms/u-boot/drivers/power/pmic/Makefile b/roms/u-boot/drivers/power/pmic/Makefile
new file mode 100644
index 000000000..89099fde5
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/Makefile
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2012 Samsung Electronics
+# Lukasz Majewski <l.majewski@samsung.com>
+
+obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
+obj-$(CONFIG_DM_PMIC_FAN53555) += fan53555.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_DA9063) += da9063.o
+obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o
+obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o
+obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_BD71837) += bd71837.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_MP5416) += mp5416.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o
+obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
+obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
+obj-$(CONFIG_PMIC_ACT8846) += act8846.o
+obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
+obj-$(CONFIG_PMIC_MAX8997) += max8997.o
+obj-$(CONFIG_PMIC_PM8916) += pm8916.o
+obj-$(CONFIG_PMIC_RK8XX) += rk8xx.o
+obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o
+obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
+obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
+obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o
+obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o
+obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
+obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o
+obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o
+
+obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
+obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
+obj-$(CONFIG_POWER_PCA9450) += pmic_pca9450.o
+obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o
+obj-$(CONFIG_POWER_PFUZE3000) += pmic_pfuze3000.o
+obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o
+obj-$(CONFIG_POWER_TPS65218) += pmic_tps62362.o
+obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o
+obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o
+obj-$(CONFIG_POWER_HI6553) += pmic_hi6553.o
+obj-$(CONFIG_POWER_MC34VR500) += pmic_mc34vr500.o
+obj-$(CONFIG_PMIC_TPS65941) += tps65941.o
diff --git a/roms/u-boot/drivers/power/pmic/act8846.c b/roms/u-boot/drivers/power/pmic/act8846.c
new file mode 100644
index 000000000..8f0f5a6d9
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/act8846.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <linux/libfdt.h>
+#include <power/act8846_pmic.h>
+#include <power/pmic.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "REG", .driver = "act8846_reg"},
+ { },
+};
+
+static int act8846_reg_count(struct udevice *dev)
+{
+ return ACT8846_NUM_OF_REGS;
+}
+
+static int act8846_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ debug("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int act8846_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ debug("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int act8846_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops act8846_ops = {
+ .reg_count = act8846_reg_count,
+ .read = act8846_read,
+ .write = act8846_write,
+};
+
+static const struct udevice_id act8846_ids[] = {
+ { .compatible = "active-semi,act8846" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_act8846) = {
+ .name = "act8846 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = act8846_ids,
+ .bind = act8846_bind,
+ .ops = &act8846_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/as3722.c b/roms/u-boot/drivers/power/pmic/as3722.c
new file mode 100644
index 000000000..3aa3cce94
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/as3722.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 NVIDIA Corporation
+ */
+
+#define pr_fmt(fmt) "as3722: " fmt
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <log.h>
+#include <dm/lists.h>
+#include <power/as3722.h>
+#include <power/pmic.h>
+
+#define AS3722_NUM_OF_REGS 0x92
+
+static int as3722_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int as3722_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int as3722_read_id(struct udevice *dev, uint *idp, uint *revisionp)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev, AS3722_ASIC_ID1);
+ if (ret < 0) {
+ pr_err("failed to read ID1 register: %d\n", ret);
+ return ret;
+ }
+ *idp = ret;
+
+ ret = pmic_reg_read(dev, AS3722_ASIC_ID2);
+ if (ret < 0) {
+ pr_err("failed to read ID2 register: %d\n", ret);
+ return ret;
+ }
+ *revisionp = ret;
+
+ return 0;
+}
+
+/* TODO(treding@nvidia.com): Add proper regulator support to avoid this */
+int as3722_sd_set_voltage(struct udevice *dev, unsigned int sd, u8 value)
+{
+ int ret;
+
+ if (sd > 6)
+ return -EINVAL;
+
+ ret = pmic_reg_write(dev, AS3722_SD_VOLTAGE(sd), value);
+ if (ret < 0) {
+ pr_err("failed to write SD%u voltage register: %d\n", sd, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int as3722_ldo_set_voltage(struct udevice *dev, unsigned int ldo, u8 value)
+{
+ int ret;
+
+ if (ldo > 11)
+ return -EINVAL;
+
+ ret = pmic_reg_write(dev, AS3722_LDO_VOLTAGE(ldo), value);
+ if (ret < 0) {
+ pr_err("failed to write LDO%u voltage register: %d\n", ldo,
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int as3722_probe(struct udevice *dev)
+{
+ uint id, revision;
+ int ret;
+
+ ret = as3722_read_id(dev, &id, &revision);
+ if (ret < 0) {
+ pr_err("failed to read ID: %d\n", ret);
+ return ret;
+ }
+
+ if (id != AS3722_DEVICE_ID) {
+ pr_err("unknown device\n");
+ return -ENOENT;
+ }
+
+ debug("AS3722 revision %#x found on I2C bus %s\n", revision, dev->name);
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "sd", .driver = "as3722_stepdown"},
+ { .prefix = "ldo", .driver = "as3722_ldo"},
+ { },
+};
+
+static int as3722_bind(struct udevice *dev)
+{
+ struct udevice *gpio_dev;
+ ofnode regulators_node;
+ int children;
+ int ret;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+ ret = device_bind_driver(dev, "gpio_as3722", "gpio_as3722", &gpio_dev);
+ if (ret) {
+ debug("%s: Cannot bind GPIOs (ret=%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static int as3722_reg_count(struct udevice *dev)
+{
+ return AS3722_NUM_OF_REGS;
+}
+
+static struct dm_pmic_ops as3722_ops = {
+ .reg_count = as3722_reg_count,
+ .read = as3722_read,
+ .write = as3722_write,
+};
+
+static const struct udevice_id as3722_ids[] = {
+ { .compatible = "ams,as3722" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_as3722) = {
+ .name = "as3722_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = as3722_ids,
+#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
+ .bind = as3722_bind,
+#endif
+ .probe = as3722_probe,
+ .ops = &as3722_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/as3722_gpio.c b/roms/u-boot/drivers/power/pmic/as3722_gpio.c
new file mode 100644
index 000000000..96943bc1a
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/as3722_gpio.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 NVIDIA Corporation
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <power/as3722.h>
+#include <power/pmic.h>
+
+#define NUM_GPIOS 8
+
+int as3722_gpio_configure(struct udevice *pmic, unsigned int gpio,
+ unsigned long flags)
+{
+ u8 value = 0;
+ int err;
+
+ if (flags & AS3722_GPIO_OUTPUT_VDDH)
+ value |= AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH;
+
+ if (flags & AS3722_GPIO_INVERT)
+ value |= AS3722_GPIO_CONTROL_INVERT;
+
+ err = pmic_reg_write(pmic, AS3722_GPIO_CONTROL(gpio), value);
+ if (err) {
+ pr_err("failed to configure GPIO#%u: %d\n", gpio, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int as3722_gpio_set_value(struct udevice *dev, unsigned int gpio,
+ int level)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ const char *l;
+ u8 value;
+ int err;
+
+ if (gpio >= NUM_GPIOS)
+ return -EINVAL;
+
+ err = pmic_reg_read(pmic, AS3722_GPIO_SIGNAL_OUT);
+ if (err < 0) {
+ pr_err("failed to read GPIO signal out register: %d\n", err);
+ return err;
+ }
+ value = err;
+
+ if (level == 0) {
+ value &= ~(1 << gpio);
+ l = "low";
+ } else {
+ value |= 1 << gpio;
+ l = "high";
+ }
+
+ err = pmic_reg_write(pmic, AS3722_GPIO_SIGNAL_OUT, value);
+ if (err) {
+ pr_err("failed to set GPIO#%u %s: %d\n", gpio, l, err);
+ return err;
+ }
+
+ return 0;
+}
+
+int as3722_gpio_direction_output(struct udevice *dev, unsigned int gpio,
+ int value)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ int err;
+
+ if (gpio > 7)
+ return -EINVAL;
+
+ if (value == 0)
+ value = AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDL;
+ else
+ value = AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH;
+
+ err = pmic_reg_write(pmic, AS3722_GPIO_CONTROL(gpio), value);
+ if (err) {
+ pr_err("failed to configure GPIO#%u as output: %d\n", gpio,
+ err);
+ return err;
+ }
+
+ err = as3722_gpio_set_value(pmic, gpio, value);
+ if (err < 0) {
+ pr_err("failed to set GPIO#%u high: %d\n", gpio, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int as3722_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->gpio_count = NUM_GPIOS;
+ uc_priv->bank_name = "as3722_";
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_as3722_ops = {
+ .direction_output = as3722_gpio_direction_output,
+ .set_value = as3722_gpio_set_value,
+};
+
+U_BOOT_DRIVER(gpio_as3722) = {
+ .name = "gpio_as3722",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_as3722_ops,
+ .probe = as3722_gpio_probe,
+};
diff --git a/roms/u-boot/drivers/power/pmic/bd71837.c b/roms/u-boot/drivers/power/pmic/bd71837.c
new file mode 100644
index 000000000..cb9238972
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/bd71837.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/bd71837.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+ /* buck */
+ { .prefix = "b", .driver = BD718XX_REGULATOR_DRIVER},
+ /* ldo */
+ { .prefix = "l", .driver = BD718XX_REGULATOR_DRIVER},
+ { },
+};
+
+static int bd71837_reg_count(struct udevice *dev)
+{
+ return BD718XX_MAX_REGISTER - 1;
+}
+
+static int bd71837_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int bd71837_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int bd71837_bind(struct udevice *dev)
+{
+ int children;
+ ofnode regulators_node;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static int bd718x7_probe(struct udevice *dev)
+{
+ int ret;
+ uint8_t mask = BD718XX_REGLOCK_PWRSEQ | BD718XX_REGLOCK_VREG;
+
+ /* Unlock the PMIC regulator control before probing the children */
+ ret = pmic_clrsetbits(dev, BD718XX_REGLOCK, mask, 0);
+ if (ret) {
+ debug("%s: %s Failed to unlock regulator control\n", __func__,
+ dev->name);
+ return ret;
+ }
+ debug("%s: '%s' - BD718x7 PMIC registers unlocked\n", __func__,
+ dev->name);
+
+ return 0;
+}
+
+static struct dm_pmic_ops bd71837_ops = {
+ .reg_count = bd71837_reg_count,
+ .read = bd71837_read,
+ .write = bd71837_write,
+};
+
+static const struct udevice_id bd71837_ids[] = {
+ { .compatible = "rohm,bd71837", .data = ROHM_CHIP_TYPE_BD71837, },
+ { .compatible = "rohm,bd71847", .data = ROHM_CHIP_TYPE_BD71847, },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_bd71837) = {
+ .name = "bd71837 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = bd71837_ids,
+ .bind = bd71837_bind,
+ .probe = bd718x7_probe,
+ .ops = &bd71837_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/da9063.c b/roms/u-boot/drivers/power/pmic/da9063.c
new file mode 100644
index 000000000..25101d18f
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/da9063.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Flowbird
+ * Martin Fuzzey <martin.fuzzey@flowbird.group>
+ */
+
+#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/da9063_pmic.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = DA9063_LDO_DRIVER },
+ { .prefix = "b", .driver = DA9063_BUCK_DRIVER },
+ { },
+};
+
+/*
+ * The register map is non contiguous and attempts to read in the holes fail.
+ * But "pmic dump" tries to dump the full register map.
+ * So define the holes here so we can fix that.
+ */
+struct da9063_reg_hole {
+ u16 first;
+ u16 last;
+};
+
+static const struct da9063_reg_hole da9063_reg_holes[] = {
+ DA9063_REG_HOLE_1,
+ DA9063_REG_HOLE_2,
+ DA9063_REG_HOLE_3,
+ /* These aren't readable. I can't see why from the datasheet but
+ * attempts to read fail and the kernel marks them unreadable too,
+ */
+ {DA9063_REG_OTP_COUNT, DA9063_REG_OTP_DATA},
+};
+
+static int da9063_reg_count(struct udevice *dev)
+{
+ return DA9063_NUM_OF_REGS;
+}
+
+static bool da9063_reg_valid(uint reg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(da9063_reg_holes); i++) {
+ const struct da9063_reg_hole *hole = &da9063_reg_holes[i];
+
+ if (reg >= hole->first && reg <= hole->last)
+ return false;
+ }
+
+ return true;
+}
+
+static int da9063_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int da9063_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (!da9063_reg_valid(reg))
+ return -ENODATA;
+
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int da9063_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static int da9063_probe(struct udevice *dev)
+{
+ return i2c_set_chip_addr_offset_mask(dev, 0x1);
+}
+
+static struct dm_pmic_ops da9063_ops = {
+ .reg_count = da9063_reg_count,
+ .read = da9063_read,
+ .write = da9063_write,
+};
+
+static const struct udevice_id da9063_ids[] = {
+ { .compatible = "dlg,da9063" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_da9063) = {
+ .name = "da9063_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = da9063_ids,
+ .bind = da9063_bind,
+ .probe = da9063_probe,
+ .ops = &da9063_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/fan53555.c b/roms/u-boot/drivers/power/pmic/fan53555.c
new file mode 100644
index 000000000..4d1e686d2
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/fan53555.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) 2018 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <i2c.h>
+#include <power/fan53555.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+static int pmic_fan53555_reg_count(struct udevice *dev)
+{
+ return 1;
+};
+
+static int pmic_fan53555_read(struct udevice *dev, uint reg,
+ u8 *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("%s: read error for register: %#x!", dev->name, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pmic_fan53555_write(struct udevice *dev, uint reg,
+ const u8 *buff, int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("%s: write error for register: %#x!", dev->name, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pmic_fan53555_bind(struct udevice *dev)
+{
+ /*
+ * The FAN53555 has only a single regulator and therefore doesn't
+ * have a subnode. So we have to rebind a child device (the one
+ * regulator) here.
+ */
+
+ const char *regulator_driver_name = "fan53555_regulator";
+ struct udevice *child;
+ struct driver *drv;
+
+ debug("%s\n", __func__);
+
+ drv = lists_driver_lookup_name(regulator_driver_name);
+ if (!drv) {
+ dev_err(dev, "no driver '%s'\n", regulator_driver_name);
+ return -ENOENT;
+ }
+
+ return device_bind_with_driver_data(dev, drv, "SW", dev->driver_data,
+ dev_ofnode(dev), &child);
+};
+
+static struct dm_pmic_ops pmic_fan53555_ops = {
+ .reg_count = pmic_fan53555_reg_count,
+ .read = pmic_fan53555_read,
+ .write = pmic_fan53555_write,
+};
+
+static const struct udevice_id pmic_fan53555_match[] = {
+ { .compatible = "fcs,fan53555", .data = FAN53555_VENDOR_FAIRCHILD, },
+ { .compatible = "silergy,syr827", .data = FAN53555_VENDOR_SILERGY, },
+ { .compatible = "silergy,syr828", .data = FAN53555_VENDOR_SILERGY, },
+ { },
+};
+
+U_BOOT_DRIVER(pmic_fan53555) = {
+ .name = "pmic_fan53555",
+ .id = UCLASS_PMIC,
+ .of_match = pmic_fan53555_match,
+ .bind = pmic_fan53555_bind,
+ .ops = &pmic_fan53555_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/i2c_pmic_emul.c b/roms/u-boot/drivers/power/pmic/i2c_pmic_emul.c
new file mode 100644
index 000000000..abe3a1051
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/i2c_pmic_emul.c
@@ -0,0 +1,166 @@
+// 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 <i2c.h>
+#include <log.h>
+#include <malloc.h>
+#include <power/pmic.h>
+#include <power/sandbox_pmic.h>
+
+/**
+ * struct sandbox_i2c_pmic_plat_data - platform data for the PMIC
+ *
+ * @rw_reg: PMICs register of the chip I/O transaction
+ * @reg: PMICs registers array
+ */
+struct sandbox_i2c_pmic_plat_data {
+ u8 rw_reg, rw_idx;
+ u8 reg_count;
+ u8 trans_len;
+ u8 buf_size;
+ u8 *reg;
+};
+
+static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip,
+ uchar *buffer, int len)
+{
+ struct sandbox_i2c_pmic_plat_data *plat = dev_get_plat(emul);
+
+ if (plat->rw_idx + len > plat->buf_size) {
+ pr_err("Request exceeds PMIC register range! Max register: %#x",
+ plat->reg_count);
+ return -EFAULT;
+ }
+
+ debug("Read PMIC: %#x at register: %#x idx: %#x count: %d\n",
+ (unsigned int)chip & 0xff, plat->rw_reg, plat->rw_idx, len);
+
+ memcpy(buffer, plat->reg + plat->rw_idx, len);
+
+ return 0;
+}
+
+static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip,
+ uchar *buffer, int len,
+ bool next_is_read)
+{
+ struct sandbox_i2c_pmic_plat_data *plat = dev_get_plat(emul);
+
+ /* Probe only */
+ if (!len)
+ return 0;
+
+ /* Set PMIC register for I/O */
+ plat->rw_reg = *buffer;
+ plat->rw_idx = plat->rw_reg * plat->trans_len;
+
+ debug("Write PMIC: %#x at register: %#x idx: %#x count: %d\n",
+ (unsigned int)chip & 0xff, plat->rw_reg, plat->rw_idx, len);
+
+ /* For read operation, set (write) only chip reg */
+ if (next_is_read)
+ return 0;
+
+ buffer++;
+ len--;
+
+ if (plat->rw_idx + len > plat->buf_size) {
+ pr_err("Request exceeds PMIC register range! Max register: %#x",
+ plat->reg_count);
+ }
+
+ memcpy(plat->reg + plat->rw_idx, buffer, len);
+
+ return 0;
+}
+
+static int sandbox_i2c_pmic_xfer(struct udevice *emul, struct i2c_msg *msg,
+ int nmsgs)
+{
+ int ret = 0;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+ if (msg->flags & I2C_M_RD) {
+ ret = sandbox_i2c_pmic_read_data(emul, msg->addr,
+ msg->buf, msg->len);
+ } else {
+ ret = sandbox_i2c_pmic_write_data(emul, msg->addr,
+ msg->buf, msg->len,
+ next_is_read);
+ }
+
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int sandbox_i2c_pmic_of_to_plat(struct udevice *emul)
+{
+ struct sandbox_i2c_pmic_plat_data *plat = dev_get_plat(emul);
+ struct udevice *pmic_dev = i2c_emul_get_device(emul);
+
+ debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__);
+ plat->reg_count = pmic_reg_count(pmic_dev);
+
+ return 0;
+}
+
+static int sandbox_i2c_pmic_probe(struct udevice *emul)
+{
+ struct sandbox_i2c_pmic_plat_data *plat = dev_get_plat(emul);
+ struct udevice *pmic_dev = i2c_emul_get_device(emul);
+ struct uc_pmic_priv *upriv = dev_get_uclass_priv(pmic_dev);
+ const u8 *reg_defaults;
+
+ plat->trans_len = upriv->trans_len;
+ plat->buf_size = plat->reg_count * plat->trans_len;
+
+ plat->reg = calloc(1, plat->buf_size);
+ if (!plat->reg) {
+ debug("Canot allocate memory (%d B) for PMIC I2C emulation!\n",
+ plat->buf_size);
+ return -ENOMEM;
+ }
+
+ reg_defaults = dev_read_u8_array_ptr(emul, "reg-defaults",
+ plat->buf_size);
+
+ if (!reg_defaults) {
+ pr_err("Property \"reg-defaults\" not found for device: %s!",
+ emul->name);
+ free(plat->reg);
+ return -EINVAL;
+ }
+
+ memcpy(plat->reg, reg_defaults, plat->buf_size);
+
+ return 0;
+}
+
+struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = {
+ .xfer = sandbox_i2c_pmic_xfer,
+};
+
+static const struct udevice_id sandbox_i2c_pmic_ids[] = {
+ { .compatible = "sandbox,i2c-pmic" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_pmic_emul) = {
+ .name = "sandbox_i2c_pmic_emul",
+ .id = UCLASS_I2C_EMUL,
+ .of_match = sandbox_i2c_pmic_ids,
+ .of_to_plat = sandbox_i2c_pmic_of_to_plat,
+ .probe = sandbox_i2c_pmic_probe,
+ .plat_auto = sizeof(struct sandbox_i2c_pmic_plat_data),
+ .ops = &sandbox_i2c_pmic_emul_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/lp873x.c b/roms/u-boot/drivers/power/pmic/lp873x.c
new file mode 100644
index 000000000..2b1260ec6
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/lp873x.c
@@ -0,0 +1,82 @@
+// 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 <power/pmic.h>
+#include <power/regulator.h>
+#include <power/lp873x.h>
+#include <dm/device.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = LP873X_LDO_DRIVER },
+ { .prefix = "buck", .driver = LP873X_BUCK_DRIVER },
+ { },
+};
+
+static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int lp873x_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int lp873x_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ printf("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops lp873x_ops = {
+ .read = lp873x_read,
+ .write = lp873x_write,
+};
+
+static const struct udevice_id lp873x_ids[] = {
+ { .compatible = "ti,lp8732", .data = LP8732 },
+ { .compatible = "ti,lp8733" , .data = LP8733 },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_lp873x) = {
+ .name = "lp873x_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = lp873x_ids,
+ .bind = lp873x_bind,
+ .ops = &lp873x_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/lp87565.c b/roms/u-boot/drivers/power/pmic/lp87565.c
new file mode 100644
index 000000000..f4a4bd03d
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/lp87565.c
@@ -0,0 +1,85 @@
+// 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>
+#include <dm/device.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "buck", .driver = LP87565_BUCK_DRIVER },
+ { },
+};
+
+static int lp87565_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret)
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static int lp87565_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret)
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static int lp87565_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ printf("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops lp87565_ops = {
+ .read = lp87565_read,
+ .write = lp87565_write,
+};
+
+static const struct udevice_id lp87565_ids[] = {
+ { .compatible = "ti,lp87565", .data = LP87565 },
+ { .compatible = "ti,lp87565-q1", .data = LP87565_Q1 },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_lp87565) = {
+ .name = "lp87565_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = lp87565_ids,
+ .bind = lp87565_bind,
+ .ops = &lp87565_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/max77686.c b/roms/u-boot/drivers/power/pmic/max77686.c
new file mode 100644
index 000000000..9f02c0b6f
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/max77686.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014-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 <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/max77686_pmic.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "LDO", .driver = MAX77686_LDO_DRIVER },
+ { .prefix = "BUCK", .driver = MAX77686_BUCK_DRIVER },
+ { },
+};
+
+static int max77686_reg_count(struct udevice *dev)
+{
+ return MAX77686_NUM_OF_REGS;
+}
+
+static int max77686_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int max77686_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int max77686_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "voltage-regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops max77686_ops = {
+ .reg_count = max77686_reg_count,
+ .read = max77686_read,
+ .write = max77686_write,
+};
+
+static const struct udevice_id max77686_ids[] = {
+ { .compatible = "maxim,max77686" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_max77686) = {
+ .name = "max77686_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = max77686_ids,
+ .bind = max77686_bind,
+ .ops = &max77686_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/max8997.c b/roms/u-boot/drivers/power/pmic/max8997.c
new file mode 100644
index 000000000..dbae155fb
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/max8997.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Samsung Electronics
+ * Jaehoon Chung <jh80.chung@samsung.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/max8997_pmic.h>
+#include <errno.h>
+
+static int max8997_reg_count(struct udevice *dev)
+{
+ return PMIC_NUM_OF_REGS;
+}
+
+static int max8997_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret)
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static int max8997_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret)
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static struct dm_pmic_ops max8997_ops = {
+ .reg_count = max8997_reg_count,
+ .read = max8997_read,
+ .write = max8997_write,
+};
+
+static const struct udevice_id max8997_ids[] = {
+ { .compatible = "maxim,max8997" },
+ { },
+};
+
+U_BOOT_DRIVER(pmic_max8997) = {
+ .name = "max8997_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = max8997_ids,
+ .ops = &max8997_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/max8998.c b/roms/u-boot/drivers/power/pmic/max8998.c
new file mode 100644
index 000000000..f58d9f2d7
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/max8998.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Samsung Electronics
+ * Jaehoon Chung <jh80.chung@samsung.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/max8998_pmic.h>
+
+static int max8998_reg_count(struct udevice *dev)
+{
+ return PMIC_NUM_OF_REGS;
+}
+
+static int max8998_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret)
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static int max8998_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret)
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static struct dm_pmic_ops max8998_ops = {
+ .reg_count = max8998_reg_count,
+ .read = max8998_read,
+ .write = max8998_write,
+};
+
+static const struct udevice_id max8998_ids[] = {
+ { .compatible = "maxim,max8998" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_max8998) = {
+ .name = "max8998_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = max8998_ids,
+ .ops = &max8998_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/mc34708.c b/roms/u-boot/drivers/power/pmic/mc34708.c
new file mode 100644
index 000000000..40d732224
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/mc34708.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fsl_pmic.h>
+#include <i2c.h>
+#include <asm/global_data.h>
+#include <power/pmic.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int mc34708_reg_count(struct udevice *dev)
+{
+ return PMIC_NUM_OF_REGS;
+}
+
+static int mc34708_write(struct udevice *dev, uint reg, const u8 *buff,
+ int len)
+{
+ u8 buf[3] = { 0 };
+ int ret;
+
+ if (len != MC34708_TRANSFER_SIZE)
+ return -EINVAL;
+
+ /*
+ * The MC34708 sends data with big endian format, hence we need to
+ * perform manual byte swap.
+ */
+ buf[0] = buff[2];
+ buf[1] = buff[1];
+ buf[2] = buff[0];
+
+ ret = dm_i2c_write(dev, reg, buf, len);
+ if (ret)
+ printf("write error to device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static int mc34708_read(struct udevice *dev, uint reg, u8 *buff, int len)
+{
+ u8 buf[3] = { 0 };
+ int ret;
+
+ if (len != MC34708_TRANSFER_SIZE)
+ return -EINVAL;
+
+ ret = dm_i2c_read(dev, reg, buf, len);
+ if (ret)
+ printf("read error from device: %p register: %#x!\n", dev, reg);
+
+ buff[0] = buf[2];
+ buff[1] = buf[1];
+ buff[2] = buf[0];
+
+ return ret;
+}
+
+static int mc34708_probe(struct udevice *dev)
+{
+ struct uc_pmic_priv *priv = dev_get_uclass_priv(dev);
+
+ priv->trans_len = MC34708_TRANSFER_SIZE;
+
+ /*
+ * Handle PMIC Errata 37: APS mode not fully functional,
+ * use explicit PWM or PFM instead
+ */
+ pmic_clrsetbits(dev, MC34708_REG_SW12_OPMODE,
+ MC34708_SW1AMODE_MASK | MC34708_SW2MODE_MASK,
+ SW_MODE_PWMPWM | (SW_MODE_PWMPWM << 14u));
+
+ pmic_clrsetbits(dev, MC34708_REG_SW345_OPMODE,
+ MC34708_SW3MODE_MASK | MC34708_SW4AMODE_MASK |
+ MC34708_SW4BMODE_MASK | MC34708_SW5MODE_MASK,
+ SW_MODE_PWMPWM | (SW_MODE_PWMPWM << 6u) |
+ (SW_MODE_PWMPWM << 12u) | (SW_MODE_PWMPWM << 18u));
+
+ return 0;
+}
+
+static struct dm_pmic_ops mc34708_ops = {
+ .reg_count = mc34708_reg_count,
+ .read = mc34708_read,
+ .write = mc34708_write,
+};
+
+static const struct udevice_id mc34708_ids[] = {
+ { .compatible = "fsl,mc34708" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_mc34708) = {
+ .name = "mc34708_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = mc34708_ids,
+ .probe = mc34708_probe,
+ .ops = &mc34708_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/mp5416.c b/roms/u-boot/drivers/power/pmic/mp5416.c
new file mode 100644
index 000000000..6180adf77
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/mp5416.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 Gateworks Corporation
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/mp5416.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+ /* buck */
+ { .prefix = "b", .driver = MP6416_REGULATOR_DRIVER },
+ /* ldo */
+ { .prefix = "l", .driver = MP6416_REGULATOR_DRIVER },
+ { },
+};
+
+static int mp5416_reg_count(struct udevice *dev)
+{
+ return MP5416_NUM_OF_REGS - 1;
+}
+
+static int mp5416_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int mp5416_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int mp5416_bind(struct udevice *dev)
+{
+ int children;
+ ofnode regulators_node;
+
+ debug("%s %s\n", __func__, dev->name);
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static int mp5416_probe(struct udevice *dev)
+{
+ debug("%s %s\n", __func__, dev->name);
+
+ return 0;
+}
+
+static struct dm_pmic_ops mp5416_ops = {
+ .reg_count = mp5416_reg_count,
+ .read = mp5416_read,
+ .write = mp5416_write,
+};
+
+static const struct udevice_id mp5416_ids[] = {
+ { .compatible = "mps,mp5416", },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_mp5416) = {
+ .name = "mp5416 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = mp5416_ids,
+ .bind = mp5416_bind,
+ .probe = mp5416_probe,
+ .ops = &mp5416_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/muic_max8997.c b/roms/u-boot/drivers/power/pmic/muic_max8997.c
new file mode 100644
index 000000000..969ce9023
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/muic_max8997.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/power_chrg.h>
+#include <power/max8997_muic.h>
+#include <i2c.h>
+#include <errno.h>
+
+static int power_chrg_get_type(struct pmic *p)
+{
+ unsigned int val;
+ unsigned char charge_type, charger;
+
+ if (pmic_probe(p))
+ return CHARGER_NO;
+
+ pmic_reg_read(p, MAX8997_MUIC_STATUS2, &val);
+ charge_type = val & MAX8997_MUIC_CHG_MASK;
+
+ switch (charge_type) {
+ case MAX8997_MUIC_CHG_NO:
+ charger = CHARGER_NO;
+ break;
+ case MAX8997_MUIC_CHG_USB:
+ case MAX8997_MUIC_CHG_USB_D:
+ charger = CHARGER_USB;
+ break;
+ case MAX8997_MUIC_CHG_TA:
+ case MAX8997_MUIC_CHG_TA_1A:
+ charger = CHARGER_TA;
+ break;
+ case MAX8997_MUIC_CHG_TA_500:
+ charger = CHARGER_TA_500;
+ break;
+ default:
+ charger = CHARGER_UNKNOWN;
+ break;
+ }
+
+ return charger;
+}
+
+static struct power_chrg power_chrg_muic_ops = {
+ .chrg_type = power_chrg_get_type,
+};
+
+int power_muic_init(unsigned int bus)
+{
+ static const char name[] = "MAX8997_MUIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board Micro USB Interface Controller init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = MUIC_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX8997_MUIC_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ p->chrg = &power_chrg_muic_ops;
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/palmas.c b/roms/u-boot/drivers/power/pmic/palmas.c
new file mode 100644
index 000000000..6080cbff0
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/palmas.c
@@ -0,0 +1,100 @@
+// 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 <power/pmic.h>
+#include <power/regulator.h>
+#include <power/palmas.h>
+#include <dm/device.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = PALMAS_LDO_DRIVER },
+ { .prefix = "smps", .driver = PALMAS_SMPS_DRIVER },
+ { },
+};
+
+static int palmas_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int palmas_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int palmas_bind(struct udevice *dev)
+{
+ ofnode pmic_node = ofnode_null(), regulators_node;
+ ofnode subnode;
+ int children;
+
+ dev_for_each_subnode(subnode, dev) {
+ const char *name;
+ char *temp;
+
+ name = ofnode_get_name(subnode);
+ temp = strstr(name, "pmic");
+ if (temp) {
+ pmic_node = subnode;
+ break;
+ }
+ }
+
+ if (!ofnode_valid(pmic_node)) {
+ debug("%s: %s pmic subnode not found!\n", __func__, dev->name);
+ return -ENXIO;
+ }
+
+ regulators_node = ofnode_find_subnode(pmic_node, "regulators");
+
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s reg subnode not found!\n", __func__, dev->name);
+ return -ENXIO;
+ }
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops palmas_ops = {
+ .read = palmas_read,
+ .write = palmas_write,
+};
+
+static const struct udevice_id palmas_ids[] = {
+ { .compatible = "ti,tps659038", .data = TPS659038 },
+ { .compatible = "ti,tps65917" , .data = TPS65917 },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_palmas) = {
+ .name = "palmas_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = palmas_ids,
+ .bind = palmas_bind,
+ .ops = &palmas_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/pca9450.c b/roms/u-boot/drivers/power/pmic/pca9450.c
new file mode 100644
index 000000000..a886647f1
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pca9450.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/pca9450.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+ /* buck */
+ { .prefix = "b", .driver = PCA9450_REGULATOR_DRIVER},
+ /* ldo */
+ { .prefix = "l", .driver = PCA9450_REGULATOR_DRIVER},
+ { },
+};
+
+static int pca9450_reg_count(struct udevice *dev)
+{
+ return PCA9450_REG_NUM;
+}
+
+static int pca9450_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pca9450_read(struct udevice *dev, uint reg, uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pca9450_bind(struct udevice *dev)
+{
+ int children;
+ ofnode regulators_node;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node,
+ pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops pca9450_ops = {
+ .reg_count = pca9450_reg_count,
+ .read = pca9450_read,
+ .write = pca9450_write,
+};
+
+static const struct udevice_id pca9450_ids[] = {
+ { .compatible = "nxp,pca9450a", .data = 0x25, },
+ { .compatible = "nxp,pca9450b", .data = 0x25, },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_pca9450) = {
+ .name = "pca9450 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = pca9450_ids,
+ .bind = pca9450_bind,
+ .ops = &pca9450_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/pfuze100.c b/roms/u-boot/drivers/power/pmic/pfuze100.c
new file mode 100644
index 000000000..65c445697
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pfuze100.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc
+ * Peng Fan <Peng.Fan@freescale.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>
+#include <power/pfuze3000_pmic.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ /* sw[x], swbst */
+ { .prefix = "s", .driver = PFUZE100_REGULATOR_DRIVER },
+ /* vgen[x], vsnvs, vcc, v33, vcc_sd */
+ { .prefix = "v", .driver = PFUZE100_REGULATOR_DRIVER },
+ { },
+};
+
+static int pfuze100_reg_count(struct udevice *dev)
+{
+ return dev->driver_data == PFUZE3000 ? PFUZE3000_NUM_OF_REGS : PFUZE100_NUM_OF_REGS;
+}
+
+static int pfuze100_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pfuze100_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ debug("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pfuze100_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops pfuze100_ops = {
+ .reg_count = pfuze100_reg_count,
+ .read = pfuze100_read,
+ .write = pfuze100_write,
+};
+
+static const struct udevice_id pfuze100_ids[] = {
+ { .compatible = "fsl,pfuze100", .data = PFUZE100, },
+ { .compatible = "fsl,pfuze200", .data = PFUZE200, },
+ { .compatible = "fsl,pfuze3000", .data = PFUZE3000, },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_pfuze100) = {
+ .name = "pfuze100 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = pfuze100_ids,
+ .bind = pfuze100_bind,
+ .ops = &pfuze100_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/pm8916.c b/roms/u-boot/drivers/power/pmic/pm8916.c
new file mode 100644
index 000000000..5f4386d4a
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pm8916.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm pm8916 pmic driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ */
+#include <common.h>
+#include <dm.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+
+#define PID_SHIFT 8
+#define PID_MASK (0xFF << PID_SHIFT)
+#define REG_MASK 0xFF
+
+struct pm8916_priv {
+ uint32_t usid; /* Slave ID on SPMI bus */
+};
+
+static int pm8916_reg_count(struct udevice *dev)
+{
+ return 0xFFFF;
+}
+
+static int pm8916_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ struct pm8916_priv *priv = dev_get_priv(dev);
+
+ if (len != 1)
+ return -EINVAL;
+
+ return spmi_reg_write(dev->parent, priv->usid,
+ (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK,
+ *buff);
+}
+
+static int pm8916_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ struct pm8916_priv *priv = dev_get_priv(dev);
+ int val;
+
+ if (len != 1)
+ return -EINVAL;
+
+ val = spmi_reg_read(dev->parent, priv->usid,
+ (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK);
+
+ if (val < 0)
+ return val;
+ *buff = val;
+ return 0;
+}
+
+static struct dm_pmic_ops pm8916_ops = {
+ .reg_count = pm8916_reg_count,
+ .read = pm8916_read,
+ .write = pm8916_write,
+};
+
+static const struct udevice_id pm8916_ids[] = {
+ { .compatible = "qcom,spmi-pmic" },
+ { }
+};
+
+static int pm8916_probe(struct udevice *dev)
+{
+ struct pm8916_priv *priv = dev_get_priv(dev);
+
+ priv->usid = dev_read_addr(dev);
+
+ if (priv->usid == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(pmic_pm8916) = {
+ .name = "pmic_pm8916",
+ .id = UCLASS_PMIC,
+ .of_match = pm8916_ids,
+ .bind = dm_scan_fdt_dev,
+ .probe = pm8916_probe,
+ .ops = &pm8916_ops,
+ .priv_auto = sizeof(struct pm8916_priv),
+};
diff --git a/roms/u-boot/drivers/power/pmic/pmic-uclass.c b/roms/u-boot/drivers/power/pmic/pmic-uclass.c
new file mode 100644
index 000000000..79166b8bb
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic-uclass.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <log.h>
+#include <vsprintf.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <power/pmic.h>
+#include <linux/ctype.h>
+
+#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
+int pmic_bind_children(struct udevice *pmic, ofnode parent,
+ const struct pmic_child_info *child_info)
+{
+ const struct pmic_child_info *info;
+ struct driver *drv;
+ struct udevice *child;
+ const char *node_name;
+ const char *reg_name;
+ int bind_count = 0;
+ ofnode node;
+ int prefix_len;
+ int ret;
+
+ debug("%s for '%s' at node offset: %d\n", __func__, pmic->name,
+ dev_of_offset(pmic));
+
+ ofnode_for_each_subnode(node, parent) {
+ node_name = ofnode_get_name(node);
+
+ debug("* Found child node: '%s'\n", node_name);
+
+ child = NULL;
+ for (info = child_info; info->prefix && info->driver; info++) {
+ debug(" - compatible prefix: '%s'\n", info->prefix);
+
+ prefix_len = strlen(info->prefix);
+ if (strncmp(info->prefix, node_name, prefix_len)) {
+ reg_name = ofnode_read_string(node,
+ "regulator-name");
+ if (!reg_name)
+ continue;
+ if (strncmp(info->prefix, reg_name, prefix_len))
+ continue;
+ }
+
+ drv = lists_driver_lookup_name(info->driver);
+ if (!drv) {
+ debug(" - driver: '%s' not found!\n",
+ info->driver);
+ continue;
+ }
+
+ debug(" - found child driver: '%s'\n", drv->name);
+
+ ret = device_bind_with_driver_data(pmic, drv, node_name,
+ 0, node, &child);
+ if (ret) {
+ debug(" - child binding error: %d\n", ret);
+ continue;
+ }
+
+ debug(" - bound child device: '%s'\n", child->name);
+
+ child->driver_data = trailing_strtol(node_name);
+
+ debug(" - set 'child->driver_data': %lu\n",
+ child->driver_data);
+ break;
+ }
+
+ if (child)
+ bind_count++;
+ else
+ debug(" - compatible prefix not found\n");
+ }
+
+ debug("Bound: %d children for PMIC: '%s'\n", bind_count, pmic->name);
+ return bind_count;
+}
+#endif
+
+int pmic_get(const char *name, struct udevice **devp)
+{
+ return uclass_get_device_by_name(UCLASS_PMIC, name, devp);
+}
+
+int pmic_reg_count(struct udevice *dev)
+{
+ const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+
+ if (!ops || !ops->reg_count)
+ return -ENOSYS;
+
+ return ops->reg_count(dev);
+}
+
+int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len)
+{
+ const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+
+ if (!buffer)
+ return -EFAULT;
+
+ if (!ops || !ops->read)
+ return -ENOSYS;
+
+ return ops->read(dev, reg, buffer, len);
+}
+
+int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len)
+{
+ const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+
+ if (!buffer)
+ return -EFAULT;
+
+ if (!ops || !ops->write)
+ return -ENOSYS;
+
+ return ops->write(dev, reg, buffer, len);
+}
+
+int pmic_reg_read(struct udevice *dev, uint reg)
+{
+ struct uc_pmic_priv *priv = dev_get_uclass_priv(dev);
+ u32 val = 0;
+ int ret;
+
+ if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) {
+ debug("Wrong transmission size [%d]\n", priv->trans_len);
+ return -EINVAL;
+ }
+
+ debug("%s: reg=%x priv->trans_len:%d", __func__, reg, priv->trans_len);
+ ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len);
+ debug(", value=%x, ret=%d\n", val, ret);
+
+ return ret ? ret : val;
+}
+
+int pmic_reg_write(struct udevice *dev, uint reg, uint value)
+{
+ struct uc_pmic_priv *priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ if (priv->trans_len < 1 || priv->trans_len > sizeof(value)) {
+ debug("Wrong transmission size [%d]\n", priv->trans_len);
+ return -EINVAL;
+ }
+
+ debug("%s: reg=%x, value=%x priv->trans_len:%d", __func__, reg, value,
+ priv->trans_len);
+ ret = pmic_write(dev, reg, (uint8_t *)&value, priv->trans_len);
+ debug(", ret=%d\n", ret);
+
+ return ret;
+}
+
+int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set)
+{
+ struct uc_pmic_priv *priv = dev_get_uclass_priv(dev);
+ u32 val = 0;
+ int ret;
+
+ if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) {
+ debug("Wrong transmission size [%d]\n", priv->trans_len);
+ return -EINVAL;
+ }
+
+ ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len);
+ if (ret < 0)
+ return ret;
+
+ val = (val & ~clr) | set;
+ return pmic_write(dev, reg, (uint8_t *)&val, priv->trans_len);
+}
+
+static int pmic_pre_probe(struct udevice *dev)
+{
+ struct uc_pmic_priv *pmic_priv = dev_get_uclass_priv(dev);
+
+ pmic_priv->trans_len = 1;
+ return 0;
+}
+
+UCLASS_DRIVER(pmic) = {
+ .id = UCLASS_PMIC,
+ .name = "pmic",
+ .pre_probe = pmic_pre_probe,
+ .per_device_auto = sizeof(struct uc_pmic_priv),
+};
diff --git a/roms/u-boot/drivers/power/pmic/pmic_hi6553.c b/roms/u-boot/drivers/power/pmic/pmic_hi6553.c
new file mode 100644
index 000000000..80b9078cf
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_hi6553.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Linaro
+ * Peter Griffin <peter.griffin@linaro.org>
+ */
+#include <asm/io.h>
+#include <common.h>
+#include <linux/delay.h>
+#include <power/pmic.h>
+#include <power/max8997_muic.h>
+#include <power/hi6553_pmic.h>
+#include <errno.h>
+
+u8 *pmussi_base;
+
+uint8_t hi6553_readb(u32 offset)
+{
+ return readb(pmussi_base + (offset << 2));
+}
+
+void hi6553_writeb(u32 offset, uint8_t value)
+{
+ writeb(value, pmussi_base + (offset << 2));
+}
+
+int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
+{
+ if (check_reg(p, reg))
+ return -EINVAL;
+
+ hi6553_writeb(reg, (uint8_t)val);
+
+ return 0;
+}
+
+int pmic_reg_read(struct pmic *p, u32 reg, u32 *val)
+{
+ if (check_reg(p, reg))
+ return -EINVAL;
+
+ *val = (u32)hi6553_readb(reg);
+
+ return 0;
+}
+
+static void hi6553_init(void)
+{
+ int data;
+
+ hi6553_writeb(HI6553_PERI_EN_MARK, 0x1e);
+ hi6553_writeb(HI6553_NP_REG_ADJ1, 0);
+ data = HI6553_DISABLE6_XO_CLK_CONN | HI6553_DISABLE6_XO_CLK_NFC |
+ HI6553_DISABLE6_XO_CLK_RF1 | HI6553_DISABLE6_XO_CLK_RF2;
+ hi6553_writeb(HI6553_DISABLE6_XO_CLK, data);
+
+ /* configure BUCK0 & BUCK1 */
+ hi6553_writeb(HI6553_BUCK01_CTRL2, 0x5e);
+ hi6553_writeb(HI6553_BUCK0_CTRL7, 0x10);
+ hi6553_writeb(HI6553_BUCK1_CTRL7, 0x10);
+ hi6553_writeb(HI6553_BUCK0_CTRL5, 0x1e);
+ hi6553_writeb(HI6553_BUCK1_CTRL5, 0x1e);
+ hi6553_writeb(HI6553_BUCK0_CTRL1, 0xfc);
+ hi6553_writeb(HI6553_BUCK1_CTRL1, 0xfc);
+
+ /* configure BUCK2 */
+ hi6553_writeb(HI6553_BUCK2_REG1, 0x4f);
+ hi6553_writeb(HI6553_BUCK2_REG5, 0x99);
+ hi6553_writeb(HI6553_BUCK2_REG6, 0x45);
+ mdelay(1);
+ hi6553_writeb(HI6553_VSET_BUCK2_ADJ, 0x22);
+ mdelay(1);
+
+ /* configure BUCK3 */
+ hi6553_writeb(HI6553_BUCK3_REG3, 0x02);
+ hi6553_writeb(HI6553_BUCK3_REG5, 0x99);
+ hi6553_writeb(HI6553_BUCK3_REG6, 0x41);
+ hi6553_writeb(HI6553_VSET_BUCK3_ADJ, 0x02);
+ mdelay(1);
+
+ /* configure BUCK4 */
+ hi6553_writeb(HI6553_BUCK4_REG2, 0x9a);
+ hi6553_writeb(HI6553_BUCK4_REG5, 0x99);
+ hi6553_writeb(HI6553_BUCK4_REG6, 0x45);
+
+ /* configure LDO20 */
+ hi6553_writeb(HI6553_LDO20_REG_ADJ, 0x50);
+
+ hi6553_writeb(HI6553_NP_REG_CHG, 0x0f);
+ hi6553_writeb(HI6553_CLK_TOP0, 0x06);
+ hi6553_writeb(HI6553_CLK_TOP3, 0xc0);
+ hi6553_writeb(HI6553_CLK_TOP4, 0x00);
+
+ /* configure LDO7 & LDO10 for SD slot */
+ data = hi6553_readb(HI6553_LDO7_REG_ADJ);
+ data = (data & 0xf8) | 0x2;
+ hi6553_writeb(HI6553_LDO7_REG_ADJ, data);
+ mdelay(5);
+ /* enable LDO7 */
+ hi6553_writeb(HI6553_ENABLE2_LDO1_8, 1 << 6);
+ mdelay(5);
+ data = hi6553_readb(HI6553_LDO10_REG_ADJ);
+ data = (data & 0xf8) | 0x5;
+ hi6553_writeb(HI6553_LDO10_REG_ADJ, data);
+ mdelay(5);
+ /* enable LDO10 */
+ hi6553_writeb(HI6553_ENABLE3_LDO9_16, 1 << 1);
+ mdelay(5);
+
+ /* select 32.764KHz */
+ hi6553_writeb(HI6553_CLK19M2_600_586_EN, 0x01);
+}
+
+int power_hi6553_init(u8 *base)
+{
+ static const char name[] = "HI6553 PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_NONE;
+ p->number_of_regs = 44;
+ pmussi_base = base;
+
+ hi6553_init();
+
+ puts("HI6553 PMIC init\n");
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/pmic_ltc3676.c b/roms/u-boot/drivers/power/pmic/pmic_ltc3676.c
new file mode 100644
index 000000000..00c3e201c
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_ltc3676.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 Gateworks Corporation
+ * Tim Harvey <tharvey@gateworks.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/ltc3676_pmic.h>
+
+int power_ltc3676_init(unsigned char bus)
+{
+ static const char name[] = "LTC3676_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = LTC3676_NUM_OF_REGS;
+ p->hw.i2c.addr = CONFIG_POWER_LTC3676_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/pmic_mc34vr500.c b/roms/u-boot/drivers/power/pmic/pmic_mc34vr500.c
new file mode 100644
index 000000000..9dd1c46ea
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_mc34vr500.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ * Hou Zhiqiang <Zhiqiang.Hou@freescale.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/mc34vr500_pmic.h>
+
+int power_mc34vr500_init(unsigned char bus)
+{
+ static const char name[] = "MC34VR500";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = MC34VR500_NUM_OF_REGS;
+ p->hw.i2c.addr = MC34VR500_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/pmic_pca9450.c b/roms/u-boot/drivers/power/pmic/pmic_pca9450.c
new file mode 100644
index 000000000..8c4d0a923
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_pca9450.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/pca9450.h>
+
+static const char pca9450_name[] = "PCA9450";
+
+int power_pca9450_init(unsigned char bus, unsigned char addr)
+{
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = pca9450_name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PCA9450_REG_NUM;
+ p->hw.i2c.addr = addr;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c b/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c
new file mode 100644
index 000000000..c646a0c31
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 Gateworks Corporation
+ * Tim Harvey <tharvey@gateworks.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/pfuze100_pmic.h>
+
+int power_pfuze100_init(unsigned char bus)
+{
+ static const char name[] = "PFUZE100";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PFUZE100_NUM_OF_REGS;
+ p->hw.i2c.addr = CONFIG_POWER_PFUZE100_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/pmic_pfuze3000.c b/roms/u-boot/drivers/power/pmic/pmic_pfuze3000.c
new file mode 100644
index 000000000..1077fa5e9
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_pfuze3000.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Peng Fan <Peng.Fan@freescale.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/pfuze3000_pmic.h>
+
+int power_pfuze3000_init(unsigned char bus)
+{
+ static const char name[] = "PFUZE3000";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PFUZE3000_NUM_OF_REGS;
+ p->hw.i2c.addr = CONFIG_POWER_PFUZE3000_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps62362.c b/roms/u-boot/drivers/power/pmic/pmic_tps62362.c
new file mode 100644
index 000000000..59190d6f6
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_tps62362.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Felipe Balbi <balbi@ti.com>
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <linux/errno.h>
+#include <power/pmic.h>
+#include <power/tps62362.h>
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+struct udevice *tps62362_dev __section(".data") = NULL;
+#endif
+
+/**
+ * tps62362_voltage_update() - Function to change a voltage level, as this
+ * is a multi-step process.
+ * @reg: Register address to write to
+ * @volt_sel: Voltage register value to write
+ * @return: 0 on success, 1 on failure
+ */
+int tps62362_voltage_update(unsigned char reg, unsigned char volt_sel)
+{
+ if (reg > TPS62362_NUM_REGS)
+ return 1;
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ return i2c_write(TPS62362_I2C_ADDR, reg, 1, &volt_sel, 1);
+#else
+ if (!tps62362_dev)
+ return -ENODEV;
+ return dm_i2c_reg_write(tps62362_dev, reg, volt_sel);
+#endif
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+int power_tps62362_init(unsigned char bus)
+{
+ static const char name[] = "TPS62362";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = TPS62362_NUM_REGS;
+ p->hw.i2c.addr = TPS62362_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
+#else
+int power_tps62362_init(unsigned char bus)
+{
+ struct udevice *dev = NULL;
+ int rc;
+
+ rc = i2c_get_chip_for_busnum(bus, TPS62362_I2C_ADDR, 1, &dev);
+ if (rc)
+ return rc;
+ tps62362_dev = dev;
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps65217.c b/roms/u-boot/drivers/power/pmic/pmic_tps65217.c
new file mode 100644
index 000000000..c7f532df4
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_tps65217.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011-2013
+ * Texas Instruments, <www.ti.com>
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <power/tps65217.h>
+
+struct udevice *tps65217_dev __section(".data") = NULL;
+
+/**
+ * tps65217_reg_read() - Generic function that can read a TPS65217 register
+ * @src_reg: Source register address
+ * @src_val: Address of destination variable
+ * @return: 0 for success, not 0 on failure.
+ */
+int tps65217_reg_read(uchar src_reg, uchar *src_val)
+{
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ return i2c_read(TPS65217_CHIP_PM, src_reg, 1, src_val, 1);
+#else
+ return dm_i2c_read(tps65217_dev, src_reg, src_val, 1);
+#endif
+}
+
+/**
+ * tps65217_reg_write() - Generic function that can write a TPS65217 PMIC
+ * register or bit field regardless of protection
+ * level.
+ *
+ * @prot_level: Register password protection. Use
+ * TPS65217_PROT_LEVEL_NONE,
+ * TPS65217_PROT_LEVEL_1 or TPS65217_PROT_LEVEL_2
+ * @dest_reg: Register address to write.
+ * @dest_val: Value to write.
+ * @mask: Bit mask (8 bits) to be applied. Function will only
+ * change bits that are set in the bit mask.
+ *
+ * @return: 0 for success, not 0 on failure, as per the i2c API
+ */
+int tps65217_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val,
+ uchar mask)
+{
+ uchar read_val;
+ uchar xor_reg;
+ int ret;
+
+ /*
+ * If we are affecting only a bit field, read dest_reg and apply the
+ * mask
+ */
+ if (mask != TPS65217_MASK_ALL_BITS) {
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ ret = i2c_read(TPS65217_CHIP_PM, dest_reg, 1, &read_val, 1);
+#else
+ ret = dm_i2c_read(tps65217_dev, dest_reg, &read_val, 1);
+#endif
+ if (ret)
+ return ret;
+
+ read_val &= (~mask);
+ read_val |= (dest_val & mask);
+ dest_val = read_val;
+ }
+
+ if (prot_level > 0) {
+ xor_reg = dest_reg ^ TPS65217_PASSWORD_UNLOCK;
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ ret = i2c_write(TPS65217_CHIP_PM, TPS65217_PASSWORD, 1,
+ &xor_reg, 1);
+#else
+ ret = dm_i2c_write(tps65217_dev, TPS65217_PASSWORD,
+ &xor_reg, 1);
+#endif
+ if (ret)
+ return ret;
+ }
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ ret = i2c_write(TPS65217_CHIP_PM, dest_reg, 1, &dest_val, 1);
+#else
+ ret = dm_i2c_write(tps65217_dev, dest_reg, &dest_val, 1);
+#endif
+ if (ret)
+ return ret;
+
+ if (prot_level == TPS65217_PROT_LEVEL_2) {
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ ret = i2c_write(TPS65217_CHIP_PM, TPS65217_PASSWORD, 1,
+ &xor_reg, 1);
+#else
+ ret = dm_i2c_write(tps65217_dev, TPS65217_PASSWORD,
+ &xor_reg, 1);
+#endif
+ if (ret)
+ return ret;
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ ret = i2c_write(TPS65217_CHIP_PM, dest_reg, 1, &dest_val, 1);
+#else
+ ret = dm_i2c_write(tps65217_dev, dest_reg, &dest_val, 1);
+#endif
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * tps65217_voltage_update() - Function to change a voltage level, as this
+ * is a multi-step process.
+ * @dc_cntrl_reg: DC voltage control register to change.
+ * @volt_sel: New value for the voltage register
+ * @return: 0 for success, not 0 on failure.
+ */
+int tps65217_voltage_update(uchar dc_cntrl_reg, uchar volt_sel)
+{
+ if ((dc_cntrl_reg != TPS65217_DEFDCDC1) &&
+ (dc_cntrl_reg != TPS65217_DEFDCDC2) &&
+ (dc_cntrl_reg != TPS65217_DEFDCDC3))
+ return 1;
+
+ /* set voltage level */
+ if (tps65217_reg_write(TPS65217_PROT_LEVEL_2, dc_cntrl_reg, volt_sel,
+ TPS65217_MASK_ALL_BITS))
+ return 1;
+
+ /* set GO bit to initiate voltage transition */
+ if (tps65217_reg_write(TPS65217_PROT_LEVEL_2, TPS65217_DEFSLEW,
+ TPS65217_DCDC_GO, TPS65217_DCDC_GO))
+ return 1;
+
+ return 0;
+}
+
+int power_tps65217_init(unsigned char bus)
+{
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct udevice *dev = NULL;
+ int rc;
+
+ rc = i2c_get_chip_for_busnum(bus, TPS65217_CHIP_PM, 1, &dev);
+ if (rc)
+ return rc;
+ tps65217_dev = dev;
+#endif
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps65218.c b/roms/u-boot/drivers/power/pmic/pmic_tps65218.c
new file mode 100644
index 000000000..671749018
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_tps65218.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011-2013
+ * Texas Instruments, <www.ti.com>
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <linux/errno.h>
+#include <power/pmic.h>
+#include <power/tps65218.h>
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+int tps65218_reg_read(uchar dest_reg, uchar *dest_val)
+{
+ uchar read_val;
+ int ret;
+
+ ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1);
+ if (ret)
+ return ret;
+
+ *dest_val = read_val;
+
+ return 0;
+}
+
+/**
+ * tps65218_reg_write() - Generic function that can write a TPS65218 PMIC
+ * register or bit field regardless of protection
+ * level.
+ *
+ * @prot_level: Register password protection. Use
+ * TPS65218_PROT_LEVEL_NONE,
+ * TPS65218_PROT_LEVEL_1 or TPS65218_PROT_LEVEL_2
+ * @dest_reg: Register address to write.
+ * @dest_val: Value to write.
+ * @mask: Bit mask (8 bits) to be applied. Function will only
+ * change bits that are set in the bit mask.
+ *
+ * @return: 0 for success, not 0 on failure, as per the i2c API
+ */
+int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val,
+ uchar mask)
+{
+ uchar read_val;
+ uchar xor_reg;
+ int ret;
+
+ /*
+ * If we are affecting only a bit field, read dest_reg and apply the
+ * mask
+ */
+ if (mask != TPS65218_MASK_ALL_BITS) {
+ ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1);
+ if (ret)
+ return ret;
+ read_val &= (~mask);
+ read_val |= (dest_val & mask);
+ dest_val = read_val;
+ }
+
+ if (prot_level > 0) {
+ xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK;
+ ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1,
+ &xor_reg, 1);
+ if (ret)
+ return ret;
+ }
+
+ ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1);
+ if (ret)
+ return ret;
+
+ if (prot_level == TPS65218_PROT_LEVEL_2) {
+ ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1,
+ &xor_reg, 1);
+ if (ret)
+ return ret;
+
+ ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#else
+struct udevice *tps65218_dev __section(".data") = NULL;
+
+int tps65218_reg_read(uchar dest_reg, uchar *dest_val)
+{
+ uchar read_val;
+ int ret;
+
+ if (!tps65218_dev)
+ return -ENODEV;
+
+ ret = dm_i2c_read(tps65218_dev, dest_reg, &read_val, 1);
+ if (ret)
+ return ret;
+
+ *dest_val = read_val;
+
+ return 0;
+}
+
+int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val,
+ uchar mask)
+{
+ uchar read_val;
+ uchar xor_reg;
+ int ret;
+
+ if (!tps65218_dev)
+ return -ENODEV;
+
+ /*
+ * If we are affecting only a bit field, read dest_reg and apply the
+ * mask
+ */
+ if (mask != TPS65218_MASK_ALL_BITS) {
+ ret = dm_i2c_read(tps65218_dev, dest_reg, &read_val, 1);
+ if (ret)
+ return ret;
+
+ read_val &= (~mask);
+ read_val |= (dest_val & mask);
+ dest_val = read_val;
+ }
+
+ if (prot_level > 0) {
+ xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK;
+ ret = dm_i2c_write(tps65218_dev, TPS65218_PASSWORD, &xor_reg,
+ 1);
+ if (ret)
+ return ret;
+ }
+
+ ret = dm_i2c_write(tps65218_dev, dest_reg, &dest_val, 1);
+ if (ret)
+ return ret;
+
+ if (prot_level == TPS65218_PROT_LEVEL_2) {
+ ret = dm_i2c_write(tps65218_dev, TPS65218_PASSWORD, &xor_reg,
+ 1);
+ if (ret)
+ return ret;
+
+ ret = dm_i2c_write(tps65218_dev, dest_reg, &dest_val, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+/**
+ * tps65218_voltage_update() - Function to change a voltage level, as this
+ * is a multi-step process.
+ * @dc_cntrl_reg: DC voltage control register to change.
+ * @volt_sel: New value for the voltage register
+ * @return: 0 for success, not 0 on failure.
+ */
+int tps65218_voltage_update(uchar dc_cntrl_reg, uchar volt_sel)
+{
+ if ((dc_cntrl_reg != TPS65218_DCDC1) &&
+ (dc_cntrl_reg != TPS65218_DCDC2) &&
+ (dc_cntrl_reg != TPS65218_DCDC3))
+ return 1;
+
+ /* set voltage level */
+ if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, dc_cntrl_reg, volt_sel,
+ TPS65218_DCDC_VSEL_MASK))
+ return 1;
+
+ /* set GO bit to initiate voltage transition */
+ if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, TPS65218_SLEW,
+ TPS65218_DCDC_GO, TPS65218_DCDC_GO))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * tps65218_toggle_fseal() - Perform the sequence that toggles the FSEAL bit.
+ *
+ * @return: 0 on success, -EBADE if the sequence was broken
+ */
+int tps65218_toggle_fseal(void)
+{
+ if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
+ 0xb1, TPS65218_MASK_ALL_BITS))
+ return -EBADE;
+
+ if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
+ 0xfe, TPS65218_MASK_ALL_BITS))
+ return -EBADE;
+
+ if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
+ 0xa3, TPS65218_MASK_ALL_BITS))
+ return -EBADE;
+
+ return 0;
+}
+
+/**
+ * tps65218_lock_fseal() - Perform the sequence that locks the FSEAL bit to 1.
+ *
+ * The FSEAL bit prevents the PMIC from turning off DCDC5 and DCDC6. It can be
+ * toggled at most 3 times: 0->1, 1->0, and finally 0->1. After the third switch
+ * its value is locked and can only be reset by powering off the PMIC entirely.
+ *
+ * @return: 0 on success, -EBADE if the sequence was broken
+ */
+int tps65218_lock_fseal(void)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (tps65218_toggle_fseal())
+ return -EBADE;
+
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_I2C)
+int power_tps65218_init(unsigned char bus)
+{
+ static const char name[] = "TPS65218_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = TPS65218_PMIC_NUM_OF_REGS;
+ p->hw.i2c.addr = TPS65218_CHIP_PM;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
+#else
+int power_tps65218_init(unsigned char bus)
+{
+ struct udevice *dev = NULL;
+ int rc;
+
+ rc = i2c_get_chip_for_busnum(bus, TPS65218_CHIP_PM, 1, &dev);
+ if (rc)
+ return rc;
+ tps65218_dev = dev;
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps65910.c b/roms/u-boot/drivers/power/pmic/pmic_tps65910.c
new file mode 100644
index 000000000..fcd0a654a
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_tps65910.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011-2013
+ * Texas Instruments, <www.ti.com>
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <power/tps65910.h>
+
+struct udevice *tps65910_dev __section(".data") = NULL;
+
+static inline int tps65910_read_reg(int addr, uchar *buf)
+{
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ return i2c_read(TPS65910_CTRL_I2C_ADDR, addr, 1, buf, 1);
+#else
+ int rc;
+
+ rc = dm_i2c_reg_read(tps65910_dev, addr);
+ if (rc < 0)
+ return rc;
+ *buf = (uchar)rc;
+ return 0;
+#endif
+}
+
+static inline int tps65910_write_reg(int addr, uchar *buf)
+{
+#if !CONFIG_IS_ENABLED(DM_I2C)
+ return i2c_write(TPS65910_CTRL_I2C_ADDR, addr, 1, buf, 1);
+#else
+ return dm_i2c_reg_write(tps65910_dev, addr, *buf);
+#endif
+}
+
+int power_tps65910_init(unsigned char bus)
+{
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct udevice *dev = NULL;
+ int rc;
+
+ rc = i2c_get_chip_for_busnum(bus, TPS65910_CTRL_I2C_ADDR, 1, &dev);
+
+ if (rc)
+ return rc;
+ tps65910_dev = dev;
+#endif
+ return 0;
+}
+
+/*
+ * tps65910_set_i2c_control() - Set the TPS65910 to be controlled via the I2C
+ * interface.
+ * @return: 0 on success, not 0 on failure
+ */
+int tps65910_set_i2c_control(void)
+{
+ int ret;
+ uchar buf;
+
+ /* VDD1/2 voltage selection register access by control i/f */
+ ret = tps65910_read_reg(TPS65910_DEVCTRL_REG, &buf);
+
+ if (ret)
+ return ret;
+
+ buf |= TPS65910_DEVCTRL_REG_SR_CTL_I2C_SEL_CTL_I2C;
+
+ return tps65910_write_reg(TPS65910_DEVCTRL_REG, &buf);
+}
+
+/*
+ * tps65910_voltage_update() - Voltage switching for MPU frequency switching.
+ * @module: mpu - 0, core - 1
+ * @vddx_op_vol_sel: vdd voltage to set
+ * @return: 0 on success, not 0 on failure
+ */
+int tps65910_voltage_update(unsigned int module, unsigned char vddx_op_vol_sel)
+{
+ uchar buf;
+ unsigned int reg_offset;
+ int ret;
+
+ if (module == MPU)
+ reg_offset = TPS65910_VDD1_OP_REG;
+ else
+ reg_offset = TPS65910_VDD2_OP_REG;
+
+ /* Select VDDx OP */
+ ret = tps65910_read_reg(reg_offset, &buf);
+ if (ret)
+ return ret;
+
+ buf &= ~TPS65910_OP_REG_CMD_MASK;
+
+ ret = tps65910_write_reg(reg_offset, &buf);
+ if (ret)
+ return ret;
+
+ /* Configure VDDx OP Voltage */
+ ret = tps65910_read_reg(reg_offset, &buf);
+ if (ret)
+ return ret;
+
+ buf &= ~TPS65910_OP_REG_SEL_MASK;
+ buf |= vddx_op_vol_sel;
+
+ ret = tps65910_write_reg(reg_offset, &buf);
+ if (ret)
+ return ret;
+
+ ret = tps65910_read_reg(reg_offset, &buf);
+ if (ret)
+ return ret;
+
+ if ((buf & TPS65910_OP_REG_SEL_MASK) != vddx_op_vol_sel)
+ return 1;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps65910_dm.c b/roms/u-boot/drivers/power/pmic/pmic_tps65910_dm.c
new file mode 100644
index 000000000..e03ddc98d
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/pmic_tps65910_dm.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65910_pmic.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo_", .driver = TPS65910_LDO_DRIVER },
+ { .prefix = "buck_", .driver = TPS65910_BUCK_DRIVER },
+ { .prefix = "boost_", .driver = TPS65910_BOOST_DRIVER },
+ { },
+};
+
+static int pmic_tps65910_reg_count(struct udevice *dev)
+{
+ return TPS65910_NUM_REGS;
+}
+
+static int pmic_tps65910_write(struct udevice *dev, uint reg, const u8 *buffer,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buffer, len);
+ if (ret)
+ pr_err("%s write error on register %02x\n", dev->name, reg);
+
+ return ret;
+}
+
+static int pmic_tps65910_read(struct udevice *dev, uint reg, u8 *buffer,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buffer, len);
+ if (ret)
+ pr_err("%s read error on register %02x\n", dev->name, reg);
+
+ return ret;
+}
+
+static int pmic_tps65910_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s regulators subnode not found\n", dev->name);
+ return -EINVAL;
+ }
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s has no children (regulators)\n", dev->name);
+
+ return 0;
+}
+
+static int pmic_tps65910_probe(struct udevice *dev)
+{
+ /* use I2C control interface instead of I2C smartreflex interface to
+ * access smartrefelex registers VDD1_OP_REG, VDD1_SR_REG, VDD2_OP_REG
+ * and VDD2_SR_REG
+ */
+ return pmic_clrsetbits(dev, TPS65910_REG_DEVICE_CTRL, 0,
+ TPS65910_I2C_SEL_MASK);
+}
+
+static struct dm_pmic_ops pmic_tps65910_ops = {
+ .reg_count = pmic_tps65910_reg_count,
+ .read = pmic_tps65910_read,
+ .write = pmic_tps65910_write,
+};
+
+static const struct udevice_id pmic_tps65910_match[] = {
+ { .compatible = "ti,tps65910" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(pmic_tps65910) = {
+ .name = "pmic_tps65910",
+ .id = UCLASS_PMIC,
+ .of_match = pmic_tps65910_match,
+ .bind = pmic_tps65910_bind,
+ .probe = pmic_tps65910_probe,
+ .ops = &pmic_tps65910_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/rk8xx.c b/roms/u-boot/drivers/power/pmic/rk8xx.c
new file mode 100644
index 000000000..5f442fea6
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/rk8xx.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <power/rk8xx_pmic.h>
+#include <power/pmic.h>
+
+static struct reg_data rk817_init_reg[] = {
+/* enable the under-voltage protection,
+ * the under-voltage protection will shutdown the LDO3 and reset the PMIC
+ */
+ { RK817_BUCK4_CMIN, 0x60, 0x60},
+};
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "DCDC_REG", .driver = "rk8xx_buck"},
+ { .prefix = "LDO_REG", .driver = "rk8xx_ldo"},
+ { .prefix = "SWITCH_REG", .driver = "rk8xx_switch"},
+ { },
+};
+
+static int rk8xx_reg_count(struct udevice *dev)
+{
+ return RK808_NUM_OF_REGS;
+}
+
+static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret) {
+ debug("write error to device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret) {
+ debug("read error from device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
+static int rk8xx_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+#endif
+
+static int rk8xx_probe(struct udevice *dev)
+{
+ struct rk8xx_priv *priv = dev_get_priv(dev);
+ struct reg_data *init_data = NULL;
+ int init_data_num = 0;
+ int ret = 0, i, show_variant;
+ u8 msb, lsb, id_msb, id_lsb;
+ u8 on_source = 0, off_source = 0;
+ u8 power_en0, power_en1, power_en2, power_en3;
+ u8 value;
+
+ /* read Chip variant */
+ if (device_is_compatible(dev, "rockchip,rk817") ||
+ device_is_compatible(dev, "rockchip,rk809")) {
+ id_msb = RK817_ID_MSB;
+ id_lsb = RK817_ID_LSB;
+ } else {
+ id_msb = ID_MSB;
+ id_lsb = ID_LSB;
+ }
+
+ ret = rk8xx_read(dev, id_msb, &msb, 1);
+ if (ret)
+ return ret;
+ ret = rk8xx_read(dev, id_lsb, &lsb, 1);
+ if (ret)
+ return ret;
+
+ priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
+ show_variant = priv->variant;
+ switch (priv->variant) {
+ case RK808_ID:
+ show_variant = 0x808; /* RK808 hardware ID is 0 */
+ break;
+ case RK805_ID:
+ case RK816_ID:
+ case RK818_ID:
+ on_source = RK8XX_ON_SOURCE;
+ off_source = RK8XX_OFF_SOURCE;
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ on_source = RK817_ON_SOURCE;
+ off_source = RK817_OFF_SOURCE;
+ init_data = rk817_init_reg;
+ init_data_num = ARRAY_SIZE(rk817_init_reg);
+ power_en0 = pmic_reg_read(dev, RK817_POWER_EN0);
+ power_en1 = pmic_reg_read(dev, RK817_POWER_EN1);
+ power_en2 = pmic_reg_read(dev, RK817_POWER_EN2);
+ power_en3 = pmic_reg_read(dev, RK817_POWER_EN3);
+
+ value = (power_en0 & 0x0f) | ((power_en1 & 0x0f) << 4);
+ pmic_reg_write(dev, RK817_POWER_EN_SAVE0, value);
+ value = (power_en2 & 0x0f) | ((power_en3 & 0x0f) << 4);
+ pmic_reg_write(dev, RK817_POWER_EN_SAVE1, value);
+ break;
+ default:
+ printf("Unknown PMIC: RK%x!!\n", priv->variant);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < init_data_num; i++) {
+ ret = pmic_clrsetbits(dev,
+ init_data[i].reg,
+ init_data[i].mask,
+ init_data[i].val);
+ if (ret < 0) {
+ printf("%s: i2c set reg 0x%x failed, ret=%d\n",
+ __func__, init_data[i].reg, ret);
+ }
+
+ debug("%s: reg[0x%x] = 0x%x\n", __func__, init_data[i].reg,
+ pmic_reg_read(dev, init_data[i].reg));
+ }
+
+ printf("PMIC: RK%x ", show_variant);
+
+ if (on_source && off_source)
+ printf("(on=0x%02x, off=0x%02x)",
+ pmic_reg_read(dev, on_source),
+ pmic_reg_read(dev, off_source));
+ printf("\n");
+
+ return 0;
+}
+
+static struct dm_pmic_ops rk8xx_ops = {
+ .reg_count = rk8xx_reg_count,
+ .read = rk8xx_read,
+ .write = rk8xx_write,
+};
+
+static const struct udevice_id rk8xx_ids[] = {
+ { .compatible = "rockchip,rk805" },
+ { .compatible = "rockchip,rk808" },
+ { .compatible = "rockchip,rk809" },
+ { .compatible = "rockchip,rk816" },
+ { .compatible = "rockchip,rk817" },
+ { .compatible = "rockchip,rk818" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_rk805) = {
+ .name = "rockchip_rk805",
+ .id = UCLASS_PMIC,
+ .of_match = rk8xx_ids,
+#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
+ .bind = rk8xx_bind,
+#endif
+ .priv_auto = sizeof(struct rk8xx_priv),
+ .probe = rk8xx_probe,
+ .ops = &rk8xx_ops,
+};
+
+DM_DRIVER_ALIAS(rockchip_rk805, rockchip_rk808)
diff --git a/roms/u-boot/drivers/power/pmic/rn5t567.c b/roms/u-boot/drivers/power/pmic/rn5t567.c
new file mode 100644
index 000000000..d9a8298eb
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/rn5t567.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Toradex AG
+ * Stefan Agner <stefan.agner@toradex.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <linux/libfdt.h>
+#include <power/rn5t567_pmic.h>
+#include <power/pmic.h>
+
+static int rn5t567_reg_count(struct udevice *dev)
+{
+ return RN5T567_NUM_OF_REGS;
+}
+
+static int rn5t567_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret) {
+ debug("write error to device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rn5t567_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret) {
+ debug("read error from device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct dm_pmic_ops rn5t567_ops = {
+ .reg_count = rn5t567_reg_count,
+ .read = rn5t567_read,
+ .write = rn5t567_write,
+};
+
+static const struct udevice_id rn5t567_ids[] = {
+ { .compatible = "ricoh,rn5t567" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_rn5t567) = {
+ .name = "rn5t567 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = rn5t567_ids,
+ .ops = &rn5t567_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/s2mps11.c b/roms/u-boot/drivers/power/pmic/s2mps11.c
new file mode 100644
index 000000000..1ba1640a8
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/s2mps11.c
@@ -0,0 +1,88 @@
+// 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 <log.h>
+#include <power/pmic.h>
+#include <power/s2mps11.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = S2MPS11_OF_LDO_PREFIX, .driver = S2MPS11_LDO_DRIVER },
+ { .prefix = S2MPS11_OF_BUCK_PREFIX, .driver = S2MPS11_BUCK_DRIVER },
+ { },
+};
+
+static int s2mps11_reg_count(struct udevice *dev)
+{
+ return S2MPS11_REG_COUNT;
+}
+
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret)
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret)
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+
+ return ret;
+}
+
+static int s2mps11_probe(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "voltage-regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ return 0;
+}
+
+static struct dm_pmic_ops s2mps11_ops = {
+ .reg_count = s2mps11_reg_count,
+ .read = s2mps11_read,
+ .write = s2mps11_write,
+};
+
+static const struct udevice_id s2mps11_ids[] = {
+ { .compatible = "samsung,s2mps11-pmic" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_s2mps11) = {
+ .name = "s2mps11_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = s2mps11_ids,
+ .ops = &s2mps11_ops,
+ .probe = s2mps11_probe,
+};
diff --git a/roms/u-boot/drivers/power/pmic/s5m8767.c b/roms/u-boot/drivers/power/pmic/s5m8767.c
new file mode 100644
index 000000000..db6d0357e
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/s5m8767.c
@@ -0,0 +1,92 @@
+// 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 <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/s5m8767.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "LDO", .driver = S5M8767_LDO_DRIVER },
+ { .prefix = "BUCK", .driver = S5M8767_BUCK_DRIVER },
+ { },
+};
+
+static int s5m8767_reg_count(struct udevice *dev)
+{
+ return S5M8767_NUM_OF_REGS;
+}
+
+static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int s5m8767_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int s5m8767_enable_32khz_cp(struct udevice *dev)
+{
+ return pmic_clrsetbits(dev, S5M8767_EN32KHZ_CP, 0, 1 << 1);
+}
+
+static int s5m8767_bind(struct udevice *dev)
+{
+ int children;
+ ofnode node;
+
+ node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops s5m8767_ops = {
+ .reg_count = s5m8767_reg_count,
+ .read = s5m8767_read,
+ .write = s5m8767_write,
+};
+
+static const struct udevice_id s5m8767_ids[] = {
+ { .compatible = "samsung,s5m8767-pmic" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_s5m8767) = {
+ .name = "s5m8767_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = s5m8767_ids,
+ .bind = s5m8767_bind,
+ .ops = &s5m8767_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/sandbox.c b/roms/u-boot/drivers/power/pmic/sandbox.c
new file mode 100644
index 000000000..d7870915d
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/sandbox.c
@@ -0,0 +1,76 @@
+// 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>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = SANDBOX_OF_LDO_PREFIX, .driver = SANDBOX_LDO_DRIVER },
+ { .prefix = SANDBOX_OF_BUCK_PREFIX, .driver = SANDBOX_BUCK_DRIVER },
+ { },
+};
+
+static int sandbox_pmic_reg_count(struct udevice *dev)
+{
+ return SANDBOX_PMIC_REG_COUNT;
+}
+
+static int sandbox_pmic_write(struct udevice *dev, uint reg,
+ const uint8_t *buff, int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int sandbox_pmic_read(struct udevice *dev, uint reg,
+ uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int sandbox_pmic_bind(struct udevice *dev)
+{
+ if (!pmic_bind_children(dev, dev_ofnode(dev), pmic_children_info))
+ pr_err("%s:%d PMIC: %s - no child found!", __func__, __LINE__,
+ dev->name);
+
+ /* Always return success for this device - allows for PMIC I/O */
+ return 0;
+}
+
+static struct dm_pmic_ops sandbox_pmic_ops = {
+ .reg_count = sandbox_pmic_reg_count,
+ .read = sandbox_pmic_read,
+ .write = sandbox_pmic_write,
+};
+
+static const struct udevice_id sandbox_pmic_ids[] = {
+ { .compatible = "sandbox,pmic" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_pmic) = {
+ .name = "sandbox_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = sandbox_pmic_ids,
+ .bind = sandbox_pmic_bind,
+ .ops = &sandbox_pmic_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/stpmic1.c b/roms/u-boot/drivers/power/pmic/stpmic1.c
new file mode 100644
index 000000000..2c85410b1
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/stpmic1.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <misc.h>
+#include <sysreset.h>
+#include <time.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <power/pmic.h>
+#include <power/stpmic1.h>
+
+#define STPMIC1_NUM_OF_REGS 0x100
+
+#define STPMIC1_NVM_SIZE 8
+#define STPMIC1_NVM_POLL_TIMEOUT 100000
+#define STPMIC1_NVM_START_ADDRESS 0xf8
+
+enum pmic_nvm_op {
+ SHADOW_READ,
+ SHADOW_WRITE,
+ NVM_READ,
+ NVM_WRITE,
+};
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+static const struct pmic_child_info stpmic1_children_info[] = {
+ { .prefix = "ldo", .driver = "stpmic1_ldo" },
+ { .prefix = "buck", .driver = "stpmic1_buck" },
+ { .prefix = "vref_ddr", .driver = "stpmic1_vref_ddr" },
+ { .prefix = "pwr_sw", .driver = "stpmic1_pwr_sw" },
+ { .prefix = "boost", .driver = "stpmic1_boost" },
+ { },
+};
+#endif /* DM_REGULATOR */
+
+static int stpmic1_reg_count(struct udevice *dev)
+{
+ return STPMIC1_NUM_OF_REGS;
+}
+
+static int stpmic1_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret)
+ dev_err(dev, "%s: failed to write register %#x :%d",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int stpmic1_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret)
+ dev_err(dev, "%s: failed to read register %#x : %d",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int stpmic1_bind(struct udevice *dev)
+{
+ int ret;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ dev_dbg(dev, "regulators subnode not found!");
+ return -ENXIO;
+ }
+ dev_dbg(dev, "found regulators subnode\n");
+
+ children = pmic_bind_children(dev, regulators_node,
+ stpmic1_children_info);
+ if (!children)
+ dev_dbg(dev, "no child found\n");
+#endif /* DM_REGULATOR */
+
+ if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
+ ret = device_bind_driver(dev, "stpmic1-nvm",
+ "stpmic1-nvm", NULL);
+ if (ret)
+ return ret;
+ }
+
+ if (CONFIG_IS_ENABLED(SYSRESET))
+ return device_bind_driver(dev, "stpmic1-sysreset",
+ "stpmic1-sysreset", NULL);
+
+ return 0;
+}
+
+static struct dm_pmic_ops stpmic1_ops = {
+ .reg_count = stpmic1_reg_count,
+ .read = stpmic1_read,
+ .write = stpmic1_write,
+};
+
+static const struct udevice_id stpmic1_ids[] = {
+ { .compatible = "st,stpmic1" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_stpmic1) = {
+ .name = "stpmic1_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = stpmic1_ids,
+ .bind = stpmic1_bind,
+ .ops = &stpmic1_ops,
+};
+
+#ifndef CONFIG_SPL_BUILD
+static int stpmic1_nvm_rw(struct udevice *dev, u8 addr, u8 *buf, int buf_len,
+ enum pmic_nvm_op op)
+{
+ unsigned long timeout;
+ u8 cmd = STPMIC1_NVM_CMD_READ;
+ int ret, len = buf_len;
+
+ if (addr < STPMIC1_NVM_START_ADDRESS)
+ return -EACCES;
+ if (addr + buf_len > STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE)
+ len = STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE - addr;
+
+ if (op == SHADOW_READ) {
+ ret = pmic_read(dev, addr, buf, len);
+ if (ret < 0)
+ return ret;
+ else
+ return len;
+ }
+
+ if (op == SHADOW_WRITE) {
+ ret = pmic_write(dev, addr, buf, len);
+ if (ret < 0)
+ return ret;
+ else
+ return len;
+ }
+
+ if (op == NVM_WRITE) {
+ cmd = STPMIC1_NVM_CMD_PROGRAM;
+
+ ret = pmic_write(dev, addr, buf, len);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = pmic_reg_read(dev, STPMIC1_NVM_CR);
+ if (ret < 0)
+ return ret;
+
+ ret = pmic_reg_write(dev, STPMIC1_NVM_CR, ret | cmd);
+ if (ret < 0)
+ return ret;
+
+ timeout = timer_get_us() + STPMIC1_NVM_POLL_TIMEOUT;
+ for (;;) {
+ ret = pmic_reg_read(dev, STPMIC1_NVM_SR);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & STPMIC1_NVM_BUSY))
+ break;
+
+ if (time_after(timer_get_us(), timeout))
+ break;
+ }
+
+ if (ret & STPMIC1_NVM_BUSY)
+ return -ETIMEDOUT;
+
+ if (op == NVM_READ) {
+ ret = pmic_read(dev, addr, buf, len);
+ if (ret < 0)
+ return ret;
+ }
+
+ return len;
+}
+
+static int stpmic1_nvm_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ enum pmic_nvm_op op = NVM_READ;
+
+ if (offset < 0) {
+ op = SHADOW_READ;
+ offset = -offset;
+ }
+
+ return stpmic1_nvm_rw(dev->parent, offset, buf, size, op);
+}
+
+static int stpmic1_nvm_write(struct udevice *dev, int offset,
+ const void *buf, int size)
+{
+ enum pmic_nvm_op op = NVM_WRITE;
+
+ if (offset < 0) {
+ op = SHADOW_WRITE;
+ offset = -offset;
+ }
+
+ return stpmic1_nvm_rw(dev->parent, offset, (void *)buf, size, op);
+}
+
+static const struct misc_ops stpmic1_nvm_ops = {
+ .read = stpmic1_nvm_read,
+ .write = stpmic1_nvm_write,
+};
+
+U_BOOT_DRIVER(stpmic1_nvm) = {
+ .name = "stpmic1-nvm",
+ .id = UCLASS_MISC,
+ .ops = &stpmic1_nvm_ops,
+};
+#endif /* CONFIG_SPL_BUILD */
+
+#ifdef CONFIG_SYSRESET
+static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct udevice *pmic_dev = dev->parent;
+ int ret;
+
+ if (type != SYSRESET_POWER && type != SYSRESET_POWER_OFF)
+ return -EPROTONOSUPPORT;
+
+ ret = pmic_reg_read(pmic_dev, STPMIC1_MAIN_CR);
+ if (ret < 0)
+ return ret;
+
+ ret |= STPMIC1_SWOFF;
+ ret &= ~STPMIC1_RREQ_EN;
+ /* request Power Cycle */
+ if (type == SYSRESET_POWER)
+ ret |= STPMIC1_RREQ_EN;
+
+ ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR, ret);
+ if (ret < 0)
+ return ret;
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops stpmic1_sysreset_ops = {
+ .request = stpmic1_sysreset_request,
+};
+
+U_BOOT_DRIVER(stpmic1_sysreset) = {
+ .name = "stpmic1-sysreset",
+ .id = UCLASS_SYSRESET,
+ .ops = &stpmic1_sysreset_ops,
+};
+#endif
diff --git a/roms/u-boot/drivers/power/pmic/tps65090.c b/roms/u-boot/drivers/power/pmic/tps65090.c
new file mode 100644
index 000000000..b81df0dff
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/tps65090.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/tps65090.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "fet", .driver = TPS65090_FET_DRIVER },
+ { },
+};
+
+static int tps65090_reg_count(struct udevice *dev)
+{
+ return TPS65090_NUM_REGS;
+}
+
+static int tps65090_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tps65090_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret) {
+ pr_err("read error %d from device: %p register: %#x!\n", ret,
+ dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tps65090_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops tps65090_ops = {
+ .reg_count = tps65090_reg_count,
+ .read = tps65090_read,
+ .write = tps65090_write,
+};
+
+static const struct udevice_id tps65090_ids[] = {
+ { .compatible = "ti,tps65090" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_tps65090) = {
+ .name = "tps65090 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = tps65090_ids,
+ .bind = tps65090_bind,
+ .ops = &tps65090_ops,
+};
diff --git a/roms/u-boot/drivers/power/pmic/tps65941.c b/roms/u-boot/drivers/power/pmic/tps65941.c
new file mode 100644
index 000000000..3dfc1918d
--- /dev/null
+++ b/roms/u-boot/drivers/power/pmic/tps65941.c
@@ -0,0 +1,84 @@
+// 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 <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65941.h>
+#include <dm/device.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = TPS65941_LDO_DRIVER },
+ { .prefix = "buck", .driver = TPS65941_BUCK_DRIVER },
+ { },
+};
+
+static int tps65941_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tps65941_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tps65941_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!\n", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ printf("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Probe all the child devices */
+ return dm_scan_fdt_dev(dev);
+}
+
+static struct dm_pmic_ops tps65941_ops = {
+ .read = tps65941_read,
+ .write = tps65941_write,
+};
+
+static const struct udevice_id tps65941_ids[] = {
+ { .compatible = "ti,tps659411", .data = TPS659411 },
+ { .compatible = "ti,tps659413", .data = TPS659413 },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_tps65941) = {
+ .name = "tps65941_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = tps65941_ids,
+ .bind = tps65941_bind,
+ .ops = &tps65941_ops,
+};
diff --git a/roms/u-boot/drivers/power/power_core.c b/roms/u-boot/drivers/power/power_core.c
new file mode 100644
index 000000000..eeed8e24a
--- /dev/null
+++ b/roms/u-boot/drivers/power/power_core.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <power/pmic.h>
+
+static LIST_HEAD(pmic_list);
+
+int check_reg(struct pmic *p, u32 reg)
+{
+ if (reg >= p->number_of_regs) {
+ printf("<reg num> = %d is invalid. Should be less than %d\n",
+ reg, p->number_of_regs);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int pmic_set_output(struct pmic *p, u32 reg, int out, int on)
+{
+ u32 val;
+
+ if (pmic_reg_read(p, reg, &val))
+ return -ENOTSUPP;
+
+ if (on)
+ val |= out;
+ else
+ val &= ~out;
+
+ if (pmic_reg_write(p, reg, val))
+ return -ENOTSUPP;
+
+ return 0;
+}
+
+struct pmic *pmic_alloc(void)
+{
+ struct pmic *p;
+
+ p = calloc(sizeof(*p), 1);
+ if (!p) {
+ printf("%s: No available memory for allocation!\n", __func__);
+ return NULL;
+ }
+
+ list_add_tail(&p->list, &pmic_list);
+
+ debug("%s: new pmic struct: 0x%p\n", __func__, p);
+
+ return p;
+}
+
+struct pmic *pmic_get(const char *s)
+{
+ struct pmic *p;
+
+ list_for_each_entry(p, &pmic_list, list) {
+ if (strcmp(p->name, s) == 0) {
+ debug("%s: pmic %s -> 0x%p\n", __func__, p->name, p);
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+#ifndef CONFIG_SPL_BUILD
+static int pmic_dump(struct pmic *p)
+{
+ int i, ret;
+ u32 val;
+
+ if (!p) {
+ puts("Wrong PMIC name!\n");
+ return -ENODEV;
+ }
+
+ printf("PMIC: %s\n", p->name);
+ for (i = 0; i < p->number_of_regs; i++) {
+ ret = pmic_reg_read(p, i, &val);
+ if (ret)
+ puts("PMIC: Registers dump failed\n");
+
+ if (!(i % 8))
+ printf("\n0x%02x: ", i);
+
+ printf("%08x ", val);
+ }
+ puts("\n");
+ return 0;
+}
+
+static const char *power_get_interface(int interface)
+{
+ const char *power_interface[] = {"I2C", "SPI", "|+|-|"};
+ return power_interface[interface];
+}
+
+static void pmic_list_names(void)
+{
+ struct pmic *p;
+
+ puts("PMIC devices:\n");
+ list_for_each_entry(p, &pmic_list, list) {
+ printf("name: %s bus: %s_%d\n", p->name,
+ power_get_interface(p->interface), p->bus);
+ }
+}
+
+static int do_pmic(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ u32 ret, reg, val;
+ char *cmd, *name;
+ struct pmic *p;
+
+ /* at least two arguments please */
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ if (strcmp(argv[1], "list") == 0) {
+ pmic_list_names();
+ return CMD_RET_SUCCESS;
+ }
+
+ if (argc < 3)
+ return CMD_RET_USAGE;
+
+ name = argv[1];
+ cmd = argv[2];
+
+ debug("%s: name: %s cmd: %s\n", __func__, name, cmd);
+ p = pmic_get(name);
+ if (!p)
+ return CMD_RET_FAILURE;
+
+ if (strcmp(cmd, "dump") == 0) {
+ if (pmic_dump(p))
+ return CMD_RET_FAILURE;
+ return CMD_RET_SUCCESS;
+ }
+
+ if (strcmp(cmd, "read") == 0) {
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ reg = simple_strtoul(argv[3], NULL, 16);
+ ret = pmic_reg_read(p, reg, &val);
+
+ if (ret)
+ puts("PMIC: Register read failed\n");
+
+ printf("\n0x%02x: 0x%08x\n", reg, val);
+
+ return CMD_RET_SUCCESS;
+ }
+
+ if (strcmp(cmd, "write") == 0) {
+ if (argc < 5)
+ return CMD_RET_USAGE;
+
+ reg = simple_strtoul(argv[3], NULL, 16);
+ val = simple_strtoul(argv[4], NULL, 16);
+ pmic_reg_write(p, reg, val);
+
+ return CMD_RET_SUCCESS;
+ }
+
+ if (strcmp(cmd, "bat") == 0) {
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ if (!p->pbat) {
+ printf("%s is not a battery\n", p->name);
+ return CMD_RET_FAILURE;
+ }
+
+ if (strcmp(argv[3], "state") == 0)
+ p->fg->fg_battery_check(p->pbat->fg, p);
+
+ if (strcmp(argv[3], "charge") == 0) {
+ printf("BAT: %s charging (ctrl+c to break)\n",
+ p->name);
+ if (p->low_power_mode)
+ p->low_power_mode();
+ if (p->pbat->battery_charge)
+ p->pbat->battery_charge(p);
+ }
+
+ return CMD_RET_SUCCESS;
+ }
+
+ /* No subcommand found */
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+ pmic, CONFIG_SYS_MAXARGS, 1, do_pmic,
+ "PMIC",
+ "list - list available PMICs\n"
+ "pmic name dump - dump named PMIC registers\n"
+ "pmic name read <reg> - read register\n"
+ "pmic name write <reg> <value> - write register\n"
+ "pmic name bat state - write register\n"
+ "pmic name bat charge - write register\n"
+);
+#endif
diff --git a/roms/u-boot/drivers/power/power_dialog.c b/roms/u-boot/drivers/power/power_dialog.c
new file mode 100644
index 000000000..e286dd108
--- /dev/null
+++ b/roms/u-boot/drivers/power/power_dialog.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <dialog_pmic.h>
+#include <errno.h>
+
+int pmic_dialog_init(unsigned char bus)
+{
+ static const char name[] = "DIALOG_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->number_of_regs = DIALOG_NUM_OF_REGS;
+
+ p->interface = PMIC_I2C;
+ p->hw.i2c.addr = CONFIG_SYS_DIALOG_PMIC_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/power_fsl.c b/roms/u-boot/drivers/power/power_fsl.c
new file mode 100644
index 000000000..a163300ab
--- /dev/null
+++ b/roms/u-boot/drivers/power/power_fsl.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <power/pmic.h>
+#include <fsl_pmic.h>
+#include <errno.h>
+
+#if defined(CONFIG_POWER_FSL_MC13892)
+#define FSL_PMIC_I2C_LENGTH 3
+#elif defined(CONFIG_POWER_FSL_MC34704)
+#define FSL_PMIC_I2C_LENGTH 1
+#endif
+
+#if defined(CONFIG_POWER_SPI)
+static u32 pmic_spi_prepare_tx(u32 reg, u32 *val, u32 write)
+{
+ return (write << 31) | (reg << 25) | (*val & 0x00FFFFFF);
+}
+#endif
+
+int pmic_init(unsigned char bus)
+{
+ static const char name[] = "FSL_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->bus = bus;
+
+#if defined(CONFIG_POWER_SPI)
+ p->interface = PMIC_SPI;
+ p->hw.spi.cs = CONFIG_FSL_PMIC_CS;
+ p->hw.spi.clk = CONFIG_FSL_PMIC_CLK;
+ p->hw.spi.mode = CONFIG_FSL_PMIC_MODE;
+ p->hw.spi.bitlen = CONFIG_FSL_PMIC_BITLEN;
+ p->hw.spi.flags = SPI_XFER_BEGIN | SPI_XFER_END;
+ p->hw.spi.prepare_tx = pmic_spi_prepare_tx;
+#elif defined(CONFIG_POWER_I2C)
+ p->interface = PMIC_I2C;
+ p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR;
+ p->hw.i2c.tx_num = FSL_PMIC_I2C_LENGTH;
+#else
+#error "You must select CONFIG_POWER_SPI or CONFIG_POWER_I2C"
+#endif
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/power_i2c.c b/roms/u-boot/drivers/power/power_i2c.c
new file mode 100644
index 000000000..b67ac2f02
--- /dev/null
+++ b/roms/u-boot/drivers/power/power_i2c.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
+ * (C) Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <log.h>
+#include <linux/types.h>
+#include <power/pmic.h>
+#include <i2c.h>
+#include <linux/compiler.h>
+
+int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
+{
+ unsigned char buf[4] = { 0 };
+
+ if (check_reg(p, reg))
+ return -EINVAL;
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(p->bus, pmic_i2c_addr,
+ 1, &dev);
+ if (ret) {
+ printf("%s: Cannot find udev for a bus %d\n", __func__,
+ p->bus);
+ return -ENXIO;
+ }
+#else /* Non DM I2C support - will be removed */
+ I2C_SET_BUS(p->bus);
+#endif
+
+ switch (pmic_i2c_tx_num) {
+ case 3:
+ if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) {
+ buf[2] = (cpu_to_le32(val) >> 16) & 0xff;
+ buf[1] = (cpu_to_le32(val) >> 8) & 0xff;
+ buf[0] = cpu_to_le32(val) & 0xff;
+ } else {
+ buf[0] = (cpu_to_le32(val) >> 16) & 0xff;
+ buf[1] = (cpu_to_le32(val) >> 8) & 0xff;
+ buf[2] = cpu_to_le32(val) & 0xff;
+ }
+ break;
+ case 2:
+ if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) {
+ buf[1] = (cpu_to_le32(val) >> 8) & 0xff;
+ buf[0] = cpu_to_le32(val) & 0xff;
+ } else {
+ buf[0] = (cpu_to_le32(val) >> 8) & 0xff;
+ buf[1] = cpu_to_le32(val) & 0xff;
+ }
+ break;
+ case 1:
+ buf[0] = cpu_to_le32(val) & 0xff;
+ break;
+ default:
+ printf("%s: invalid tx_num: %d", __func__, pmic_i2c_tx_num);
+ return -EINVAL;
+ }
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+ return dm_i2c_write(dev, reg, buf, pmic_i2c_tx_num);
+#else
+ return i2c_write(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num);
+#endif
+}
+
+int pmic_reg_read(struct pmic *p, u32 reg, u32 *val)
+{
+ unsigned char buf[4] = { 0 };
+ u32 ret_val = 0;
+ int ret;
+
+ if (check_reg(p, reg))
+ return -EINVAL;
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct udevice *dev;
+
+ ret = i2c_get_chip_for_busnum(p->bus, pmic_i2c_addr,
+ 1, &dev);
+ if (ret) {
+ printf("%s: Cannot find udev for a bus %d\n", __func__,
+ p->bus);
+ return -ENXIO;
+ }
+ ret = dm_i2c_read(dev, reg, buf, pmic_i2c_tx_num);
+#else /* Non DM I2C support - will be removed */
+ I2C_SET_BUS(p->bus);
+ ret = i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num);
+#endif
+ if (ret)
+ return ret;
+
+ switch (pmic_i2c_tx_num) {
+ case 3:
+ if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG)
+ ret_val = le32_to_cpu(buf[2] << 16
+ | buf[1] << 8 | buf[0]);
+ else
+ ret_val = le32_to_cpu(buf[0] << 16 |
+ buf[1] << 8 | buf[2]);
+ break;
+ case 2:
+ if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG)
+ ret_val = le32_to_cpu(buf[1] << 8 | buf[0]);
+ else
+ ret_val = le32_to_cpu(buf[0] << 8 | buf[1]);
+ break;
+ case 1:
+ ret_val = le32_to_cpu(buf[0]);
+ break;
+ default:
+ printf("%s: invalid tx_num: %d", __func__, pmic_i2c_tx_num);
+ return -EINVAL;
+ }
+ memcpy(val, &ret_val, sizeof(ret_val));
+
+ return 0;
+}
+
+int pmic_probe(struct pmic *p)
+{
+ debug("Bus: %d PMIC:%s probed!\n", p->bus, p->name);
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(p->bus, pmic_i2c_addr,
+ 1, &dev);
+ if (ret) {
+ printf("%s: Cannot find udev for a bus %d\n", __func__,
+ p->bus);
+ return -ENXIO;
+ }
+#else /* Non DM I2C support - will be removed */
+ i2c_set_bus_num(p->bus);
+ if (i2c_probe(pmic_i2c_addr)) {
+ printf("Can't find PMIC:%s\n", p->name);
+ return -ENODEV;
+ }
+#endif
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/power_spi.c b/roms/u-boot/drivers/power/power_spi.c
new file mode 100644
index 000000000..1eaf9773e
--- /dev/null
+++ b/roms/u-boot/drivers/power/power_spi.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <power/pmic.h>
+#include <spi.h>
+
+static struct spi_slave *slave;
+
+static u32 pmic_reg(struct pmic *p, u32 reg, u32 *val, u32 write)
+{
+ u32 pmic_tx, pmic_rx;
+ u32 tmp;
+
+ if (!slave) {
+ slave = spi_setup_slave(p->bus, p->hw.spi.cs, p->hw.spi.clk,
+ p->hw.spi.mode);
+
+ if (!slave)
+ return -ENODEV;
+ }
+
+ if (check_reg(p, reg))
+ return -EINVAL;
+
+ if (spi_claim_bus(slave))
+ return -EBUSY;
+
+ pmic_tx = p->hw.spi.prepare_tx(reg, val, write);
+
+ tmp = cpu_to_be32(pmic_tx);
+
+ if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx,
+ pmic_spi_flags))
+ goto err;
+
+ if (write) {
+ pmic_tx = p->hw.spi.prepare_tx(reg, val, 0);
+ tmp = cpu_to_be32(pmic_tx);
+ if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx,
+ pmic_spi_flags))
+ goto err;
+ }
+
+ spi_release_bus(slave);
+ *val = cpu_to_be32(pmic_rx);
+
+ return 0;
+
+err:
+ spi_release_bus(slave);
+ return -ENOTSUPP;
+}
+
+int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
+{
+ return pmic_reg(p, reg, &val, 1);
+}
+
+int pmic_reg_read(struct pmic *p, u32 reg, u32 *val)
+{
+ return pmic_reg(p, reg, val, 0);
+}
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,
+};
diff --git a/roms/u-boot/drivers/power/sy8106a.c b/roms/u-boot/drivers/power/sy8106a.c
new file mode 100644
index 000000000..45f479398
--- /dev/null
+++ b/roms/u-boot/drivers/power/sy8106a.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016
+ * Jelle van der Waa <jelle@vdwaa.nl>
+ */
+#include <common.h>
+#include <i2c.h>
+#include <sy8106a.h>
+
+#define SY8106A_I2C_ADDR 0x65
+#define SY8106A_VOUT1_SEL 1
+#define SY8106A_VOUT1_SEL_ENABLE (1 << 7)
+
+#ifdef CONFIG_SPL_BUILD
+static u8 sy8106a_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int sy8106a_set_vout1(unsigned int mvolt)
+{
+ u8 data = sy8106a_mvolt_to_cfg(mvolt, 680, 1950, 10) | SY8106A_VOUT1_SEL_ENABLE;
+ return i2c_write(SY8106A_I2C_ADDR, SY8106A_VOUT1_SEL, 1, &data, 1);
+}
+#endif
diff --git a/roms/u-boot/drivers/power/tps6586x.c b/roms/u-boot/drivers/power/tps6586x.c
new file mode 100644
index 000000000..49b28a5e6
--- /dev/null
+++ b/roms/u-boot/drivers/power/tps6586x.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <tps6586x.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include <linux/delay.h>
+
+static struct udevice *tps6586x_dev;
+
+enum {
+ /* Registers that we access */
+ SUPPLY_CONTROL1 = 0x20,
+ SUPPLY_CONTROL2,
+ SM1_VOLTAGE_V1 = 0x23,
+ SM1_VOLTAGE_V2,
+ SM0_VOLTAGE_V1 = 0x26,
+ SM0_VOLTAGE_V2,
+ PFM_MODE = 0x47,
+
+ /* Bits in the supply control registers */
+ CTRL_SM1_RAMP = 0x01,
+ CTRL_SM1_SUPPLY2 = 0x02,
+ CTRL_SM0_RAMP = 0x04,
+ CTRL_SM0_SUPPLY2 = 0x08,
+};
+
+#define MAX_I2C_RETRY 3
+static int tps6586x_read(int reg)
+{
+ int i;
+ uchar data;
+ int retval = -1;
+
+ for (i = 0; i < MAX_I2C_RETRY; ++i) {
+ if (!dm_i2c_read(tps6586x_dev, reg, &data, 1)) {
+ retval = (int)data;
+ goto exit;
+ }
+
+ /* i2c access failed, retry */
+ udelay(100);
+ }
+
+exit:
+ debug("pmu_read %x=%x\n", reg, retval);
+ if (retval < 0)
+ debug("%s: failed to read register %#x: %d\n", __func__, reg,
+ retval);
+ return retval;
+}
+
+static int tps6586x_write(int reg, uchar *data, uint len)
+{
+ int i;
+ int retval = -1;
+
+ for (i = 0; i < MAX_I2C_RETRY; ++i) {
+ if (!dm_i2c_write(tps6586x_dev, reg, data, len)) {
+ retval = 0;
+ goto exit;
+ }
+
+ /* i2c access failed, retry */
+ udelay(100);
+ }
+
+exit:
+ debug("pmu_write %x=%x: ", reg, retval);
+ for (i = 0; i < len; i++)
+ debug("%x ", data[i]);
+ if (retval)
+ debug("%s: failed to write register %#x\n", __func__, reg);
+ return retval;
+}
+
+/*
+ * Get current voltage of SM0 and SM1
+ *
+ * @param sm0 Place to put SM0 voltage
+ * @param sm1 Place to put SM1 voltage
+ * @return 0 if ok, -1 on error
+ */
+static int read_voltages(int *sm0, int *sm1)
+{
+ int ctrl1, ctrl2;
+ int is_v2;
+
+ /*
+ * Each vdd has two supply sources, ie, v1 and v2.
+ * The supply control reg1 and reg2 determine the current selection.
+ */
+ ctrl1 = tps6586x_read(SUPPLY_CONTROL1);
+ ctrl2 = tps6586x_read(SUPPLY_CONTROL2);
+ if (ctrl1 == -1 || ctrl2 == -1)
+ return -ENOTSUPP;
+
+ /* Figure out whether V1 or V2 is selected */
+ is_v2 = (ctrl1 | ctrl2) & CTRL_SM0_SUPPLY2;
+ *sm0 = tps6586x_read(is_v2 ? SM0_VOLTAGE_V2 : SM0_VOLTAGE_V1);
+ *sm1 = tps6586x_read(is_v2 ? SM1_VOLTAGE_V2 : SM1_VOLTAGE_V1);
+ if (*sm0 == -1 || *sm1 == -1)
+ return -ENOTSUPP;
+
+ return 0;
+}
+
+static int set_voltage(int reg, int data, int rate)
+{
+ uchar control_bit;
+ uchar buff[3];
+
+ control_bit = (reg == SM0_VOLTAGE_V1 ? CTRL_SM0_RAMP : CTRL_SM1_RAMP);
+
+ /*
+ * Only one supply is needed in u-boot. set both v1 and v2 to
+ * same value.
+ *
+ * When both v1 and v2 are set to same value, we just need to set
+ * control1 reg to trigger the supply selection.
+ */
+ buff[0] = buff[1] = (uchar)data;
+ buff[2] = rate;
+
+ /* write v1, v2 and rate, then trigger */
+ if (tps6586x_write(reg, buff, 3) ||
+ tps6586x_write(SUPPLY_CONTROL1, &control_bit, 1))
+ return -ENOTSUPP;
+
+ return 0;
+}
+
+static int calculate_next_voltage(int voltage, int target, int step)
+{
+ int diff = voltage < target ? step : -step;
+
+ if (abs(target - voltage) > step)
+ voltage += diff;
+ else
+ voltage = target;
+
+ return voltage;
+}
+
+int tps6586x_set_pwm_mode(int mask)
+{
+ uchar val;
+ int ret;
+
+ assert(tps6586x_dev);
+ ret = tps6586x_read(PFM_MODE);
+ if (ret != -1) {
+ val = (uchar)ret;
+ val |= mask;
+
+ ret = tps6586x_write(PFM_MODE, &val, 1);
+ }
+
+ if (ret == -1)
+ debug("%s: Failed to read/write PWM mode reg\n", __func__);
+
+ return ret;
+}
+
+int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,
+ int min_sm0_over_sm1)
+{
+ int sm0, sm1;
+ int bad;
+
+ assert(tps6586x_dev);
+
+ /* get current voltage settings */
+ if (read_voltages(&sm0, &sm1)) {
+ debug("%s: Cannot read voltage settings\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * if vdd_core < vdd_cpu + rel
+ * skip
+ *
+ * This condition may happen when system reboots due to kernel crash.
+ */
+ if (min_sm0_over_sm1 != -1 && sm0 < sm1 + min_sm0_over_sm1) {
+ debug("%s: SM0 is %d, SM1 is %d, but min_sm0_over_sm1 is %d\n",
+ __func__, sm0, sm1, min_sm0_over_sm1);
+ return -EINVAL;
+ }
+
+ /*
+ * Since vdd_core and vdd_cpu may both stand at either greater or less
+ * than their nominal voltage, the adjustment may go either directions.
+ *
+ * Make sure vdd_core is always higher than vdd_cpu with certain margin.
+ * So, find out which vdd to adjust first in each step.
+ *
+ * case 1: both sm0 and sm1 need to move up
+ * adjust sm0 before sm1
+ *
+ * case 2: both sm0 and sm1 need to move down
+ * adjust sm1 before sm0
+ *
+ * case 3: sm0 moves down and sm1 moves up
+ * adjusting either one first is fine.
+ *
+ * Adjust vdd_core and vdd_cpu one step at a time until they reach
+ * their nominal values.
+ */
+ bad = 0;
+ while (!bad && (sm0 != sm0_target || sm1 != sm1_target)) {
+ int adjust_sm0_late = 0; /* flag to adjust vdd_core later */
+
+ debug("%d-%d %d-%d ", sm0, sm0_target, sm1, sm1_target);
+
+ if (sm0 != sm0_target) {
+ /*
+ * if case 1 and case 3, set new sm0 first.
+ * otherwise, hold down until new sm1 is set.
+ */
+ sm0 = calculate_next_voltage(sm0, sm0_target, step);
+ if (sm1 < sm1_target)
+ bad |= set_voltage(SM0_VOLTAGE_V1, sm0, rate);
+ else
+ adjust_sm0_late = 1;
+ }
+
+ if (sm1 != sm1_target) {
+ sm1 = calculate_next_voltage(sm1, sm1_target, step);
+ bad |= set_voltage(SM1_VOLTAGE_V1, sm1, rate);
+ }
+
+ if (adjust_sm0_late)
+ bad |= set_voltage(SM0_VOLTAGE_V1, sm0, rate);
+ debug("%d\n", adjust_sm0_late);
+ }
+ debug("%d-%d %d-%d done\n", sm0, sm0_target, sm1, sm1_target);
+
+ return bad ? -EINVAL : 0;
+}
+
+int tps6586x_init(struct udevice *dev)
+{
+ tps6586x_dev = dev;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/power/twl4030.c b/roms/u-boot/drivers/power/twl4030.c
new file mode 100644
index 000000000..d3e8949af
--- /dev/null
+++ b/roms/u-boot/drivers/power/twl4030.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix at windriver.com>
+ *
+ * twl4030_power_reset_init is derived from code on omapzoom,
+ * git://git.omapzoom.com/repo/u-boot.git
+ *
+ * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ *
+ * twl4030_power_init is from cpu/omap3/common.c, power_init_r
+ *
+ * (C) Copyright 2004-2008
+ * Texas Instruments, <www.ti.com>
+ *
+ * Author :
+ * Sunil Kumar <sunilsaini05 at gmail.com>
+ * Shashi Ranjan <shashiranjanmca05 at gmail.com>
+ *
+ * Derived from Beagle Board and 3430 SDP code by
+ * Richard Woodruff <r-woodruff2 at ti.com>
+ * Syed Mohammed Khasim <khasim at ti.com>
+ */
+
+#include <command.h>
+#include <twl4030.h>
+#include <linux/delay.h>
+
+/*
+ * Power Reset
+ */
+void twl4030_power_reset_init(void)
+{
+ u8 val = 0;
+ if (twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_P1_SW_EVENTS, &val)) {
+ printf("Error:TWL4030: failed to read the power register\n");
+ printf("Could not initialize hardware reset\n");
+ } else {
+ val |= TWL4030_PM_MASTER_SW_EVENTS_STOPON_PWRON;
+ if (twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_P1_SW_EVENTS, val)) {
+ printf("Error:TWL4030: failed to write the power register\n");
+ printf("Could not initialize hardware reset\n");
+ }
+ }
+}
+
+/*
+ * Power off
+ */
+void twl4030_power_off(void)
+{
+ u8 data;
+
+ /* PM master unlock (CFG and TST keys) */
+
+ data = 0xCE;
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_PROTECT_KEY, data);
+ data = 0xEC;
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_PROTECT_KEY, data);
+
+ /* VBAT start disable */
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_CFG_P1_TRANSITION, &data);
+ data &= ~TWL4030_PM_MASTER_CFG_TRANSITION_STARTON_VBAT;
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_CFG_P1_TRANSITION, data);
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_CFG_P2_TRANSITION, &data);
+ data &= ~TWL4030_PM_MASTER_CFG_TRANSITION_STARTON_VBAT;
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_CFG_P2_TRANSITION, data);
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_CFG_P3_TRANSITION, &data);
+ data &= ~TWL4030_PM_MASTER_CFG_TRANSITION_STARTON_VBAT;
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_CFG_P3_TRANSITION, data);
+
+ /* High jitter for PWRANA2 */
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_CFG_PWRANA2, &data);
+ data &= ~(TWL4030_PM_MASTER_CFG_PWRANA2_LOJIT0_LOWV |
+ TWL4030_PM_MASTER_CFG_PWRANA2_LOJIT1_LOWV);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_CFG_PWRANA2, data);
+
+ /* PM master lock */
+
+ data = 0xFF;
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_PROTECT_KEY, data);
+
+ /* Power off */
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_P1_SW_EVENTS, &data);
+ data |= TWL4030_PM_MASTER_SW_EVENTS_DEVOFF;
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_P1_SW_EVENTS, data);
+}
+
+/*
+ * Set Device Group and Voltage
+ */
+void twl4030_pmrecv_vsel_cfg(u8 vsel_reg, u8 vsel_val,
+ u8 dev_grp, u8 dev_grp_sel)
+{
+ int ret;
+
+ /* Select the Voltage */
+ ret = twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, vsel_reg,
+ vsel_val);
+ if (ret != 0) {
+ printf("Could not write vsel to reg %02x (%d)\n",
+ vsel_reg, ret);
+ return;
+ }
+
+ /* Select the Device Group (enable the supply if dev_grp_sel != 0) */
+ ret = twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, dev_grp,
+ dev_grp_sel);
+ if (ret != 0)
+ printf("Could not write grp_sel to reg %02x (%d)\n",
+ dev_grp, ret);
+}
+
+void twl4030_power_init(void)
+{
+ /* set VAUX3 to 2.8V */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VAUX3_DEDICATED,
+ TWL4030_PM_RECEIVER_VAUX3_VSEL_28,
+ TWL4030_PM_RECEIVER_VAUX3_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+
+ /* set VPLL2 to 1.8V */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VPLL2_DEDICATED,
+ TWL4030_PM_RECEIVER_VPLL2_VSEL_18,
+ TWL4030_PM_RECEIVER_VPLL2_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_ALL);
+
+ /* set VDAC to 1.8V */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VDAC_DEDICATED,
+ TWL4030_PM_RECEIVER_VDAC_VSEL_18,
+ TWL4030_PM_RECEIVER_VDAC_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+}
+
+void twl4030_power_mmc_init(int dev_index)
+{
+ if (dev_index == 0) {
+ /* Set VMMC1 to 3.15 Volts */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VMMC1_DEDICATED,
+ TWL4030_PM_RECEIVER_VMMC1_VSEL_32,
+ TWL4030_PM_RECEIVER_VMMC1_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+
+ mdelay(100); /* ramp-up delay from Linux code */
+ } else if (dev_index == 1) {
+ /* Set VMMC2 to 3.15 Volts */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VMMC2_DEDICATED,
+ TWL4030_PM_RECEIVER_VMMC2_VSEL_32,
+ TWL4030_PM_RECEIVER_VMMC2_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+
+ mdelay(100); /* ramp-up delay from Linux code */
+ }
+}
+
+#ifdef CONFIG_CMD_POWEROFF
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ twl4030_power_off();
+
+ return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+int twl4030_i2c_write_u8(u8 chip_no, u8 reg, u8 val)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev);
+ if (ret) {
+ pr_err("unable to get I2C bus. ret %d\n", ret);
+ return ret;
+ }
+ ret = dm_i2c_reg_write(dev, reg, val);
+ if (ret) {
+ pr_err("writing to twl4030 failed. ret %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+int twl4030_i2c_read(u8 chip_no, u8 reg, u8 *valp, int len)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev);
+ if (ret) {
+ pr_err("unable to get I2C bus. ret %d\n", ret);
+ return ret;
+ }
+ ret = dm_i2c_read(dev, reg, valp, len);
+ if (ret) {
+ pr_err("reading from twl4030 failed. ret %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/drivers/power/twl6030.c b/roms/u-boot/drivers/power/twl6030.c
new file mode 100644
index 000000000..2b50a56fa
--- /dev/null
+++ b/roms/u-boot/drivers/power/twl6030.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ */
+#include <config.h>
+#include <linux/delay.h>
+
+#include <twl6030.h>
+
+static struct twl6030_data *twl;
+
+static struct twl6030_data twl6030_info = {
+ .chip_type = chip_TWL6030,
+ .adc_rbase = GPCH0_LSB,
+ .adc_ctrl = CTRL_P2,
+ .adc_enable = CTRL_P2_SP2,
+ .vbat_mult = TWL6030_VBAT_MULT,
+ .vbat_shift = TWL6030_VBAT_SHIFT,
+};
+
+static struct twl6030_data twl6032_info = {
+ .chip_type = chip_TWL6032,
+ .adc_rbase = TWL6032_GPCH0_LSB,
+ .adc_ctrl = TWL6032_CTRL_P1,
+ .adc_enable = CTRL_P1_SP1,
+ .vbat_mult = TWL6032_VBAT_MULT,
+ .vbat_shift = TWL6032_VBAT_SHIFT,
+};
+
+
+static int twl6030_gpadc_read_channel(u8 channel_no)
+{
+ u8 lsb = 0;
+ u8 msb = 0;
+ int ret = 0;
+
+ ret = twl6030_i2c_read_u8(TWL6030_CHIP_ADC,
+ twl->adc_rbase + channel_no * 2, &lsb);
+ if (ret)
+ return ret;
+
+ ret = twl6030_i2c_read_u8(TWL6030_CHIP_ADC,
+ twl->adc_rbase + 1 + channel_no * 2, &msb);
+ if (ret)
+ return ret;
+
+ return (msb << 8) | lsb;
+}
+
+static int twl6030_gpadc_sw2_trigger(void)
+{
+ u8 val;
+ int ret = 0;
+
+ ret = twl6030_i2c_write_u8(TWL6030_CHIP_ADC,
+ twl->adc_ctrl, twl->adc_enable);
+ if (ret)
+ return ret;
+
+ /* Waiting until the SW1 conversion ends*/
+ val = CTRL_P2_BUSY;
+
+ while (!((val & CTRL_P2_EOCP2) && (!(val & CTRL_P2_BUSY)))) {
+ ret = twl6030_i2c_read_u8(TWL6030_CHIP_ADC,
+ twl->adc_ctrl, &val);
+ if (ret)
+ return ret;
+ udelay(1000);
+ }
+
+ return 0;
+}
+
+void twl6030_power_off(void)
+{
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_PHOENIX_DEV_ON,
+ TWL6030_PHOENIX_APP_DEVOFF | TWL6030_PHOENIX_CON_DEVOFF |
+ TWL6030_PHOENIX_MOD_DEVOFF);
+}
+
+void twl6030_stop_usb_charging(void)
+{
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER, CONTROLLER_CTRL1, 0);
+
+ return;
+}
+
+void twl6030_start_usb_charging(void)
+{
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_VICHRG, CHARGERUSB_VICHRG_1500);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_CINLIMIT, CHARGERUSB_CIN_LIMIT_NONE);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CONTROLLER_INT_MASK, MBAT_TEMP);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_INT_MASK, MASK_MCHARGERUSB_THMREG);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_VOREG, CHARGERUSB_VOREG_4P0);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_CTRL2, CHARGERUSB_CTRL2_VITERM_400);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER, CHARGERUSB_CTRL1, TERM);
+ /* Enable USB charging */
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CONTROLLER_CTRL1, CONTROLLER_CTRL1_EN_CHARGER);
+ return;
+}
+
+int twl6030_get_battery_current(void)
+{
+ int battery_current = 0;
+ u8 msb = 0;
+ u8 lsb = 0;
+
+ twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, FG_REG_11, &msb);
+ twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, FG_REG_10, &lsb);
+ battery_current = ((msb << 8) | lsb);
+
+ /* convert 10 bit signed number to 16 bit signed number */
+ if (battery_current >= 0x2000)
+ battery_current = (battery_current - 0x4000);
+
+ battery_current = battery_current * 3000 / 4096;
+ printf("Battery Current: %d mA\n", battery_current);
+
+ return battery_current;
+}
+
+int twl6030_get_battery_voltage(void)
+{
+ int battery_volt = 0;
+ int ret = 0;
+ u8 vbatch;
+
+ if (twl->chip_type == chip_TWL6030) {
+ vbatch = TWL6030_GPADC_VBAT_CHNL;
+ } else {
+ ret = twl6030_i2c_write_u8(TWL6030_CHIP_ADC,
+ TWL6032_GPSELECT_ISB,
+ TWL6032_GPADC_VBAT_CHNL);
+ if (ret)
+ return ret;
+ vbatch = 0;
+ }
+
+ /* Start GPADC SW conversion */
+ ret = twl6030_gpadc_sw2_trigger();
+ if (ret) {
+ printf("Failed to convert battery voltage\n");
+ return ret;
+ }
+
+ /* measure Vbat voltage */
+ battery_volt = twl6030_gpadc_read_channel(vbatch);
+ if (battery_volt < 0) {
+ printf("Failed to read battery voltage\n");
+ return ret;
+ }
+ battery_volt = (battery_volt * twl->vbat_mult) >> twl->vbat_shift;
+ printf("Battery Voltage: %d mV\n", battery_volt);
+
+ return battery_volt;
+}
+
+void twl6030_init_battery_charging(void)
+{
+ u8 val = 0;
+ int battery_volt = 0;
+ int ret = 0;
+
+ ret = twl6030_i2c_read_u8(TWL6030_CHIP_USB, USB_PRODUCT_ID_LSB, &val);
+ if (ret) {
+ puts("twl6030_init_battery_charging(): could not determine chip!\n");
+ return;
+ }
+ if (val == 0x30) {
+ twl = &twl6030_info;
+ } else if (val == 0x32) {
+ twl = &twl6032_info;
+ } else {
+ puts("twl6030_init_battery_charging(): unsupported chip type\n");
+ return;
+ }
+
+ /* Enable VBAT measurement */
+ if (twl->chip_type == chip_TWL6030) {
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, MISC1, VBAT_MEAS);
+ twl6030_i2c_write_u8(TWL6030_CHIP_ADC,
+ TWL6030_GPADC_CTRL,
+ GPADC_CTRL_SCALER_DIV4);
+ } else {
+ twl6030_i2c_write_u8(TWL6030_CHIP_ADC,
+ TWL6032_GPADC_CTRL2,
+ GPADC_CTRL2_CH18_SCALER_EN);
+ }
+
+ /* Enable GPADC module */
+ ret = twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER, TOGGLE1, FGS | GPADCS);
+ if (ret) {
+ printf("Failed to enable GPADC\n");
+ return;
+ }
+
+ battery_volt = twl6030_get_battery_voltage();
+ if (battery_volt < 0)
+ return;
+
+ if (battery_volt < 3000)
+ printf("Main battery voltage too low!\n");
+
+ /* Check for the presence of USB charger */
+ twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, CONTROLLER_STAT1, &val);
+
+ /* check for battery presence indirectly via Fuel gauge */
+ if ((val & VBUS_DET) && (battery_volt < 3300))
+ twl6030_start_usb_charging();
+
+ return;
+}
+
+void twl6030_power_mmc_init(int dev_index)
+{
+ u8 value = 0;
+
+ if (dev_index == 0) {
+ /* 3.0V voltage output for VMMC */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_VMMC_CFG_VOLTAGE,
+ TWL6030_CFG_VOLTAGE_30);
+
+ /* Enable P1 output for VMMC */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_VMMC_CFG_STATE,
+ TWL6030_CFG_STATE_P1 | TWL6030_CFG_STATE_ON);
+ } else if (dev_index == 1) {
+ twl6030_i2c_read_u8(TWL6030_CHIP_PM, TWL6030_PH_STS_BOOT,
+ &value);
+ /* BOOT2 indicates 1.8V/2.8V VAUX1 for eMMC */
+ if (value & TWL6030_PH_STS_BOOT2) {
+ /* 1.8V voltage output for VAUX1 */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_VAUX1_CFG_VOLTAGE,
+ TWL6030_CFG_VOLTAGE_18);
+ } else {
+ /* 2.8V voltage output for VAUX1 */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_VAUX1_CFG_VOLTAGE,
+ TWL6030_CFG_VOLTAGE_28);
+ }
+
+ /* Enable P1 output for VAUX */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_VAUX1_CFG_STATE,
+ TWL6030_CFG_STATE_P1 | TWL6030_CFG_STATE_ON);
+ }
+}
+
+void twl6030_usb_device_settings()
+{
+ u8 value = 0;
+
+ /* 3.3V voltage output for VUSB */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_VUSB_CFG_VOLTAGE,
+ TWL6030_CFG_VOLTAGE_33);
+
+ /* Enable P1 output for VUSB */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_VUSB_CFG_STATE,
+ TWL6030_CFG_STATE_P1 | TWL6030_CFG_STATE_ON);
+
+ /* Select the input supply for VUSB regulator */
+ twl6030_i2c_read_u8(TWL6030_CHIP_PM, TWL6030_MISC2, &value);
+ value |= TWL6030_MISC2_VUSB_IN_VSYS;
+ value &= ~TWL6030_MISC2_VUSB_IN_PMID;
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, TWL6030_MISC2, value);
+}
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+int twl6030_i2c_write_u8(u8 chip_no, u8 reg, u8 val)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev);
+ if (ret) {
+ pr_err("unable to get I2C bus. ret %d\n", ret);
+ return ret;
+ }
+ ret = dm_i2c_reg_write(dev, reg, val);
+ if (ret) {
+ pr_err("writing to twl6030 failed. ret %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+int twl6030_i2c_read_u8(u8 chip_no, u8 reg, u8 *valp)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(0, chip_no, 1, &dev);
+ if (ret) {
+ pr_err("unable to get I2C bus. ret %d\n", ret);
+ return ret;
+ }
+ ret = dm_i2c_reg_read(dev, reg);
+ if (ret < 0) {
+ pr_err("reading from twl6030 failed. ret %d\n", ret);
+ return ret;
+ }
+ *valp = (u8)ret;
+ return 0;
+}
+#endif