This driver acts mostly as an interface between PMIC/regulator devices
connected to MediaTek SoCs over SPMI, providing read/write functions to
those devices.

It has been successfully tested with the MT6373 PMIC but should work
just as well with other PMICs as long as the corresponding compatible
string is added to the driver.

Signed-off-by: Arnaud Ferraris <[email protected]>
---
 drivers/power/pmic/Kconfig    |  6 +++
 drivers/power/pmic/Makefile   |  1 +
 drivers/power/pmic/mtk-spmi.c | 88 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+)

diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 95687d0bdfd..8f35dfdea84 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -464,6 +464,12 @@ config DM_PMIC_MTK_PWRAP
          on different MediaTek SoCs. The PMIC wrapper is a proprietary
          hardware to connect the PMIC.
 
+config DM_PMIC_MTK_SPMI
+       bool "Enable driver for MediaTek PMIC Support over SPMI"
+       help
+         Say yes here to add support for controlling MediaTek PMICs using the
+         SPMI bus.
+
 endif
 
 config PMIC_TPS65217
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index da9b810de90..a6a16b90bc6 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_PMIC_RAA215300) += raa215300.o
 obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o
 obj-$(CONFIG_$(PHASE_)DM_PMIC_CPCAP) += cpcap.o
 obj-$(CONFIG_DM_PMIC_MTK_PWRAP) += mtk-pwrap.o
+obj-$(CONFIG_DM_PMIC_MTK_SPMI) += mtk-spmi.o
 
 ifeq ($(CONFIG_$(PHASE_)POWER_LEGACY),y)
 obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
diff --git a/drivers/power/pmic/mtk-spmi.c b/drivers/power/pmic/mtk-spmi.c
new file mode 100644
index 00000000000..39895bf9c0d
--- /dev/null
+++ b/drivers/power/pmic/mtk-spmi.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MediaTek generic PMIC driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ * (C) Copyright 2026 Collabora Ltd
+ * Author: Arnaud Ferraris <[email protected]>
+ */
+#include <dm.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+
+#define REG_MASK 0xFFFF
+
+struct pmic_mtk_priv {
+       u32 usid; /* Slave ID on SPMI bus */
+};
+
+static int pmic_mtk_reg_count(struct udevice *dev)
+{
+       return 0xFFFF;
+}
+
+static int pmic_mtk_write(struct udevice *dev, uint reg, const u8 *buff, int 
len)
+{
+       struct pmic_mtk_priv *priv = dev_get_priv(dev);
+
+       if (len != 1)
+               return -EINVAL;
+
+       return spmi_reg_write(dev->parent, priv->usid, /* pid */ 0, reg & 
REG_MASK, *buff);
+}
+
+static int pmic_mtk_read(struct udevice *dev, uint reg, u8 *buff, int len)
+{
+       struct pmic_mtk_priv *priv = dev_get_priv(dev);
+       int val;
+
+       if (len != 1)
+               return -EINVAL;
+
+       val = spmi_reg_read(dev->parent, priv->usid, /* pid */ 0, reg & 
REG_MASK);
+
+       if (val < 0)
+               return val;
+       *buff = val;
+       return 0;
+}
+
+static struct dm_pmic_ops pmic_mtk_ops = {
+       .reg_count = pmic_mtk_reg_count,
+       .read = pmic_mtk_read,
+       .write = pmic_mtk_write,
+};
+
+static const struct udevice_id pmic_mtk_ids[] = {
+       { .compatible = "mediatek,mt6373" },
+       { }
+};
+
+static int pmic_mtk_probe(struct udevice *dev)
+{
+       struct pmic_mtk_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       /*
+        * dev_read_addr() can't be used here because the reg property actually
+        * contains two discrete values, not a single 64-bit address.
+        * The address is the first value.
+        */
+       ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", 0, &priv->usid);
+       if (ret < 0)
+               return -EINVAL;
+
+       debug("usid: %d\n", priv->usid);
+
+       return 0;
+}
+
+U_BOOT_DRIVER(pmic_mtk_spmi) = {
+       .name = "pmic_mtk_spmi",
+       .id = UCLASS_PMIC,
+       .of_match = pmic_mtk_ids,
+       .bind = dm_scan_fdt_dev,
+       .probe = pmic_mtk_probe,
+       .ops = &pmic_mtk_ops,
+       .priv_auto      = sizeof(struct pmic_mtk_priv),
+};

-- 
2.53.0

Reply via email to