summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-11-04 09:55:39 -0400
committerTom Rini <trini@konsulko.com>2023-11-04 09:55:39 -0400
commita4c83bda17196bf5d1ce640844595aaeced6465e (patch)
treed3796998ac6eabc3e8b7bcdf0d86fdc2b482ad74 /drivers
parent51d6cdb3c0989babb6675b0d42989c2ee5ac8ddb (diff)
parent4afdc7a3c63d99b53676d31cc38e18de15a036f5 (diff)
downloadu-boot-a4c83bda17196bf5d1ce640844595aaeced6465e.tar.gz
u-boot-a4c83bda17196bf5d1ce640844595aaeced6465e.tar.bz2
u-boot-a4c83bda17196bf5d1ce640844595aaeced6465e.zip
Merge branch '2023-11-03-assorted-tegra-improvements'
- Assorted improvements for Tegra platforms
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/tegra_mmc.c52
-rw-r--r--drivers/power/pmic/Kconfig20
-rw-r--r--drivers/power/pmic/Makefile2
-rw-r--r--drivers/power/pmic/max77663.c90
-rw-r--r--drivers/power/pmic/palmas.c34
-rw-r--r--drivers/power/pmic/pmic_tps65910_dm.c27
-rw-r--r--drivers/power/pmic/tps80031.c91
-rw-r--r--drivers/power/regulator/Kconfig28
-rw-r--r--drivers/power/regulator/Makefile3
-rw-r--r--drivers/power/regulator/max77663_regulator.c375
-rw-r--r--drivers/power/regulator/palmas_regulator.c24
-rw-r--r--drivers/power/regulator/tps65911_regulator.c395
-rw-r--r--drivers/power/regulator/tps80031_regulator.c347
-rw-r--r--drivers/sysreset/Kconfig36
-rw-r--r--drivers/sysreset/Makefile5
-rw-r--r--drivers/sysreset/sysreset_max77663.c52
-rw-r--r--drivers/sysreset/sysreset_palmas.c52
-rw-r--r--drivers/sysreset/sysreset_tegra.c45
-rw-r--r--drivers/sysreset/sysreset_tps65910.c54
-rw-r--r--drivers/sysreset/sysreset_tps80031.c40
20 files changed, 1731 insertions, 41 deletions
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index f76fee3ea0..d507adbb36 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -37,6 +37,9 @@ struct tegra_mmc_priv {
unsigned int version; /* SDHCI spec. version */
unsigned int clock; /* Current clock (MHz) */
int mmc_id; /* peripheral id */
+
+ int tap_value;
+ int trim_value;
};
static void tegra_mmc_set_power(struct tegra_mmc_priv *priv,
@@ -526,31 +529,6 @@ static void tegra_mmc_pad_init(struct tegra_mmc_priv *priv)
printf("%s: Warning: Autocal timed out!\n", __func__);
/* TBD: Set CFG2TMC_SDMMC1_PAD_CAL_DRV* regs here */
}
-
-#if defined(CONFIG_TEGRA210)
- u32 tap_value, trim_value;
-
- /* Set tap/trim values for SDMMC1/3 @ <48MHz here */
- val = readl(&priv->reg->venspictl); /* aka VENDOR_SYS_SW_CNTL */
- val &= IO_TRIM_BYPASS_MASK;
- if (id == PERIPH_ID_SDMMC1) {
- tap_value = 4; /* default */
- if (val)
- tap_value = 3;
- trim_value = 2;
- } else { /* SDMMC3 */
- tap_value = 3;
- trim_value = 3;
- }
-
- val = readl(&priv->reg->venclkctl);
- val &= ~TRIM_VAL_MASK;
- val |= (trim_value << TRIM_VAL_SHIFT);
- val &= ~TAP_VAL_MASK;
- val |= (tap_value << TAP_VAL_SHIFT);
- writel(val, &priv->reg->venclkctl);
- debug("%s: VENDOR_CLOCK_CNTRL = 0x%08X\n", __func__, val);
-#endif /* T210 */
#endif /* T30/T210 */
}
@@ -588,6 +566,22 @@ static void tegra_mmc_reset(struct tegra_mmc_priv *priv, struct mmc *mmc)
/* Make sure SDIO pads are set up */
tegra_mmc_pad_init(priv);
+
+ if (!IS_ERR_VALUE(priv->tap_value) ||
+ !IS_ERR_VALUE(priv->trim_value)) {
+ u32 val;
+
+ val = readl(&priv->reg->venclkctl);
+
+ val &= ~TRIM_VAL_MASK;
+ val |= (priv->trim_value << TRIM_VAL_SHIFT);
+
+ val &= ~TAP_VAL_MASK;
+ val |= (priv->tap_value << TAP_VAL_SHIFT);
+
+ writel(val, &priv->reg->venclkctl);
+ debug("%s: VENDOR_CLOCK_CNTRL = 0x%08X\n", __func__, val);
+ }
}
static int tegra_mmc_init(struct udevice *dev)
@@ -742,6 +736,14 @@ static int tegra_mmc_probe(struct udevice *dev)
if (dm_gpio_is_valid(&priv->pwr_gpio))
dm_gpio_set_value(&priv->pwr_gpio, 1);
+ ret = dev_read_u32(dev, "nvidia,default-tap", &priv->tap_value);
+ if (ret)
+ priv->tap_value = ret;
+
+ ret = dev_read_u32(dev, "nvidia,default-trim", &priv->trim_value);
+ if (ret)
+ priv->trim_value = ret;
+
upriv->mmc = &plat->mmc;
return tegra_mmc_init(dev);
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 4a6f0ce093..454a6e0cf8 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -184,6 +184,15 @@ config SPL_DM_PMIC_PFUZE100
This config enables implementation of driver-model pmic uclass features
for PMIC PFUZE100 in SPL. The driver implements read/write operations.
+config DM_PMIC_MAX77663
+ bool "Enable Driver Model for PMIC MAX77663"
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC MAX77663. The driver implements read/write operations.
+ This is a Power Management IC with a decent set of peripherals from which
+ 4 DC-to-DC Step-Down (SD) Regulators, 9 Low-Dropout Linear (LDO) Regulators,
+ 8 GPIOs, Real-Time Clock (RTC) and more with I2C Compatible Interface.
+
config DM_PMIC_MAX77686
bool "Enable Driver Model for PMIC MAX77686"
---help---
@@ -342,6 +351,17 @@ config DM_PMIC_TPS65910
DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO
pmic children.
+config DM_PMIC_TPS80031
+ bool "Enable driver for Texas Instruments TPS80031/TPS80032 PMIC"
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for TPS80031/TPS80032 PMICs. The driver implements read/write operations.
+ This is a Power Management IC with a decent set of peripherals from which
+ 5 Buck Converters refered as Switched-mode power supply (SMPS), 11 General-
+ Purpose Low-Dropout Voltage Regulators (LDO), USB OTG Module, Real-Time
+ Clock (RTC) with Timer and Alarm Wake-Up, Two Digital PWM Outputs and more
+ with I2C Compatible Interface. PMIC occupies 4 I2C addresses.
+
config PMIC_STPMIC1
bool "Enable support for STMicroelectronics STPMIC1 PMIC"
depends on DM_I2C
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 0b3b3d62d0..55ee614364 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_$(SPL_TPL_)DM_PMIC) += pmic-uclass.o
obj-$(CONFIG_$(SPL_)DM_PMIC_FAN53555) += fan53555.o
obj-$(CONFIG_$(SPL_)DM_PMIC_DA9063) += da9063.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_MAX77663) += max77663.o
obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o
obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o
obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_$(SPL_)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_)DM_PMIC_TPS80031) += tps80031.o
obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o
obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o
diff --git a/drivers/power/pmic/max77663.c b/drivers/power/pmic/max77663.c
new file mode 100644
index 0000000000..68c3cbbc64
--- /dev/null
+++ b/drivers/power/pmic/max77663.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <dm/lists.h>
+#include <power/pmic.h>
+#include <power/max77663.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = MAX77663_LDO_DRIVER },
+ { .prefix = "sd", .driver = MAX77663_SD_DRIVER },
+ { },
+};
+
+static int max77663_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret) {
+ log_debug("write error to device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max77663_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret) {
+ log_debug("read error from device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max77663_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children, ret;
+
+ if (IS_ENABLED(CONFIG_SYSRESET_MAX77663)) {
+ ret = device_bind_driver(dev, MAX77663_RST_DRIVER,
+ "sysreset", NULL);
+ if (ret) {
+ log_err("cannot bind SYSRESET (ret = %d)\n", ret);
+ return ret;
+ }
+ }
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ log_err("%s regulators subnode not found!\n", 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)
+ log_err("%s - no child found\n", dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops max77663_ops = {
+ .read = max77663_read,
+ .write = max77663_write,
+};
+
+static const struct udevice_id max77663_ids[] = {
+ { .compatible = "maxim,max77663" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_max77663) = {
+ .name = "max77663_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = max77663_ids,
+ .bind = max77663_bind,
+ .ops = &max77663_ops,
+};
diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c
index eb83c88d56..32f2a938b2 100644
--- a/drivers/power/pmic/palmas.c
+++ b/drivers/power/pmic/palmas.c
@@ -8,13 +8,13 @@
#include <fdtdec.h>
#include <errno.h>
#include <dm.h>
+#include <dm/lists.h>
#include <i2c.h>
#include <log.h>
#include <linux/printk.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 },
@@ -47,7 +47,16 @@ static int palmas_bind(struct udevice *dev)
{
ofnode pmic_node = ofnode_null(), regulators_node;
ofnode subnode;
- int children;
+ int children, ret;
+
+ if (IS_ENABLED(CONFIG_SYSRESET_PALMAS)) {
+ ret = device_bind_driver(dev, PALMAS_RST_DRIVER,
+ "sysreset", NULL);
+ if (ret) {
+ log_err("cannot bind SYSRESET (ret = %d)\n", ret);
+ return ret;
+ }
+ }
dev_for_each_subnode(subnode, dev) {
const char *name;
@@ -81,6 +90,24 @@ static int palmas_bind(struct udevice *dev)
return 0;
}
+static int palmas_probe(struct udevice *dev)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct palmas_priv *priv = dev_get_priv(dev);
+ struct udevice *bus = dev_get_parent(dev);
+ u32 chip2_addr = chip->chip_addr + 1;
+ int ret;
+
+ /* Palmas PMIC is multi chip and chips are located in a row */
+ ret = i2c_get_chip(bus, chip2_addr, 1, &priv->chip2);
+ if (ret) {
+ log_err("cannot get second PMIC I2C chip (err %d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static struct dm_pmic_ops palmas_ops = {
.read = palmas_read,
.write = palmas_write,
@@ -88,6 +115,7 @@ static struct dm_pmic_ops palmas_ops = {
static const struct udevice_id palmas_ids[] = {
{ .compatible = "ti,tps659038", .data = TPS659038 },
+ { .compatible = "ti,tps65913" , .data = TPS659038 },
{ .compatible = "ti,tps65917" , .data = TPS65917 },
{ }
};
@@ -97,5 +125,7 @@ U_BOOT_DRIVER(pmic_palmas) = {
.id = UCLASS_PMIC,
.of_match = palmas_ids,
.bind = palmas_bind,
+ .probe = palmas_probe,
.ops = &palmas_ops,
+ .priv_auto = sizeof(struct palmas_priv),
};
diff --git a/drivers/power/pmic/pmic_tps65910_dm.c b/drivers/power/pmic/pmic_tps65910_dm.c
index 8ead1db802..ecf836eb0e 100644
--- a/drivers/power/pmic/pmic_tps65910_dm.c
+++ b/drivers/power/pmic/pmic_tps65910_dm.c
@@ -5,6 +5,7 @@
#include <common.h>
#include <dm.h>
+#include <dm/lists.h>
#include <i2c.h>
#include <log.h>
#include <linux/printk.h>
@@ -12,13 +13,19 @@
#include <power/regulator.h>
#include <power/tps65910_pmic.h>
-static const struct pmic_child_info pmic_children_info[] = {
+static const struct pmic_child_info tps65910_children_info[] = {
{ .prefix = "ldo_", .driver = TPS65910_LDO_DRIVER },
{ .prefix = "buck_", .driver = TPS65910_BUCK_DRIVER },
{ .prefix = "boost_", .driver = TPS65910_BOOST_DRIVER },
{ },
};
+static const struct pmic_child_info tps65911_children_info[] = {
+ { .prefix = "ldo", .driver = TPS65911_LDO_DRIVER },
+ { .prefix = "vdd", .driver = TPS65911_VDD_DRIVER },
+ { },
+};
+
static int pmic_tps65910_reg_count(struct udevice *dev)
{
return TPS65910_NUM_REGS;
@@ -50,8 +57,19 @@ static int pmic_tps65910_read(struct udevice *dev, uint reg, u8 *buffer,
static int pmic_tps65910_bind(struct udevice *dev)
{
+ const struct pmic_child_info *tps6591x_children_info =
+ (struct pmic_child_info *)dev_get_driver_data(dev);
ofnode regulators_node;
- int children;
+ int children, ret;
+
+ if (IS_ENABLED(CONFIG_SYSRESET_TPS65910)) {
+ ret = device_bind_driver(dev, TPS65910_RST_DRIVER,
+ "sysreset", NULL);
+ if (ret) {
+ log_err("cannot bind SYSRESET (ret = %d)\n", ret);
+ return ret;
+ }
+ }
regulators_node = dev_read_subnode(dev, "regulators");
if (!ofnode_valid(regulators_node)) {
@@ -59,7 +77,7 @@ static int pmic_tps65910_bind(struct udevice *dev)
return -EINVAL;
}
- children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ children = pmic_bind_children(dev, regulators_node, tps6591x_children_info);
if (!children)
debug("%s has no children (regulators)\n", dev->name);
@@ -83,7 +101,8 @@ static struct dm_pmic_ops pmic_tps65910_ops = {
};
static const struct udevice_id pmic_tps65910_match[] = {
- { .compatible = "ti,tps65910" },
+ { .compatible = "ti,tps65910", .data = (ulong)&tps65910_children_info },
+ { .compatible = "ti,tps65911", .data = (ulong)&tps65911_children_info },
{ /* sentinel */ }
};
diff --git a/drivers/power/pmic/tps80031.c b/drivers/power/pmic/tps80031.c
new file mode 100644
index 0000000000..a2f935b0c6
--- /dev/null
+++ b/drivers/power/pmic/tps80031.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <dm/lists.h>
+#include <power/pmic.h>
+#include <power/tps80031.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = TPS80031_LDO_DRIVER },
+ { .prefix = "smps", .driver = TPS80031_SMPS_DRIVER },
+ { },
+};
+
+static int tps80031_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret) {
+ log_debug("write error to device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps80031_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret) {
+ log_debug("read error from device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps80031_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children, ret;
+
+ if (IS_ENABLED(CONFIG_SYSRESET_TPS80031)) {
+ ret = device_bind_driver(dev, TPS80031_RST_DRIVER,
+ "sysreset", NULL);
+ if (ret) {
+ log_err("cannot bind SYSRESET (ret = %d)\n", ret);
+ return ret;
+ }
+ }
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ log_err("%s regulators subnode not found!\n", 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)
+ log_err("%s - no child found\n", dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops tps80031_ops = {
+ .read = tps80031_read,
+ .write = tps80031_write,
+};
+
+static const struct udevice_id tps80031_ids[] = {
+ { .compatible = "ti,tps80031" },
+ { .compatible = "ti,tps80032" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_tps80031) = {
+ .name = "tps80031_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = tps80031_ids,
+ .bind = tps80031_bind,
+ .ops = &tps80031_ops,
+};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index eb5aa38c1c..102ec7bc5f 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -141,6 +141,15 @@ config SPL_REGULATOR_PWM
This config enables implementation of driver-model regulator uclass
features for PWM regulators in SPL.
+config DM_REGULATOR_MAX77663
+ bool "Enable Driver Model for REGULATOR MAX77663"
+ depends on DM_REGULATOR && DM_PMIC_MAX77663
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for REGULATOR MAX77663. The driver supports both DC-to-DC
+ Step-Down (SD) Regulators and Low-Dropout Linear (LDO) Regulators
+ found in MAX77663 PMIC and implements get/set api for value and enable.
+
config DM_REGULATOR_MAX77686
bool "Enable Driver Model for REGULATOR MAX77686"
depends on DM_REGULATOR && DM_PMIC_MAX77686
@@ -337,6 +346,17 @@ config DM_REGULATOR_TPS65910
regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements
the get/set api for value and enable.
+config DM_REGULATOR_TPS65911
+ bool "Enable driver for TPS65911 PMIC regulators"
+ depends on DM_PMIC_TPS65910
+ ---help---
+ This config enables implementation of driver-model regulator
+ uclass features for the TPS65911 PMIC. The driver supports Step-Down
+ DC-DC Converters for Processor Cores (VDD1 and VDD2), Step-Down DC-DC
+ Converter for I/O Power (VIO), Controller for External FETs (VDDCtrl)
+ and LDO Voltage Regulators found in TPS65911 PMIC and implements
+ get/set api for value and enable.
+
config DM_REGULATOR_TPS62360
bool "Enable driver for TPS6236x Power Regulator"
depends on DM_REGULATOR
@@ -347,6 +367,14 @@ config DM_REGULATOR_TPS62360
implements the get/set api for value only, as the power line is
always on.
+config DM_REGULATOR_TPS80031
+ bool "Enable driver for TPS80031/TPS80032 PMIC regulators"
+ depends on DM_PMIC_TPS80031
+ ---help---
+ This enables implementation of driver-model regulator uclass
+ features for TPS80031/TPS80032 PMICs. The driver implements
+ get/set api for: value and enable.
+
config DM_REGULATOR_STPMIC1
bool "Enable driver for STPMIC1 regulators"
depends on DM_REGULATOR && PMIC_STPMIC1
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index d9e0cd5949..f79932d833 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o
obj-$(CONFIG_$(SPL_)REGULATOR_AXP) += axp_regulator.o
obj-$(CONFIG_$(SPL_)REGULATOR_AXP_USB_POWER) += axp_usb_power.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_DA9063) += da9063.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_MAX77663) += max77663_regulator.o
obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o
obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
@@ -31,7 +32,9 @@ 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_$(SPL_)DM_REGULATOR_TPS65911) += tps65911_regulator.o
obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS80031) += tps80031_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
diff --git a/drivers/power/regulator/max77663_regulator.c b/drivers/power/regulator/max77663_regulator.c
new file mode 100644
index 0000000000..ea4b7c63e5
--- /dev/null
+++ b/drivers/power/regulator/max77663_regulator.c
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/max77663.h>
+
+/* fist row is control registers, second is voltage registers */
+static const char max77663_sd_reg[][MAX77663_SD_NUM] = {
+ { 0x1d, 0x1e, 0x1f, 0x20, 0x21 },
+ { 0x16, 0x17, 0x18, 0x19, 0x2a },
+};
+
+static const char max77663_ldo_reg[MAX77663_LDO_NUM] = {
+ 0x23, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x2f, 0x31, 0x33
+};
+
+static int max77663_sd_enable(struct udevice *dev, int op, bool *enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ if (val & SD_STATUS_MASK)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ val &= ~SD_STATUS_MASK;
+
+ if (*enable)
+ val |= SD_STATUS_MASK;
+
+ ret = pmic_reg_write(dev->parent, adr, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * max77663_*_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @idx: regulator index
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int max77663_sd_volt2hex(int idx, int uV)
+{
+ switch (idx) {
+ case 0:
+ /* SD0 has max voltage 1.4V */
+ if (uV > SD0_VOLT_MAX)
+ return -EINVAL;
+ break;
+ case 1:
+ /* SD1 has max voltage 1.55V */
+ if (uV > SD1_VOLT_MAX)
+ return -EINVAL;
+ break;
+ default:
+ /* SD2 and SD3 have max voltage 3.79V */
+ if (uV > SD_VOLT_MAX)
+ return -EINVAL;
+ break;
+ };
+
+ if (uV < SD_VOLT_MIN)
+ uV = SD_VOLT_MIN;
+
+ return (uV - SD_VOLT_BASE) / 12500;
+}
+
+/**
+ * max77663_*_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @idx: regulator index
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int max77663_sd_hex2volt(int idx, int hex)
+{
+ switch (idx) {
+ case 0:
+ /* SD0 has max voltage 1.4V */
+ if (hex > SD0_VOLT_MAX_HEX)
+ return -EINVAL;
+ break;
+ case 1:
+ /* SD1 has max voltage 1.55V */
+ if (hex > SD1_VOLT_MAX_HEX)
+ return -EINVAL;
+ break;
+ default:
+ /* SD2 and SD3 have max voltage 3.79V */
+ if (hex > SD_VOLT_MAX_HEX)
+ return -EINVAL;
+ break;
+ };
+
+ if (hex < SD_VOLT_MIN_HEX)
+ hex = SD_VOLT_MIN_HEX;
+
+ return SD_VOLT_BASE + hex * 12500;
+}
+
+static int max77663_sd_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int idx = dev->driver_data;
+ int hex, ret;
+
+ if (op == PMIC_OP_GET) {
+ hex = pmic_reg_read(dev->parent, adr);
+ if (hex < 0)
+ return hex;
+
+ *uV = 0;
+
+ ret = max77663_sd_hex2volt(idx, hex);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+
+ return 0;
+ }
+
+ /* SD regulators use entire register for voltage */
+ hex = max77663_sd_volt2hex(idx, *uV);
+ if (hex < 0)
+ return hex;
+
+ return pmic_reg_write(dev->parent, adr, hex);
+}
+
+static int max77663_sd_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ int idx = dev->driver_data;
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->ctrl_reg = max77663_sd_reg[0][idx];
+ uc_pdata->volt_reg = max77663_sd_reg[1][idx];
+
+ return 0;
+}
+
+static int sd_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = max77663_sd_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int sd_set_value(struct udevice *dev, int uV)
+{
+ return max77663_sd_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int sd_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = max77663_sd_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int sd_set_enable(struct udevice *dev, bool enable)
+{
+ return max77663_sd_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops max77663_sd_ops = {
+ .get_value = sd_get_value,
+ .set_value = sd_set_value,
+ .get_enable = sd_get_enable,
+ .set_enable = sd_set_enable,
+};
+
+U_BOOT_DRIVER(max77663_sd) = {
+ .name = MAX77663_SD_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &max77663_sd_ops,
+ .probe = max77663_sd_probe,
+};
+
+static int max77663_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ if (val & LDO_STATUS_MASK)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ val &= ~LDO_STATUS_MASK;
+
+ if (*enable)
+ val |= LDO_STATUS_MASK;
+
+ ret = pmic_reg_write(dev->parent, adr, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max77663_ldo_volt2hex(int idx, int uV)
+{
+ switch (idx) {
+ case 0:
+ case 1:
+ if (uV > LDO01_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - LDO_VOLT_BASE) / 25000;
+ case 4:
+ if (uV > LDO4_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - LDO_VOLT_BASE) / 12500;
+ default:
+ if (uV > LDO_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - LDO_VOLT_BASE) / 50000;
+ };
+}
+
+static int max77663_ldo_hex2volt(int idx, int hex)
+{
+ if (hex > LDO_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ switch (idx) {
+ case 0:
+ case 1:
+ return (hex * 25000) + LDO_VOLT_BASE;
+ case 4:
+ return (hex * 12500) + LDO_VOLT_BASE;
+ default:
+ return (hex * 50000) + LDO_VOLT_BASE;
+ };
+}
+
+static int max77663_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int idx = dev->driver_data;
+ int hex, val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ ret = max77663_ldo_hex2volt(idx, val & LDO_VOLT_MASK);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = max77663_ldo_volt2hex(idx, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~LDO_VOLT_MASK;
+
+ return pmic_reg_write(dev->parent, adr, val | hex);
+}
+
+static int max77663_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ int idx = dev->driver_data;
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->ctrl_reg = max77663_ldo_reg[idx];
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = max77663_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return max77663_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = max77663_ldo_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ return max77663_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops max77663_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(max77663_ldo) = {
+ .name = MAX77663_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &max77663_ldo_ops,
+ .probe = max77663_ldo_probe,
+};
diff --git a/drivers/power/regulator/palmas_regulator.c b/drivers/power/regulator/palmas_regulator.c
index 3c4eb83be7..d615e94734 100644
--- a/drivers/power/regulator/palmas_regulator.c
+++ b/drivers/power/regulator/palmas_regulator.c
@@ -301,19 +301,23 @@ static int palmas_ldo_probe(struct udevice *dev)
uc_pdata->type = REGULATOR_TYPE_LDO;
- if (dev->driver_data) {
+ /* 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];
+ return 0;
+ }
+
+ 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;
+ }
+
+ if (dev->driver_data > 0) {
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;
diff --git a/drivers/power/regulator/tps65911_regulator.c b/drivers/power/regulator/tps65911_regulator.c
new file mode 100644
index 0000000000..2b5acdfcbb
--- /dev/null
+++ b/drivers/power/regulator/tps65911_regulator.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65910_pmic.h>
+
+/* fist row is control registers, second is voltage registers */
+static const char tps65911_vdd_reg[][TPS65911_VDD_NUM] = {
+ { TPS65911_REG_VDD1, TPS65911_REG_VDD2,
+ TPS65911_REG_VDDCTRL, TPS65911_REG_VIO },
+ { TPS65911_REG_VDD1_OP, TPS65911_REG_VDD2_OP,
+ TPS65911_REG_VDDCTRL_OP, 0x00 },
+};
+
+static const char tps65911_ldo_reg[TPS65911_LDO_NUM] = {
+ TPS65911_REG_LDO1, TPS65911_REG_LDO2, TPS65911_REG_LDO3,
+ TPS65911_REG_LDO4, TPS65911_REG_LDO5, TPS65911_REG_LDO6,
+ TPS65911_REG_LDO7, TPS65911_REG_LDO8
+};
+
+static int tps65911_regulator_enable(struct udevice *dev, int op, bool *enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ if (val & TPS65910_SUPPLY_STATE_ON)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ val &= ~TPS65910_SUPPLY_STATE_MASK;
+
+ if (*enable)
+ val |= TPS65910_SUPPLY_STATE_ON;
+
+ ret = pmic_reg_write(dev->parent, adr, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps65911_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = tps65911_regulator_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int tps65911_set_enable(struct udevice *dev, bool enable)
+{
+ return tps65911_regulator_enable(dev, PMIC_OP_SET, &enable);
+}
+
+/**
+ * tps65911_vdd_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int tps65911_vdd_volt2hex(int uV)
+{
+ if (uV > TPS65911_VDD_VOLT_MAX)
+ return -EINVAL;
+
+ if (uV < TPS65911_VDD_VOLT_MIN)
+ uV = TPS65911_VDD_VOLT_MIN;
+
+ return (uV - TPS65911_VDD_VOLT_BASE) / 12500;
+}
+
+/**
+ * tps65911_vdd_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int tps65911_vdd_hex2volt(int hex)
+{
+ if (hex > TPS65910_VDD_SEL_MAX)
+ return -EINVAL;
+
+ if (hex < TPS65910_VDD_SEL_MIN)
+ hex = TPS65910_VDD_SEL_MIN;
+
+ return TPS65911_VDD_VOLT_BASE + hex * 12500;
+}
+
+static int tps65911_vio_range[4] = {
+ 1500000, 1800000, 2500000, 3300000
+};
+
+static int tps65911_vio_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int i, val;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ val &= TPS65910_SEL_MASK;
+
+ *uV = tps65911_vio_range[val >> 2];
+
+ return 0;
+ }
+
+ val &= ~TPS65910_SEL_MASK;
+
+ for (i = 0; i < ARRAY_SIZE(tps65911_vio_range); i++)
+ if (*uV <= tps65911_vio_range[i])
+ break;
+
+ return pmic_reg_write(dev->parent, adr, val | i << 2);
+}
+
+static int tps65911_vdd_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int val, ret;
+
+ /* in case vdd is vio */
+ if (!adr)
+ return tps65911_vio_val(dev, op, uV);
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ ret = tps65911_vdd_hex2volt(val);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ val = tps65911_vdd_volt2hex(*uV);
+ if (val < 0)
+ return val;
+
+ return pmic_reg_write(dev->parent, adr, val);
+}
+
+static int tps65911_vdd_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ /* check for vddctrl and vddio cases */
+ if (!strcmp("vddctrl", dev->name)) {
+ uc_pdata->ctrl_reg = tps65911_vdd_reg[0][2];
+ uc_pdata->volt_reg = tps65911_vdd_reg[1][2];
+ return 0;
+ }
+
+ if (!strcmp("vddio", dev->name)) {
+ uc_pdata->ctrl_reg = tps65911_vdd_reg[0][3];
+ uc_pdata->volt_reg = tps65911_vdd_reg[1][3];
+ return 0;
+ }
+
+ if (dev->driver_data > 0) {
+ u8 idx = dev->driver_data - 1;
+
+ uc_pdata->ctrl_reg = tps65911_vdd_reg[0][idx];
+ uc_pdata->volt_reg = tps65911_vdd_reg[1][idx];
+ }
+
+ return 0;
+}
+
+static int vdd_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps65911_vdd_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int vdd_set_value(struct udevice *dev, int uV)
+{
+ return tps65911_vdd_val(dev, PMIC_OP_SET, &uV);
+}
+
+static const struct dm_regulator_ops tps65911_vdd_ops = {
+ .get_value = vdd_get_value,
+ .set_value = vdd_set_value,
+ .get_enable = tps65911_get_enable,
+ .set_enable = tps65911_set_enable,
+};
+
+U_BOOT_DRIVER(tps65911_vdd) = {
+ .name = TPS65911_VDD_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65911_vdd_ops,
+ .probe = tps65911_vdd_probe,
+};
+
+/**
+ * tps65911_ldo_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @idx: regulator index
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int tps65911_ldo_volt2hex(int idx, int uV)
+{
+ int step;
+
+ if (uV > TPS65911_LDO_VOLT_MAX)
+ return -EINVAL;
+
+ if (uV < TPS65911_LDO_VOLT_BASE)
+ uV = TPS65911_LDO_VOLT_BASE;
+
+ switch (idx) {
+ case 1:
+ case 2:
+ case 4:
+ step = TPS65911_LDO124_VOLT_STEP;
+ break;
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ step = TPS65911_LDO358_VOLT_STEP;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return ((uV - TPS65911_LDO_VOLT_BASE) / step) << 2;
+}
+
+/**
+ * tps65911_ldo_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @idx: regulator index
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int tps65911_ldo_hex2volt(int idx, int hex)
+{
+ int step;
+
+ switch (idx) {
+ case 1:
+ case 2:
+ case 4:
+ if (hex > TPS65911_LDO124_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ step = TPS65911_LDO124_VOLT_STEP;
+ break;
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ if (hex > TPS65911_LDO358_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (hex < TPS65911_LDO358_VOLT_MIN_HEX)
+ hex = TPS65911_LDO358_VOLT_MIN_HEX;
+
+ step = TPS65911_LDO358_VOLT_STEP;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return TPS65911_LDO_VOLT_BASE + hex * step;
+}
+
+static int tps65911_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int idx = dev->driver_data;
+ int val, hex, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+ val &= TPS65911_LDO_SEL_MASK;
+
+ ret = tps65911_ldo_hex2volt(idx, val >> 2);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = tps65911_ldo_volt2hex(idx, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~TPS65911_LDO_SEL_MASK;
+
+ return pmic_reg_write(dev->parent, adr, val | hex);
+}
+
+static int tps65911_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u8 idx = dev->driver_data - 1;
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->ctrl_reg = tps65911_ldo_reg[idx];
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps65911_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return tps65911_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static const struct dm_regulator_ops tps65911_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = tps65911_get_enable,
+ .set_enable = tps65911_set_enable,
+};
+
+U_BOOT_DRIVER(tps65911_ldo) = {
+ .name = TPS65911_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65911_ldo_ops,
+ .probe = tps65911_ldo_probe,
+};
diff --git a/drivers/power/regulator/tps80031_regulator.c b/drivers/power/regulator/tps80031_regulator.c
new file mode 100644
index 0000000000..87696662e1
--- /dev/null
+++ b/drivers/power/regulator/tps80031_regulator.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps80031.h>
+
+static const char tps80031_smps_reg[][TPS80031_SMPS_NUM] = {
+ { 0x54, 0x5a, 0x66, 0x42, 0x48 },
+ { 0x56, 0x5c, 0x68, 0x44, 0x4a },
+ { BIT(3), BIT(4), BIT(6), BIT(0), BIT(1) },
+};
+
+static const char tps80031_ldo_reg[][TPS80031_LDO_NUM] = {
+ { 0x9e, 0x86, 0x8e, 0x8a, 0x9a, 0x92, 0xa6, 0x96, 0xa2 },
+ { 0x9f, 0x87, 0x8f, 0x8b, 0x9b, 0x93, 0xa7, 0x97, 0xa3 },
+};
+
+static int tps80031_regulator_enable(struct udevice *dev, int op, bool *enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ if (val & REGULATOR_MODE_ON)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ val &= ~REGULATOR_STATUS_MASK;
+
+ if (*enable)
+ val |= REGULATOR_MODE_ON;
+
+ ret = pmic_reg_write(dev->parent, adr, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps80031_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = tps80031_regulator_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int tps80031_set_enable(struct udevice *dev, bool enable)
+{
+ return tps80031_regulator_enable(dev, PMIC_OP_SET, &enable);
+}
+
+/**
+ * tps80031_ldo_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int tps80031_ldo_volt2hex(int uV)
+{
+ if (uV > LDO_VOLT_MAX)
+ return -EINVAL;
+
+ if (uV < LDO_VOLT_MIN)
+ uV = LDO_VOLT_MIN;
+
+ return DIV_ROUND_UP(uV - LDO_VOLT_BASE, 102000);
+}
+
+/**
+ * tps80031_ldo_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int tps80031_ldo_hex2volt(int hex)
+{
+ if (hex > LDO_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (hex < LDO_VOLT_MIN_HEX)
+ hex = LDO_VOLT_MIN_HEX;
+
+ return LDO_VOLT_BASE + hex * 102000;
+}
+
+static int tps80031_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int val, hex, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ ret = tps80031_ldo_hex2volt(val & LDO_VOLT_MASK);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = tps80031_ldo_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~LDO_VOLT_MASK;
+
+ return pmic_reg_write(dev->parent, adr, val | hex);
+}
+
+static int tps80031_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+
+ /* check for ldoln and ldousb cases */
+ if (!strcmp("ldoln", dev->name)) {
+ uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][7];
+ uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][7];
+ return 0;
+ }
+
+ if (!strcmp("ldousb", dev->name)) {
+ uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][8];
+ uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][8];
+ return 0;
+ }
+
+ if (dev->driver_data > 0) {
+ u8 idx = dev->driver_data - 1;
+
+ uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][idx];
+ uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][idx];
+ }
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps80031_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return tps80031_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static const struct dm_regulator_ops tps80031_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = tps80031_get_enable,
+ .set_enable = tps80031_set_enable,
+};
+
+U_BOOT_DRIVER(tps80031_ldo) = {
+ .name = TPS80031_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps80031_ldo_ops,
+ .probe = tps80031_ldo_probe,
+};
+
+struct tps80031_smps_priv {
+ int flags;
+};
+
+/* DCDC voltages for the selector of 0x39 to 0x3F */
+static int tps80031_dcdc_voltages[5] = {
+ 1350000, 1500000, 1800000, 1900000, 2100000
+};
+
+/**
+ * tps80031_smps_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @base: base voltage in uV
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int tps80031_smps_volt2hex(u32 base, int uV)
+{
+ int i;
+
+ if (uV < base)
+ return 1;
+
+ if (uV > SMPS_VOLT_LINEAR) {
+ for (i = 0; i < ARRAY_SIZE(tps80031_dcdc_voltages); i++)
+ if (uV <= tps80031_dcdc_voltages[i])
+ break;
+
+ return SMPS_VOLT_NLINEAR_HEX + i;
+ }
+
+ return DIV_ROUND_UP(uV - base, 12500);
+}
+
+/**
+ * tps80031_smps_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @base: base voltage in uV
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int tps80031_smps_hex2volt(u32 base, int hex)
+{
+ if (!hex)
+ return 0;
+
+ /* if reg value exceeds linear scale use table */
+ if (hex > SMPS_VOLT_LINEAR_HEX)
+ return tps80031_dcdc_voltages[hex - SMPS_VOLT_LINEAR_HEX];
+ else
+ return base + hex * 12500;
+}
+
+static int tps80031_smps_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ struct tps80031_smps_priv *priv = dev_get_priv(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int base, val, hex, ret;
+
+ /* If offset flag was set then base voltage is higher */
+ if (priv->flags & TPS80031_OFFSET_FLAG)
+ base = SMPS_VOLT_BASE_OFFSET;
+ else
+ base = SMPS_VOLT_BASE;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ ret = tps80031_smps_hex2volt(base, val & SMPS_VOLT_MASK);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = tps80031_smps_volt2hex(base, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~SMPS_VOLT_MASK;
+
+ return pmic_reg_write(dev->parent, adr, val | hex);
+}
+
+static int tps80031_smps_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ struct tps80031_smps_priv *priv = dev_get_priv(dev);
+ int idx = dev->driver_data - 1;
+ int val;
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ uc_pdata->ctrl_reg = tps80031_smps_reg[CTRL][idx];
+ uc_pdata->volt_reg = tps80031_smps_reg[VOLT][idx];
+
+ /* Determine if smps regulator uses higher voltage */
+ val = pmic_reg_read(dev->parent, TPS80031_SMPS_OFFSET);
+ if (val & tps80031_smps_reg[OFFSET][idx])
+ priv->flags |= TPS80031_OFFSET_FLAG;
+
+ return 0;
+}
+
+static int smps_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps80031_smps_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int smps_set_value(struct udevice *dev, int uV)
+{
+ return tps80031_smps_val(dev, PMIC_OP_SET, &uV);
+}
+
+static const struct dm_regulator_ops tps80031_smps_ops = {
+ .get_value = smps_get_value,
+ .set_value = smps_set_value,
+ .get_enable = tps80031_get_enable,
+ .set_enable = tps80031_set_enable,
+};
+
+U_BOOT_DRIVER(tps80031_smps) = {
+ .name = TPS80031_SMPS_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps80031_smps_ops,
+ .probe = tps80031_smps_probe,
+ .priv_auto = sizeof(struct tps80031_smps_priv),
+};
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index bdbe2a9536..0e52f99628 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -74,6 +74,13 @@ config SYSRESET_GPIO
example on Microblaze where reset logic can be controlled via GPIO
pin which triggers cpu reset.
+config SYSRESET_MAX77663
+ bool "Enable support for MAX77663 PMIC System Reset"
+ depends on DM_PMIC_MAX77663
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in MAX77663 PMIC.
+
config SYSRESET_MICROBLAZE
bool "Enable support for Microblaze soft reset"
depends on MICROBLAZE
@@ -102,6 +109,13 @@ config SYSRESET_SPL_AT91
This enables the system reset driver support for Microchip/Atmel
SoCs in SPL.
+config SYSRESET_PALMAS
+ bool "Enable support for PALMAS System Reset"
+ depends on PMIC_PALMAS
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in PLAMAS PMIC family.
+
config SYSRESET_PSCI
bool "Enable support for PSCI System Reset"
depends on ARM_PSCI_FW
@@ -137,6 +151,12 @@ config SYSRESET_SOCFPGA_SOC64
This enables the system reset driver support for Intel SOCFPGA
SoC64 SoCs.
+config SYSRESET_TEGRA
+ bool "Tegra PMC system reset driver"
+ depends on ARCH_TEGRA
+ help
+ This enables the system reset ability of PMC used in Tegra SoCs.
+
config SYSRESET_TI_SCI
bool "TI System Control Interface (TI SCI) system reset driver"
depends on TI_SCI_PROTOCOL
@@ -144,6 +164,22 @@ config SYSRESET_TI_SCI
This enables the system reset driver support over TI System Control
Interface available on some new TI's SoCs.
+config SYSRESET_TPS65910
+ bool "Enable support for TPS65910/TPS65911 PMIC System Reset"
+ depends on DM_PMIC_TPS65910
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in TPS65910/TPS65911
+ PMICs.
+
+config SYSRESET_TPS80031
+ bool "Enable support for TPS80031/TPS80032 PMIC System Reset"
+ depends on DM_PMIC_TPS80031
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in TPS80031/TPS80032
+ PMICs.
+
config SYSRESET_SYSCON
bool "Enable support for mfd syscon reboot driver"
select REGMAP
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index 40c876764a..c9f1c625ae 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -9,14 +9,19 @@ obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
obj-$(CONFIG_POWEROFF_GPIO) += poweroff_gpio.o
obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_MAX77663) += sysreset_max77663.o
obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o
obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_PALMAS) += sysreset_palmas.o
obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
obj-$(CONFIG_SYSRESET_SBI) += sysreset_sbi.o
obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o
obj-$(CONFIG_SYSRESET_SOCFPGA_SOC64) += sysreset_socfpga_soc64.o
+obj-$(CONFIG_SYSRESET_TEGRA) += sysreset_tegra.o
obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_TPS65910) += sysreset_tps65910.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_TPS80031) += sysreset_tps80031.o
obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o
obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o
obj-$(CONFIG_SYSRESET_RESETCTL) += sysreset_resetctl.o
diff --git a/drivers/sysreset/sysreset_max77663.c b/drivers/sysreset/sysreset_max77663.c
new file mode 100644
index 0000000000..8febcf8de6
--- /dev/null
+++ b/drivers/sysreset/sysreset_max77663.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/max77663.h>
+
+static int max77663_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ int val;
+
+ val = pmic_reg_read(dev->parent, MAX77663_REG_ONOFF_CFG1);
+ if (val < 0)
+ return val;
+
+ /* clear both bits */
+ val &= ~ONOFF_SFT_RST;
+ val &= ~ONOFF_PWR_OFF;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* MAX77663: SFT_RST > ONOFF_CFG1 */
+ pmic_reg_write(dev->parent, MAX77663_REG_ONOFF_CFG1,
+ val | ONOFF_SFT_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* MAX77663: PWR_OFF > ONOFF_CFG1 */
+ pmic_reg_write(dev->parent, MAX77663_REG_ONOFF_CFG1,
+ val | ONOFF_PWR_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops max77663_sysreset = {
+ .request = max77663_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_max77663) = {
+ .id = UCLASS_SYSRESET,
+ .name = MAX77663_RST_DRIVER,
+ .ops = &max77663_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_palmas.c b/drivers/sysreset/sysreset_palmas.c
new file mode 100644
index 0000000000..9e3aa40348
--- /dev/null
+++ b/drivers/sysreset/sysreset_palmas.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/palmas.h>
+
+static int palmas_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ struct palmas_priv *priv = dev_get_priv(dev->parent);
+ int ret;
+
+ /*
+ * Mask INT3 on second page which detects vbus
+ * or device will immediately turn on.
+ */
+ ret = dm_i2c_reg_clrset(priv->chip2, PALMAS_INT3_MASK,
+ MASK_VBUS, MASK_VBUS);
+ if (ret < 0)
+ return ret;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* PALMAS: SW_RST > DEV_CTRL */
+ pmic_reg_write(dev->parent, PALMAS_DEV_CTRL, SW_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* PALMAS: DEV_OFF > DEV_CTRL */
+ pmic_reg_write(dev->parent, PALMAS_DEV_CTRL, DEV_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops palmas_sysreset = {
+ .request = palmas_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_palmas) = {
+ .id = UCLASS_SYSRESET,
+ .name = PALMAS_RST_DRIVER,
+ .ops = &palmas_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_tegra.c b/drivers/sysreset/sysreset_tegra.c
new file mode 100644
index 0000000000..10bcd3a187
--- /dev/null
+++ b/drivers/sysreset/sysreset_tegra.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <linux/err.h>
+#include <asm/arch-tegra/pmc.h>
+
+static int tegra_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ u32 value;
+
+ switch (type) {
+ case SYSRESET_WARM:
+ case SYSRESET_COLD:
+ /* resets everything but scratch 0 and reset status */
+ value = tegra_pmc_readl(PMC_CNTRL);
+ value |= PMC_CNTRL_MAIN_RST;
+ tegra_pmc_writel(value, PMC_CNTRL);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tegra_sysreset = {
+ .request = tegra_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tegra) = {
+ .id = UCLASS_SYSRESET,
+ .name = "sysreset_tegra",
+ .ops = &tegra_sysreset,
+};
+
+/* Link to Tegra PMC once there is a driver */
+U_BOOT_DRVINFO(sysreset_tegra) = {
+ .name = "sysreset_tegra"
+};
diff --git a/drivers/sysreset/sysreset_tps65910.c b/drivers/sysreset/sysreset_tps65910.c
new file mode 100644
index 0000000000..98da56661c
--- /dev/null
+++ b/drivers/sysreset/sysreset_tps65910.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/tps65910_pmic.h>
+
+static int tps65910_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ int val;
+
+ val = pmic_reg_read(dev->parent, TPS65910_REG_DEVICE_CTRL);
+ if (val < 0)
+ return val;
+
+ /* define power-off to be sequential */
+ val |= PWR_OFF_SEQ;
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL, val);
+
+ val &= ~DEV_ON;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* TPS65910: DEV_OFF_RST > DEVICE_CTRL */
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL,
+ val | DEV_OFF_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* TPS65910: DEV_OFF > DEVICE_CTRL */
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL,
+ val | DEV_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tps65910_sysreset = {
+ .request = tps65910_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tps65910) = {
+ .id = UCLASS_SYSRESET,
+ .name = TPS65910_RST_DRIVER,
+ .ops = &tps65910_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_tps80031.c b/drivers/sysreset/sysreset_tps80031.c
new file mode 100644
index 0000000000..50024fe4e7
--- /dev/null
+++ b/drivers/sysreset/sysreset_tps80031.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/tps80031.h>
+
+static int tps80031_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ switch (type) {
+ case SYSRESET_POWER:
+ /* TPS80031: SW_RESET > PHOENIX_DEV_ON */
+ pmic_reg_write(dev->parent, TPS80031_PHOENIX_DEV_ON, SW_RESET);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* TPS80031: DEVOFF > PHOENIX_DEV_ON */
+ pmic_reg_write(dev->parent, TPS80031_PHOENIX_DEV_ON, DEVOFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tps80031_sysreset = {
+ .request = tps80031_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tps80031) = {
+ .id = UCLASS_SYSRESET,
+ .name = TPS80031_RST_DRIVER,
+ .ops = &tps80031_sysreset,
+};