feat(st-pmic): add STPMIC2 driver

The STPMIC2 embeds 15 regulators with various
properties, and is designed to supply the STM32MP2
SOC. This driver handles a minimal set of feature
to handle the boot of a board.

Signed-off-by: Pascal Paillet <p.paillet@st.com>
Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Signed-off-by: Maxime Méré <maxime.mere@foss.st.com>
Change-Id: Ibe0cacf8aec2871eb9a86ec16cbbd18d3745fe9e
diff --git a/drivers/st/pmic/stm32mp_pmic2.c b/drivers/st/pmic/stm32mp_pmic2.c
new file mode 100644
index 0000000..c19d36a
--- /dev/null
+++ b/drivers/st/pmic/stm32mp_pmic2.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/regulator.h>
+#include <drivers/st/stm32_i2c.h>
+#include <drivers/st/stm32mp_pmic2.h>
+#include <drivers/st/stpmic2.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#define PMIC_NODE_NOT_FOUND	1
+
+struct regul_handle_s {
+	const uint32_t id;
+	uint16_t bypass_mv;
+};
+
+static struct pmic_handle_s pmic2_handle;
+static struct i2c_handle_s i2c_handle;
+
+/* This driver is monoinstance */
+static struct pmic_handle_s *pmic2;
+
+static int dt_get_pmic_node(void *fdt)
+{
+	static int node = -FDT_ERR_BADOFFSET;
+
+	if (node == -FDT_ERR_BADOFFSET) {
+		node = fdt_node_offset_by_compatible(fdt, -1, "st,stpmic2");
+	}
+
+	return node;
+}
+
+int dt_pmic_status(void)
+{
+	static int status = -FDT_ERR_BADVALUE;
+	int node;
+	void *fdt;
+
+	if (status != -FDT_ERR_BADVALUE) {
+		return status;
+	}
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	node = dt_get_pmic_node(fdt);
+	if (node <= 0) {
+		status = -FDT_ERR_NOTFOUND;
+
+		return status;
+	}
+
+	status = DT_SECURE;
+
+	return status;
+}
+
+/*
+ * Get PMIC and its I2C bus configuration from the device tree.
+ * Return 0 on success, negative on error, 1 if no PMIC node is defined.
+ */
+static int dt_pmic2_i2c_config(struct dt_node_info *i2c_info,
+			       struct stm32_i2c_init_s *init,
+			       uint32_t *i2c_addr)
+{
+	static int i2c_node = -FDT_ERR_NOTFOUND;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	if (i2c_node == -FDT_ERR_NOTFOUND) {
+		int pmic_node;
+		const fdt32_t *cuint;
+
+		pmic_node = dt_get_pmic_node(fdt);
+		if (pmic_node < 0) {
+			return PMIC_NODE_NOT_FOUND;
+		}
+
+		cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
+		if (cuint == NULL) {
+			return -FDT_ERR_NOTFOUND;
+		}
+
+		*i2c_addr = fdt32_to_cpu(*cuint) << 1;
+		if (*i2c_addr > UINT16_MAX) {
+			return -FDT_ERR_BADVALUE;
+		}
+
+		i2c_node = fdt_parent_offset(fdt, pmic_node);
+		if (i2c_node < 0) {
+			return -FDT_ERR_NOTFOUND;
+		}
+	}
+
+	dt_fill_device_info(i2c_info, i2c_node);
+	if (i2c_info->base == 0U) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	i2c_info->status = DT_SECURE;
+
+	return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init);
+}
+
+bool initialize_pmic_i2c(void)
+{
+	int ret;
+	struct dt_node_info i2c_info;
+	struct i2c_handle_s *i2c = &i2c_handle;
+	uint32_t i2c_addr = 0U;
+	struct stm32_i2c_init_s i2c_init;
+
+	ret = dt_pmic2_i2c_config(&i2c_info, &i2c_init, &i2c_addr);
+	if (ret < 0) {
+		ERROR("I2C configuration failed %d\n", ret);
+		panic();
+	}
+
+	if (ret != 0) {
+		return false;
+	}
+
+	/* Initialize PMIC I2C */
+	i2c->i2c_base_addr		= i2c_info.base;
+	i2c->dt_status			= i2c_info.status;
+	i2c->clock			= i2c_info.clock;
+	i2c->i2c_state			= I2C_STATE_RESET;
+	i2c_init.own_address1		= i2c_addr;
+	i2c_init.addressing_mode	= I2C_ADDRESSINGMODE_7BIT;
+	i2c_init.dual_address_mode	= I2C_DUALADDRESS_DISABLE;
+	i2c_init.own_address2		= 0;
+	i2c_init.own_address2_masks	= I2C_OAR2_OA2NOMASK;
+	i2c_init.general_call_mode	= I2C_GENERALCALL_DISABLE;
+	i2c_init.no_stretch_mode	= I2C_NOSTRETCH_DISABLE;
+	i2c_init.analog_filter		= 1;
+	i2c_init.digital_filter_coef	= 0;
+
+	ret = stm32_i2c_init(i2c, &i2c_init);
+	if (ret != 0) {
+		ERROR("Cannot initialize I2C %x (%d)\n",
+		      i2c->i2c_base_addr, ret);
+		panic();
+	}
+
+	if (!stm32_i2c_is_device_ready(i2c, i2c_addr, 1,
+				       I2C_TIMEOUT_BUSY_MS)) {
+		ERROR("I2C device not ready\n");
+		panic();
+	}
+
+	pmic2 = &pmic2_handle;
+	pmic2->i2c_handle = &i2c_handle;
+	pmic2->i2c_addr = i2c_addr;
+
+	return true;
+}
+
+static int pmic2_set_state(const struct regul_description *desc, bool enable)
+{
+	struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
+
+	VERBOSE("%s: set state to %d\n", desc->node_name, enable);
+
+	return stpmic2_regulator_set_state(pmic2, regul->id, enable);
+}
+
+static int pmic2_get_state(const struct regul_description *desc)
+{
+	struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
+	bool enabled;
+
+	VERBOSE("%s: get state\n", desc->node_name);
+
+	if (stpmic2_regulator_get_state(pmic2, regul->id, &enabled) < 0) {
+		panic();
+	}
+
+	return enabled;
+}
+
+static int pmic2_get_voltage(const struct regul_description *desc)
+{
+	struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
+	uint16_t mv;
+
+	VERBOSE("%s: get volt\n", desc->node_name);
+
+	if (regul->bypass_mv != 0U) {
+		int ret;
+
+		/* If the regul is in bypass mode, return bypass value */
+		ret = stpmic2_regulator_get_prop(pmic2, regul->id, STPMIC2_BYPASS);
+		if (ret < 0) {
+			return ret;
+		}
+
+		if (ret == 1) {
+			return regul->bypass_mv;
+		}
+	};
+
+	if (stpmic2_regulator_get_voltage(pmic2, regul->id, &mv) < 0) {
+		panic();
+	}
+
+	return mv;
+}
+
+static int pmic2_set_voltage(const struct regul_description *desc, uint16_t mv)
+{
+	struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
+
+	VERBOSE("%s: set volt\n", desc->node_name);
+
+	if (regul->bypass_mv != 0U) {
+		int ret;
+
+		/* If the regul is in bypass mode, authorize bypass mV */
+		ret = stpmic2_regulator_get_prop(pmic2, regul->id, STPMIC2_BYPASS);
+		if (ret < 0) {
+			return ret;
+		}
+
+		if ((ret == 1) && (mv != regul->bypass_mv)) {
+			return -EPERM;
+		}
+	};
+
+	return stpmic2_regulator_set_voltage(pmic2, regul->id, mv);
+}
+
+static int pmic2_list_voltages(const struct regul_description *desc,
+			       const uint16_t **levels, size_t *count)
+{
+	struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
+
+	VERBOSE("%s: list volt\n", desc->node_name);
+
+	if (regul->bypass_mv != 0U) {
+		int ret;
+
+		ret = stpmic2_regulator_get_prop(pmic2, regul->id, STPMIC2_BYPASS);
+		if (ret < 0) {
+			return ret;
+		}
+
+		/* bypass is enabled, return a list with only bypass mV */
+		if (ret == 1) {
+			if (count != NULL) {
+				*count = 1U;
+			}
+			if (levels != NULL) {
+				*levels = &regul->bypass_mv;
+			}
+			return 0;
+		}
+	};
+
+	return stpmic2_regulator_levels_mv(pmic2, regul->id, levels, count);
+}
+
+static int pmic2_set_flag(const struct regul_description *desc, uint16_t flag)
+{
+	struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
+	uint32_t id = regul->id;
+	int ret = -EPERM;
+
+	VERBOSE("%s: set_flag 0x%x\n", desc->node_name, flag);
+
+	switch (flag) {
+	case REGUL_PULL_DOWN:
+		ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_PULL_DOWN, 1U);
+		break;
+	case REGUL_OCP:
+		ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_OCP, 1U);
+		break;
+	case REGUL_SINK_SOURCE:
+		ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_SINK_SOURCE, 1U);
+		break;
+	case REGUL_ENABLE_BYPASS:
+		ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_BYPASS, 1U);
+		break;
+	case REGUL_MASK_RESET:
+		ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_MASK_RESET, 1U);
+		break;
+	default:
+		ERROR("Invalid flag %u", flag);
+		panic();
+	}
+
+	if (ret != 0) {
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+int stpmic2_set_prop(const struct regul_description *desc, uint16_t prop, uint32_t value)
+{
+	struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
+	int ret;
+
+	VERBOSE("%s: set_prop 0x%x val=%u\n", desc->node_name, prop, value);
+
+	ret = stpmic2_regulator_set_prop(pmic2, regul->id, prop, value);
+	if (ret != 0)
+		return -EPERM;
+
+	return 0;
+}
+
+static struct regul_ops pmic2_ops = {
+	.set_state = pmic2_set_state,
+	.get_state = pmic2_get_state,
+	.set_voltage = pmic2_set_voltage,
+	.get_voltage = pmic2_get_voltage,
+	.list_voltages = pmic2_list_voltages,
+	.set_flag = pmic2_set_flag,
+};
+
+#define DEFINE_PMIC_REGUL_HANDLE(rid) \
+[(rid)] = { \
+	.id = (rid), \
+}
+
+static struct regul_handle_s pmic2_regul_handles[STPMIC2_NB_REG] = {
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK1),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK2),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK3),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK4),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK5),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK6),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK7),
+
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO1),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO2),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO3),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO4),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO5),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO6),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO7),
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO8),
+
+	DEFINE_PMIC_REGUL_HANDLE(STPMIC2_REFDDR),
+};
+
+#define DEFINE_REGUL(rid, name) \
+[rid] = { \
+	.node_name = name, \
+	.ops = &pmic2_ops, \
+	.driver_data = &pmic2_regul_handles[rid], \
+}
+
+static const struct regul_description pmic2_descs[STPMIC2_NB_REG] = {
+	DEFINE_REGUL(STPMIC2_BUCK1, "buck1"),
+	DEFINE_REGUL(STPMIC2_BUCK2, "buck2"),
+	DEFINE_REGUL(STPMIC2_BUCK3, "buck3"),
+	DEFINE_REGUL(STPMIC2_BUCK4, "buck4"),
+	DEFINE_REGUL(STPMIC2_BUCK5, "buck5"),
+	DEFINE_REGUL(STPMIC2_BUCK6, "buck6"),
+	DEFINE_REGUL(STPMIC2_BUCK7, "buck7"),
+
+	DEFINE_REGUL(STPMIC2_LDO1, "ldo1"),
+	DEFINE_REGUL(STPMIC2_LDO2, "ldo2"),
+	DEFINE_REGUL(STPMIC2_LDO3, "ldo3"),
+	DEFINE_REGUL(STPMIC2_LDO4, "ldo4"),
+	DEFINE_REGUL(STPMIC2_LDO5, "ldo5"),
+	DEFINE_REGUL(STPMIC2_LDO6, "ldo6"),
+	DEFINE_REGUL(STPMIC2_LDO7, "ldo7"),
+	DEFINE_REGUL(STPMIC2_LDO8, "ldo8"),
+
+	DEFINE_REGUL(STPMIC2_REFDDR, "refddr"),
+};
+
+static int register_pmic2(void)
+{
+	void *fdt;
+	int pmic_node, regulators_node, subnode;
+
+	VERBOSE("Register pmic2\n");
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	pmic_node = dt_get_pmic_node(fdt);
+	if (pmic_node < 0) {
+		return pmic_node;
+	}
+
+	regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
+	if (regulators_node < 0) {
+		return -ENOENT;
+	}
+
+	fdt_for_each_subnode(subnode, fdt, regulators_node) {
+		const char *reg_name = fdt_get_name(fdt, subnode, NULL);
+		const struct regul_description *desc;
+		unsigned int i;
+		int ret;
+		const fdt32_t *cuint;
+
+		for (i = 0; i < STPMIC2_NB_REG; i++) {
+			desc = &pmic2_descs[i];
+			if (strcmp(desc->node_name, reg_name) == 0) {
+				break;
+			}
+		}
+		assert(i < STPMIC2_NB_REG);
+
+		ret = regulator_register(desc, subnode);
+		if (ret != 0) {
+			WARN("%s:%d failed to register %s\n", __func__,
+			     __LINE__, reg_name);
+			return ret;
+		}
+
+		cuint = fdt_getprop(fdt, subnode, "st,regulator-bypass-microvolt", NULL);
+		if (cuint != NULL) {
+			struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
+
+			regul->bypass_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
+			VERBOSE("%s: bypass voltage=%umV\n", desc->node_name,
+				regul->bypass_mv);
+		}
+
+		if (fdt_getprop(fdt, subnode, "st,mask-reset", NULL)  != NULL) {
+			VERBOSE("%s: set mask-reset\n", desc->node_name);
+			ret = pmic2_set_flag(desc, REGUL_MASK_RESET);
+			if (ret != 0) {
+				ERROR("set mask-reset failed\n");
+				return ret;
+			}
+		}
+
+		if (fdt_getprop(fdt, subnode, "st,regulator-sink-source", NULL) != NULL) {
+			VERBOSE("%s: set regulator-sink-source\n", desc->node_name);
+			ret = pmic2_set_flag(desc, REGUL_SINK_SOURCE);
+			if (ret != 0) {
+				ERROR("set regulator-sink-source failed\n");
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void initialize_pmic(void)
+{
+	int ret;
+	uint8_t val;
+
+	ret = initialize_pmic_i2c();
+	if (!ret) {
+		VERBOSE("No PMIC2\n");
+		return;
+	}
+
+	if (stpmic2_get_version(pmic2, &val) != 0) {
+		ERROR("Failed to access PMIC\n");
+		panic();
+	}
+	INFO("PMIC2 version = 0x%02x\n", val);
+
+	if (stpmic2_get_product_id(pmic2, &val) != 0) {
+		ERROR("Failed to access PMIC\n");
+		panic();
+	}
+	INFO("PMIC2 product ID = 0x%02x\n", val);
+
+	ret = register_pmic2();
+	if (ret < 0) {
+		ERROR("Register pmic2 failed\n");
+		panic();
+	}
+
+#if EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
+	stpmic2_dump_regulators(pmic2);
+#endif
+}
diff --git a/drivers/st/pmic/stpmic2.c b/drivers/st/pmic/stpmic2.c
new file mode 100644
index 0000000..05a80ec
--- /dev/null
+++ b/drivers/st/pmic/stpmic2.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/st/stpmic2.h>
+
+#define RET_SUCCESS			0
+#define RET_ERROR_NOT_SUPPORTED		-1
+#define RET_ERROR_GENERIC		-2
+#define RET_ERROR_BAD_PARAMETERS	-3
+
+#define I2C_TIMEOUT_MS			25
+
+#define VOLTAGE_INDEX_INVALID		((size_t)~0U)
+
+struct regul_struct {
+	const char *name;
+	const uint16_t *volt_table;
+	uint8_t volt_table_size;
+	uint8_t volt_cr;
+	uint8_t volt_shift;
+	uint8_t en_cr;
+	uint8_t alt_en_cr;
+	uint8_t msrt_reg;
+	uint8_t msrt_mask;
+	uint8_t pd_reg;
+	uint8_t pd_val;
+	uint8_t ocp_reg;
+	uint8_t ocp_mask;
+};
+
+/* Voltage tables in mV */
+static const uint16_t buck1236_volt_table[] = {
+	500U, 510U, 520U, 530U, 540U, 550U, 560U, 570U, 580U, 590U,
+	600U, 610U, 620U, 630U, 640U, 650U, 660U, 670U, 680U, 690U,
+	700U, 710U, 720U, 730U, 740U, 750U, 760U, 770U, 780U, 790U,
+	800U, 810U, 820U, 830U, 840U, 850U, 860U, 870U, 880U, 890U,
+	900U, 910U, 920U, 930U, 940U, 950U, 960U, 970U, 980U, 990U,
+	1000U, 1010U, 1020U, 1030U, 1040U, 1050U, 1060U, 1070U, 1080U, 1090U,
+	1100U, 1110U, 1120U, 1130U, 1140U, 1150U, 1160U, 1170U, 1180U, 1190U,
+	1200U, 1210U, 1220U, 1230U, 1240U, 1250U, 1260U, 1270U, 1280U, 1290U,
+	1300U, 1310U, 1320U, 1330U, 1340U, 1350U, 1360U, 1370U, 1380U, 1390U,
+	1400U, 1410U, 1420U, 1430U, 1440U, 1450U, 1460U, 1470U, 1480U, 1490U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U
+};
+
+static const uint16_t buck457_volt_table[] = {
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
+	1500U, 1600U, 1700U, 1800U, 1900U, 2000U, 2100U, 2200U, 2300U, 2400U,
+	2500U, 2600U, 2700U, 2800U, 2900U, 3000U, 3100U, 3200U, 3300U, 3400U,
+	3500U, 3600U, 3700U, 3800U, 3900U, 4000U, 4100U, 4200U
+};
+
+static const uint16_t ldo235678_volt_table[] = {
+	900U, 1000U, 1100U, 1200U, 1300U, 1400U, 1500U, 1600U, 1700U, 1800U,
+	1900U, 2000U, 2100U, 2200U, 2300U, 2400U, 2500U, 2600U, 2700U, 2800U,
+	2900U, 3000U, 3100U, 3200U, 3300U, 3400U, 3500U, 3600U, 3700U, 3800U,
+	3900U, 4000U
+};
+
+static const uint16_t ldo1_volt_table[] = {
+	1800U,
+};
+
+static const uint16_t ldo4_volt_table[] = {
+	3300U,
+};
+
+static const uint16_t refddr_volt_table[] = {
+	0,
+};
+
+#define DEFINE_BUCK(regu_name, ID, pd, table) { \
+	.name			= regu_name, \
+	.volt_table		= table, \
+	.volt_table_size	= ARRAY_SIZE(table), \
+	.en_cr			= ID ## _MAIN_CR2, \
+	.volt_cr		= ID ## _MAIN_CR1, \
+	.alt_en_cr		= ID ## _ALT_CR2, \
+	.msrt_reg		= BUCKS_MRST_CR, \
+	.msrt_mask		= ID ## _MRST, \
+	.pd_reg			= pd, \
+	.pd_val			= ID ## _PD_FAST, \
+	.ocp_reg		= FS_OCP_CR1, \
+	.ocp_mask		= FS_OCP_ ## ID, \
+}
+
+#define DEFINE_LDOx(regu_name, ID, table) { \
+	.name			= regu_name, \
+	.volt_table		= table, \
+	.volt_table_size	= ARRAY_SIZE(table), \
+	.volt_shift		= LDO_VOLT_SHIFT, \
+	.en_cr			= ID ## _MAIN_CR, \
+	.volt_cr		= ID ## _MAIN_CR, \
+	.alt_en_cr		= ID ## _ALT_CR, \
+	.msrt_reg		= LDOS_MRST_CR, \
+	.msrt_mask		= ID ## _MRST, \
+	.pd_reg			= LDOS_PD_CR1, \
+	.pd_val			= ID ## _PD, \
+	.ocp_reg		= FS_OCP_CR2, \
+	.ocp_mask		= FS_OCP_ ## ID, \
+}
+
+#define DEFINE_REFDDR(regu_name, ID, table) { \
+	.name			= regu_name, \
+	.volt_table		= table, \
+	.volt_table_size	= ARRAY_SIZE(table), \
+	.en_cr			= ID ## _MAIN_CR, \
+	.volt_cr		= ID ## _MAIN_CR, \
+	.alt_en_cr		= ID ## _ALT_CR, \
+	.msrt_reg		= BUCKS_MRST_CR, \
+	.msrt_mask		= ID ## _MRST, \
+	.pd_reg			= LDOS_PD_CR2, \
+	.pd_val			= ID ## _PD, \
+	.ocp_reg		= FS_OCP_CR1, \
+	.ocp_mask		= FS_OCP_ ## ID, \
+}
+
+/* Table of Regulators in PMIC SoC */
+static const struct regul_struct regul_table[STPMIC2_NB_REG] = {
+	[STPMIC2_BUCK1] = DEFINE_BUCK("buck1", BUCK1, BUCKS_PD_CR1,
+				      buck1236_volt_table),
+	[STPMIC2_BUCK2] = DEFINE_BUCK("buck2", BUCK2, BUCKS_PD_CR1,
+				      buck1236_volt_table),
+	[STPMIC2_BUCK3] = DEFINE_BUCK("buck3", BUCK3, BUCKS_PD_CR1,
+				      buck1236_volt_table),
+	[STPMIC2_BUCK4] = DEFINE_BUCK("buck4", BUCK4, BUCKS_PD_CR1,
+				      buck457_volt_table),
+	[STPMIC2_BUCK5] = DEFINE_BUCK("buck5", BUCK5, BUCKS_PD_CR2,
+				      buck457_volt_table),
+	[STPMIC2_BUCK6] = DEFINE_BUCK("buck6", BUCK6, BUCKS_PD_CR2,
+				      buck1236_volt_table),
+	[STPMIC2_BUCK7] = DEFINE_BUCK("buck7", BUCK7, BUCKS_PD_CR2,
+				      buck457_volt_table),
+
+	[STPMIC2_REFDDR] = DEFINE_REFDDR("refddr", REFDDR, refddr_volt_table),
+
+	[STPMIC2_LDO1] = DEFINE_LDOx("ldo1", LDO1, ldo1_volt_table),
+	[STPMIC2_LDO2] = DEFINE_LDOx("ldo2", LDO2, ldo235678_volt_table),
+	[STPMIC2_LDO3] = DEFINE_LDOx("ldo3", LDO3, ldo235678_volt_table),
+	[STPMIC2_LDO4] = DEFINE_LDOx("ldo4", LDO4, ldo4_volt_table),
+	[STPMIC2_LDO5] = DEFINE_LDOx("ldo5", LDO5, ldo235678_volt_table),
+	[STPMIC2_LDO6] = DEFINE_LDOx("ldo6", LDO6, ldo235678_volt_table),
+	[STPMIC2_LDO7] = DEFINE_LDOx("ldo7", LDO7, ldo235678_volt_table),
+	[STPMIC2_LDO8] = DEFINE_LDOx("ldo8", LDO8, ldo235678_volt_table),
+
+};
+
+int stpmic2_register_read(struct pmic_handle_s *pmic,
+			  uint8_t register_id, uint8_t *value)
+{
+	int ret = stm32_i2c_mem_read(pmic->i2c_handle,
+				     pmic->i2c_addr,
+				     (uint16_t)register_id,
+				     I2C_MEMADD_SIZE_8BIT, value,
+				     1, I2C_TIMEOUT_MS);
+	if (ret != 0) {
+		ERROR("Failed to read reg:0x%x\n", register_id);
+	}
+
+	return ret;
+}
+
+int stpmic2_register_write(struct pmic_handle_s *pmic,
+			   uint8_t register_id, uint8_t value)
+{
+	uint8_t val = value;
+	int ret = stm32_i2c_mem_write(pmic->i2c_handle,
+				      pmic->i2c_addr,
+				      (uint16_t)register_id,
+				      I2C_MEMADD_SIZE_8BIT, &val,
+				      1, I2C_TIMEOUT_MS);
+	if (ret != 0) {
+		ERROR("Failed to write reg:0x%x\n", register_id);
+	}
+
+	return ret;
+}
+
+int stpmic2_register_update(struct pmic_handle_s *pmic,
+			    uint8_t register_id, uint8_t value, uint8_t mask)
+{
+	int status;
+	uint8_t val = 0U;
+
+	status = stpmic2_register_read(pmic, register_id, &val);
+	if (status != 0) {
+		return status;
+	}
+
+	val = (val & ((uint8_t)~mask)) | (value & mask);
+
+	VERBOSE("REG:0x%x v=0x%x mask=0x%x -> 0x%x\n",
+		register_id, value, mask, val);
+
+	return stpmic2_register_write(pmic, register_id, val);
+}
+
+int stpmic2_regulator_set_state(struct pmic_handle_s *pmic,
+				uint8_t id, bool enable)
+{
+	const struct regul_struct *regul = &regul_table[id];
+
+	if (enable) {
+		return stpmic2_register_update(pmic, regul->en_cr, 1U, 1U);
+	} else {
+		return stpmic2_register_update(pmic, regul->en_cr, 0, 1U);
+	}
+}
+
+int stpmic2_regulator_get_state(struct pmic_handle_s *pmic,
+				uint8_t id, bool *enabled)
+{
+	const struct regul_struct *regul = &regul_table[id];
+	uint8_t val;
+
+	if (stpmic2_register_read(pmic, regul->en_cr, &val) != 0) {
+		return RET_ERROR_GENERIC;
+	}
+
+	*enabled = (val & 1U) == 1U;
+
+	return RET_SUCCESS;
+}
+
+int stpmic2_regulator_levels_mv(struct pmic_handle_s *pmic,
+				uint8_t id, const uint16_t **levels,
+				size_t *levels_count)
+{
+	const struct regul_struct *regul = &regul_table[id];
+
+	if (regul == NULL) {
+		return RET_ERROR_BAD_PARAMETERS;
+	}
+
+	if (levels_count != NULL) {
+		*levels_count = regul->volt_table_size;
+	}
+	if (levels != NULL) {
+		*levels = regul->volt_table;
+	}
+
+	return RET_SUCCESS;
+}
+
+int stpmic2_regulator_get_voltage(struct pmic_handle_s *pmic,
+				  uint8_t id, uint16_t *val)
+{
+	const struct regul_struct *regul = &regul_table[id];
+	uint8_t value = 0U;
+	uint8_t mask;
+
+	if (regul->volt_table_size == 0U) {
+		return RET_ERROR_GENERIC;
+	}
+
+	mask = regul->volt_table_size - 1U;
+	if (mask != 0U) {
+		if (stpmic2_register_read(pmic, regul->volt_cr, &value) != 0) {
+			return RET_ERROR_GENERIC;
+		}
+
+		value = (value >> regul->volt_shift) & mask;
+	}
+
+	if (value > regul->volt_table_size) {
+		return RET_ERROR_GENERIC;
+	}
+
+	*val = regul->volt_table[value];
+
+	return RET_SUCCESS;
+}
+
+static size_t voltage_to_index(const struct regul_struct *regul,
+			       uint16_t millivolts)
+{
+	unsigned int i;
+
+	assert(regul->volt_table);
+	for (i = 0U; i < regul->volt_table_size; i++) {
+		if (regul->volt_table[i] == millivolts) {
+			return i;
+		}
+	}
+
+	return VOLTAGE_INDEX_INVALID;
+}
+
+int stpmic2_regulator_set_voltage(struct pmic_handle_s *pmic,
+				  uint8_t id, uint16_t millivolts)
+{
+	const struct regul_struct *regul = &regul_table[id];
+	size_t index;
+	uint8_t mask;
+
+	if (!regul->volt_table_size) {
+		return RET_SUCCESS;
+	}
+
+	mask = regul->volt_table_size - 1U;
+
+	index = voltage_to_index(regul, millivolts);
+	if (index == VOLTAGE_INDEX_INVALID) {
+		return RET_ERROR_GENERIC;
+	}
+
+	return stpmic2_register_update(pmic, regul->volt_cr,
+				       index << regul->volt_shift,
+				       mask << regul->volt_shift);
+}
+
+/* update both normal and alternate register */
+static int stpmic2_update_en_crs(struct pmic_handle_s *pmic, uint8_t id,
+				 uint8_t value, uint8_t mask)
+{
+	const struct regul_struct *regul = &regul_table[id];
+
+	if (stpmic2_register_update(pmic, regul->en_cr, value, mask) != 0) {
+		return RET_ERROR_GENERIC;
+	}
+
+	if (stpmic2_register_update(pmic, regul->alt_en_cr, value, mask) != 0) {
+		return RET_ERROR_GENERIC;
+	}
+
+	return RET_SUCCESS;
+}
+
+int stpmic2_regulator_get_prop(struct pmic_handle_s *pmic, uint8_t id,
+			       enum stpmic2_prop_id prop)
+{
+	const struct regul_struct *regul = &regul_table[id];
+	uint8_t val;
+
+	VERBOSE("%s: get prop 0x%x\n", regul->name, prop);
+
+	switch (prop) {
+	case STPMIC2_BYPASS:
+		if ((id <= STPMIC2_BUCK7) || (id == STPMIC2_LDO1) ||
+		    (id == STPMIC2_LDO4) || (id == STPMIC2_REFDDR)) {
+			return 0;
+		}
+
+		if (stpmic2_register_read(pmic, regul->en_cr, &val) != 0) {
+			return -EIO;
+		}
+
+		if ((val & LDO_BYPASS) != 0) {
+			return 1;
+		}
+
+		break;
+	default:
+		ERROR("Invalid prop %u\n", prop);
+		panic();
+	}
+
+	return 0;
+}
+
+int stpmic2_regulator_set_prop(struct pmic_handle_s *pmic, uint8_t id,
+			       enum stpmic2_prop_id prop, uint32_t arg)
+{
+	const struct regul_struct *regul = &regul_table[id];
+
+	VERBOSE("%s: set prop 0x%x arg=%u\n", regul->name, prop, arg);
+
+	switch (prop) {
+	case STPMIC2_PULL_DOWN:
+		return stpmic2_register_update(pmic, regul->pd_reg,
+					       regul->pd_val,
+					       regul->pd_val);
+	case STPMIC2_MASK_RESET:
+		if (!regul->msrt_mask) {
+			return RET_ERROR_NOT_SUPPORTED;
+		}
+		/* enable mask reset */
+		return stpmic2_register_update(pmic, regul->msrt_reg,
+					       regul->msrt_mask,
+					       regul->msrt_mask);
+	case STPMIC2_BYPASS:
+		if ((id <= STPMIC2_BUCK7) || (id == STPMIC2_LDO1) ||
+		    (id == STPMIC2_LDO4) || (id == STPMIC2_REFDDR)) {
+			return RET_ERROR_NOT_SUPPORTED;
+		}
+
+		/* clear sink source mode */
+		if ((id == STPMIC2_LDO3) && (arg != 0U)) {
+			if (stpmic2_update_en_crs(pmic, id, 0, LDO3_SNK_SRC) != 0) {
+				return RET_ERROR_GENERIC;
+			}
+		}
+
+		/* enable bypass mode */
+		return stpmic2_update_en_crs(pmic, id,
+					     (arg != 0U) ? LDO_BYPASS : 0,
+					     LDO_BYPASS);
+	case STPMIC2_SINK_SOURCE:
+		if (id != STPMIC2_LDO3) {
+			return RET_ERROR_NOT_SUPPORTED;
+		}
+
+		/* clear bypass mode */
+		if (stpmic2_update_en_crs(pmic, id, 0, LDO_BYPASS) != 0) {
+			return RET_ERROR_GENERIC;
+		}
+
+		return stpmic2_update_en_crs(pmic, id, LDO3_SNK_SRC,
+					     LDO3_SNK_SRC);
+	case STPMIC2_OCP:
+		return stpmic2_register_update(pmic, regul->ocp_reg,
+					       regul->ocp_mask,
+					       regul->ocp_mask);
+	default:
+		ERROR("Invalid prop %u\n", prop);
+		panic();
+	}
+
+	return -EPERM;
+}
+
+#if EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
+void stpmic2_dump_regulators(struct pmic_handle_s *pmic)
+{
+	size_t i;
+	char const *name;
+
+	for (i = 0U; i < ARRAY_SIZE(regul_table); i++) {
+		uint16_t val;
+		bool state;
+
+		if (!regul_table[i].volt_cr) {
+			continue;
+		}
+
+		stpmic2_regulator_get_voltage(pmic, i, &val);
+		stpmic2_regulator_get_state(pmic, i, &state);
+
+		name = regul_table[i].name;
+
+		VERBOSE("PMIC regul %s: %s, %dmV\n",
+			name, state ? "EN" : "DIS", val);
+	}
+}
+#endif
+
+int stpmic2_get_version(struct pmic_handle_s *pmic, uint8_t *val)
+{
+	return stpmic2_register_read(pmic, VERSION_SR, val);
+}
+
+int stpmic2_get_product_id(struct pmic_handle_s *pmic, uint8_t *val)
+{
+	return stpmic2_register_read(pmic, PRODUCT_ID, val);
+}
diff --git a/include/drivers/st/stm32mp_pmic2.h b/include/drivers/st/stm32mp_pmic2.h
new file mode 100644
index 0000000..51eba38
--- /dev/null
+++ b/include/drivers/st/stm32mp_pmic2.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_PMIC2_H
+#define STM32MP_PMIC2_H
+
+#include <stdbool.h>
+#include <drivers/st/regulator.h>
+
+#include <platform_def.h>
+
+/*
+ * dt_pmic_status - Check PMIC status from device tree
+ *
+ * Returns the status of the PMIC (secure, non-secure), or a negative value on
+ * error
+ */
+int dt_pmic_status(void);
+
+/*
+ * initialize_pmic_i2c - Initialize I2C for the PMIC control
+ *
+ * Returns true if PMIC is available, false if not found, panics on errors
+ */
+bool initialize_pmic_i2c(void);
+
+/*
+ * initialize_pmic - Main PMIC initialization function, called at platform init
+ *
+ * Panics on errors
+ */
+void initialize_pmic(void);
+
+/*
+ * stpmic2_set_prop - Set PMIC2 proprietary property
+ *
+ * Returns non zero on errors
+ */
+int stpmic2_set_prop(const struct regul_description *desc, uint16_t prop, uint32_t value);
+
+/*
+ * pmic_switch_off - switch off the platform with PMIC
+ *
+ * Panics on errors
+ */
+void pmic_switch_off(void);
+
+#endif /* STM32MP_PMIC2_H */
diff --git a/include/drivers/st/stpmic2.h b/include/drivers/st/stpmic2.h
new file mode 100644
index 0000000..58ba64a
--- /dev/null
+++ b/include/drivers/st/stpmic2.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STPMIC2_H
+#define STPMIC2_H
+
+#include <drivers/st/stm32_i2c.h>
+#include <lib/utils_def.h>
+
+enum {
+	STPMIC2_BUCK1 = 0,
+	STPMIC2_BUCK2,
+	STPMIC2_BUCK3,
+	STPMIC2_BUCK4,
+	STPMIC2_BUCK5,
+	STPMIC2_BUCK6,
+	STPMIC2_BUCK7,
+	STPMIC2_REFDDR,
+	STPMIC2_LDO1,
+	STPMIC2_LDO2,
+	STPMIC2_LDO3,
+	STPMIC2_LDO4,
+	STPMIC2_LDO5,
+	STPMIC2_LDO6,
+	STPMIC2_LDO7,
+	STPMIC2_LDO8,
+	STPMIC2_NB_REG
+};
+
+/* Status Registers */
+#define PRODUCT_ID		0x00
+#define VERSION_SR		0x01
+#define TURN_ON_SR		0x02
+#define TURN_OFF_SR		0x03
+#define RESTART_SR		0x04
+#define OCP_SR1			0x05
+#define OCP_SR2			0x06
+#define EN_SR1			0x07
+#define EN_SR2			0x08
+#define FS_CNT_SR1		0x09
+#define FS_CNT_SR2		0x0A
+#define FS_CNT_SR3		0x0B
+#define MODE_SR			0x0C
+/* Control Registers */
+#define MAIN_CR			0x10
+#define VINLOW_CR		0x11
+#define PKEY_LKP_CR		0x12
+#define WDG_CR			0x13
+#define WDG_TMR_CR		0x14
+#define WDG_TMR_SR		0x15
+#define FS_OCP_CR1		0x16
+#define FS_OCP_CR2		0x17
+#define PADS_PULL_CR		0x18
+#define BUCKS_PD_CR1		0x19
+#define BUCKS_PD_CR2		0x1A
+#define LDOS_PD_CR1		0x1B
+#define LDOS_PD_CR2		0x1C
+#define BUCKS_MRST_CR		0x1D
+#define LDOS_MRST_CR		0x1E
+/* Buck CR */
+#define BUCK1_MAIN_CR1		0x20
+#define BUCK1_MAIN_CR2		0x21
+#define BUCK1_ALT_CR1		0x22
+#define BUCK1_ALT_CR2		0x23
+#define BUCK1_PWRCTRL_CR	0x24
+#define BUCK2_MAIN_CR1		0x25
+#define BUCK2_MAIN_CR2		0x26
+#define BUCK2_ALT_CR1		0x27
+#define BUCK2_ALT_CR2		0x28
+#define BUCK2_PWRCTRL_CR	0x29
+#define BUCK3_MAIN_CR1		0x2A
+#define BUCK3_MAIN_CR2		0x2B
+#define BUCK3_ALT_CR1		0x2C
+#define BUCK3_ALT_CR2		0x2D
+#define BUCK3_PWRCTRL_CR	0x2E
+#define BUCK4_MAIN_CR1		0x2F
+#define BUCK4_MAIN_CR2		0x30
+#define BUCK4_ALT_CR1		0x31
+#define BUCK4_ALT_CR2		0x32
+#define BUCK4_PWRCTRL_CR	0x33
+#define BUCK5_MAIN_CR1		0x34
+#define BUCK5_MAIN_CR2		0x35
+#define BUCK5_ALT_CR1		0x36
+#define BUCK5_ALT_CR2		0x37
+#define BUCK5_PWRCTRL_CR	0x38
+#define BUCK6_MAIN_CR1		0x39
+#define BUCK6_MAIN_CR2		0x3A
+#define BUCK6_ALT_CR1		0x3B
+#define BUCK6_ALT_CR2		0x3C
+#define BUCK6_PWRCTRL_CR	0x3D
+#define BUCK7_MAIN_CR1		0x3E
+#define BUCK7_MAIN_CR2		0x3F
+#define BUCK7_ALT_CR1		0x40
+#define BUCK7_ALT_CR2		0x41
+#define BUCK7_PWRCTRL_CR	0x42
+/* LDO CR */
+#define LDO1_MAIN_CR		0x4C
+#define LDO1_ALT_CR		0x4D
+#define LDO1_PWRCTRL_CR		0x4E
+#define LDO2_MAIN_CR		0x4F
+#define LDO2_ALT_CR		0x50
+#define LDO2_PWRCTRL_CR		0x51
+#define LDO3_MAIN_CR		0x52
+#define LDO3_ALT_CR		0x53
+#define LDO3_PWRCTRL_CR		0x54
+#define LDO4_MAIN_CR		0x55
+#define LDO4_ALT_CR		0x56
+#define LDO4_PWRCTRL_CR		0x57
+#define LDO5_MAIN_CR		0x58
+#define LDO5_ALT_CR		0x59
+#define LDO5_PWRCTRL_CR		0x5A
+#define LDO6_MAIN_CR		0x5B
+#define LDO6_ALT_CR		0x5C
+#define LDO6_PWRCTRL_CR		0x5D
+#define LDO7_MAIN_CR		0x5E
+#define LDO7_ALT_CR		0x5F
+#define LDO7_PWRCTRL_CR		0x60
+#define LDO8_MAIN_CR		0x61
+#define LDO8_ALT_CR		0x62
+#define LDO8_PWRCTRL_CR		0x63
+#define REFDDR_MAIN_CR		0x64
+#define REFDDR_ALT_CR		0x65
+#define REFDDR_PWRCTRL_CR	0x66
+/* INTERRUPT CR */
+#define INT_PENDING_R1		0x70
+#define INT_PENDING_R2		0x71
+#define INT_PENDING_R3		0x72
+#define INT_PENDING_R4		0x73
+#define INT_CLEAR_R1		0x74
+#define INT_CLEAR_R2		0x75
+#define INT_CLEAR_R3		0x76
+#define INT_CLEAR_R4		0x77
+#define INT_MASK_R1		0x78
+#define INT_MASK_R2		0x79
+#define INT_MASK_R3		0x7A
+#define INT_MASK_R4		0x7B
+#define INT_SRC_R1		0x7C
+#define INT_SRC_R2		0x7D
+#define INT_SRC_R3		0x7E
+#define INT_SRC_R4		0x7F
+#define INT_DBG_LATCH_R1	0x80
+#define INT_DBG_LATCH_R2	0x81
+#define INT_DBG_LATCH_R3	0x82
+#define INT_DBG_LATCH_R4	0x83
+
+/* BUCKS_MRST_CR bits definition */
+#define BUCK1_MRST		BIT(0)
+#define BUCK2_MRST		BIT(1)
+#define BUCK3_MRST		BIT(2)
+#define BUCK4_MRST		BIT(3)
+#define BUCK5_MRST		BIT(4)
+#define BUCK6_MRST		BIT(5)
+#define BUCK7_MRST		BIT(6)
+#define REFDDR_MRST		BIT(7)
+
+/* LDOS_MRST_CR bits definition */
+#define LDO1_MRST		BIT(0)
+#define LDO2_MRST		BIT(1)
+#define LDO3_MRST		BIT(2)
+#define LDO4_MRST		BIT(3)
+#define LDO5_MRST		BIT(4)
+#define LDO6_MRST		BIT(5)
+#define LDO7_MRST		BIT(6)
+#define LDO8_MRST		BIT(7)
+
+/* LDOx_MAIN_CR */
+#define LDO_VOLT_SHIFT		1
+#define LDO_BYPASS		BIT(6)
+#define LDO1_INPUT_SRC		BIT(7)
+#define LDO3_SNK_SRC		BIT(7)
+#define LDO4_INPUT_SRC_SHIFT	6
+#define LDO4_INPUT_SRC_MASK	GENMASK_32(7, 6)
+
+/* PWRCTRL register bit definition */
+#define PWRCTRL_EN		BIT(0)
+#define PWRCTRL_RS		BIT(1)
+#define PWRCTRL_SEL_SHIFT	2
+#define PWRCTRL_SEL_MASK	GENMASK_32(3, 2)
+
+/* BUCKx_MAIN_CR2 */
+#define PREG_MODE_SHIFT		1
+#define PREG_MODE_MASK		GENMASK_32(2, 1)
+
+/* BUCKS_PD_CR1 */
+#define BUCK1_PD_MASK		GENMASK_32(1, 0)
+#define BUCK2_PD_MASK		GENMASK_32(3, 2)
+#define BUCK3_PD_MASK		GENMASK_32(5, 4)
+#define BUCK4_PD_MASK		GENMASK_32(7, 6)
+
+#define BUCK1_PD_FAST		BIT(1)
+#define BUCK2_PD_FAST		BIT(3)
+#define BUCK3_PD_FAST		BIT(5)
+#define BUCK4_PD_FAST		BIT(7)
+
+/* BUCKS_PD_CR2 */
+#define BUCK5_PD_MASK		GENMASK_32(1, 0)
+#define BUCK6_PD_MASK		GENMASK_32(3, 2)
+#define BUCK7_PD_MASK		GENMASK_32(5, 4)
+
+#define BUCK5_PD_FAST		BIT(1)
+#define BUCK6_PD_FAST		BIT(3)
+#define BUCK7_PD_FAST		BIT(5)
+
+/* LDOS_PD_CR1 */
+#define LDO1_PD			BIT(0)
+#define LDO2_PD			BIT(1)
+#define LDO3_PD			BIT(2)
+#define LDO4_PD			BIT(3)
+#define LDO5_PD			BIT(4)
+#define LDO6_PD			BIT(5)
+#define LDO7_PD			BIT(6)
+#define LDO8_PD			BIT(7)
+
+/* LDOS_PD_CR2 */
+#define REFDDR_PD		BIT(0)
+
+/* FS_OCP_CR1 */
+#define FS_OCP_BUCK1		BIT(0)
+#define FS_OCP_BUCK2		BIT(1)
+#define FS_OCP_BUCK3		BIT(2)
+#define FS_OCP_BUCK4		BIT(3)
+#define FS_OCP_BUCK5		BIT(4)
+#define FS_OCP_BUCK6		BIT(5)
+#define FS_OCP_BUCK7		BIT(6)
+#define FS_OCP_REFDDR		BIT(7)
+
+/* FS_OCP_CR2 */
+#define FS_OCP_LDO1		BIT(0)
+#define FS_OCP_LDO2		BIT(1)
+#define FS_OCP_LDO3		BIT(2)
+#define FS_OCP_LDO4		BIT(3)
+#define FS_OCP_LDO5		BIT(4)
+#define FS_OCP_LDO6		BIT(5)
+#define FS_OCP_LDO7		BIT(6)
+#define FS_OCP_LDO8		BIT(7)
+
+/* IRQ definitions */
+#define IT_PONKEY_F	0
+#define IT_PONKEY_R	1
+#define IT_BUCK1_OCP	16
+#define IT_BUCK2_OCP	17
+#define IT_BUCK3_OCP	18
+#define IT_BUCK4_OCP	19
+#define IT_BUCK5_OCP	20
+#define IT_BUCK6_OCP	21
+#define IT_BUCK7_OCP	22
+#define IT_REFDDR_OCP	23
+#define IT_LDO1_OCP	24
+#define IT_LDO2_OCP	25
+#define IT_LDO3_OCP	26
+#define IT_LDO4_OCP	27
+#define IT_LDO5_OCP	28
+#define IT_LDO6_OCP	29
+#define IT_LDO7_OCP	30
+#define IT_LDO8_OCP	31
+
+enum stpmic2_prop_id {
+	STPMIC2_MASK_RESET = 0,
+	STPMIC2_PULL_DOWN,
+	STPMIC2_BYPASS,		/* arg: 1=set 0=reset */
+	STPMIC2_SINK_SOURCE,
+	STPMIC2_OCP,
+};
+
+struct pmic_handle_s {
+	struct i2c_handle_s *i2c_handle;
+	uint32_t i2c_addr;
+	unsigned int pmic_status;
+};
+
+int stpmic2_register_read(struct pmic_handle_s *pmic,
+			  uint8_t register_id, uint8_t *value);
+int stpmic2_register_write(struct pmic_handle_s *pmic,
+			   uint8_t register_id, uint8_t value);
+int stpmic2_register_update(struct pmic_handle_s *pmic,
+			    uint8_t register_id, uint8_t value, uint8_t mask);
+
+int stpmic2_regulator_set_state(struct pmic_handle_s *pmic,
+				uint8_t id, bool enable);
+int stpmic2_regulator_get_state(struct pmic_handle_s *pmic,
+				uint8_t id, bool *enabled);
+
+int stpmic2_regulator_levels_mv(struct pmic_handle_s *pmic,
+				uint8_t id, const uint16_t **levels,
+				size_t *levels_count);
+int stpmic2_regulator_get_voltage(struct pmic_handle_s *pmic,
+				  uint8_t id, uint16_t *val);
+int stpmic2_regulator_set_voltage(struct pmic_handle_s *pmic,
+				  uint8_t id, uint16_t millivolts);
+
+#if EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
+void stpmic2_dump_regulators(struct pmic_handle_s *pmic);
+#endif
+
+int stpmic2_get_version(struct pmic_handle_s *pmic, uint8_t *val);
+int stpmic2_get_product_id(struct pmic_handle_s *pmic, uint8_t *val);
+
+int stpmic2_regulator_get_prop(struct pmic_handle_s *pmic, uint8_t id,
+			       enum stpmic2_prop_id prop);
+
+int stpmic2_regulator_set_prop(struct pmic_handle_s *pmic, uint8_t id,
+			       enum stpmic2_prop_id prop, uint32_t arg);
+
+#endif /*STPMIC2_H*/
diff --git a/plat/st/stm32mp2/bl2_plat_setup.c b/plat/st/stm32mp2/bl2_plat_setup.c
index 50d19ab..eb6c6f8 100644
--- a/plat/st/stm32mp2/bl2_plat_setup.c
+++ b/plat/st/stm32mp2/bl2_plat_setup.c
@@ -15,6 +15,7 @@
 #include <drivers/mmc.h>
 #include <drivers/st/regulator_fixed.h>
 #include <drivers/st/stm32mp2_ddr_helpers.h>
+#include <drivers/st/stm32mp_pmic2.h>
 #include <drivers/st/stm32mp_risab_regs.h>
 #include <lib/fconf/fconf.h>
 #include <lib/fconf/fconf_dyn_cfg_getter.h>
@@ -230,6 +231,10 @@
 		panic();
 	}
 
+	if (dt_pmic_status() > 0) {
+		initialize_pmic();
+	}
+
 	fconf_populate("TB_FW", STM32MP_DTB_BASE);
 
 	stm32mp_io_setup();
diff --git a/plat/st/stm32mp2/platform.mk b/plat/st/stm32mp2/platform.mk
index 32d6235..a22fe5c 100644
--- a/plat/st/stm32mp2/platform.mk
+++ b/plat/st/stm32mp2/platform.mk
@@ -110,6 +110,11 @@
 PLAT_BL_COMMON_SOURCES		+=	drivers/st/uart/${ARCH}/stm32_console.S
 PLAT_BL_COMMON_SOURCES		+=	plat/st/stm32mp2/${ARCH}/stm32mp2_helper.S
 
+PLAT_BL_COMMON_SOURCES		+=	drivers/st/pmic/stm32mp_pmic2.c				\
+					drivers/st/pmic/stpmic2.c				\
+
+PLAT_BL_COMMON_SOURCES		+=	drivers/st/i2c/stm32_i2c.c
+
 PLAT_BL_COMMON_SOURCES		+=	plat/st/stm32mp2/stm32mp2_private.c
 
 PLAT_BL_COMMON_SOURCES		+=	drivers/st/bsec/bsec3.c					\