[PATCH] sunxi: spl: support DM I2C PMIC bus
James Hilliard
james.hilliard1 at gmail.com
Fri Jun 26 05:09:07 CEST 2026
sunxi_board_init() may need to configure AXP regulators before DRAM is
available. The legacy I2C SPL path calls i2c_init_board() before
sunxi_board_init(), which enables the TWI clock/reset and pinmux. Do the
same when SPL DM I2C is enabled, but keep i2c_init() limited to the
legacy I2C path.
Expose i2c_init_board() to DM I2C callers through the I2C header instead
of adding a local sunxi prototype.
The AXP PMIC bus helper path used when SPL_PMIC_AXP is disabled also
still used the legacy I2C accessors. Add a DM I2C path by resolving the
PMIC bus and chip address from the control FDT, then using dm_i2c_read()
and dm_i2c_write(). Return an error if the PMIC node is not present in
the control FDT rather than guessing at the first I2C bus.
Do not cache the DM bus in static storage: this path runs before DRAM
init in SPL, and SPL BSS may live in DRAM. Resolve the bus locally
instead so the early PMIC path does not depend on pre-DRAM BSS.
Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
arch/arm/mach-sunxi/board.c | 5 +-
arch/arm/mach-sunxi/pmic_bus.c | 127 +++++++++++++++++++++++++++++++++
include/i2c.h | 3 +-
3 files changed, 133 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 432b1c10f92..aed50ecbf48 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -483,10 +483,13 @@ void board_init_f(ulong dummy)
spl_init();
preloader_console_init();
-#if CONFIG_IS_ENABLED(I2C) && CONFIG_IS_ENABLED(SYS_I2C_LEGACY)
+#if CONFIG_IS_ENABLED(I2C) && \
+ (CONFIG_IS_ENABLED(SYS_I2C_LEGACY) || CONFIG_IS_ENABLED(DM_I2C))
/* Needed early by sunxi_board_init if PMU is enabled */
i2c_init_board();
+#if CONFIG_IS_ENABLED(SYS_I2C_LEGACY)
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
#endif
sunxi_board_init();
}
diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c
index c77dc538456..52594e7896f 100644
--- a/arch/arm/mach-sunxi/pmic_bus.c
+++ b/arch/arm/mach-sunxi/pmic_bus.c
@@ -10,6 +10,9 @@
#include <axp_pmic.h>
#include <dm.h>
+#include <dm/ofnode.h>
+#include <dm/uclass.h>
+#include <errno.h>
#include <asm/arch/p2wi.h>
#include <asm/arch/rsb.h>
#include <i2c.h>
@@ -22,6 +25,102 @@
static struct udevice *pmic;
#endif
+#if !CONFIG_IS_ENABLED(PMIC_AXP) && CONFIG_IS_ENABLED(DM_I2C)
+static int pmic_bus_get_i2c_bus(struct udevice **busp, ofnode *nodep)
+{
+ static const char * const compatibles[] = {
+#if defined(CONFIG_AXP152_POWER)
+ "x-powers,axp152",
+#endif
+#if defined(CONFIG_AXP209_POWER)
+ "x-powers,axp202",
+ "x-powers,axp209",
+#endif
+#if defined(CONFIG_AXP221_POWER)
+ "x-powers,axp221",
+ "x-powers,axp223",
+#endif
+#if defined(CONFIG_AXP305_POWER)
+ "x-powers,axp305",
+#endif
+#if defined(CONFIG_AXP313_POWER)
+ "x-powers,axp313a",
+ "x-powers,axp323",
+#endif
+#if defined(CONFIG_AXP318W_POWER)
+ "x-powers,axp318w",
+#endif
+#if defined(CONFIG_AXP717_POWER)
+ "x-powers,axp717",
+#endif
+#if defined(CONFIG_AXP803_POWER)
+ "x-powers,axp803",
+#endif
+#if defined(CONFIG_AXP809_POWER)
+ "x-powers,axp809",
+ "x-powers,axp806",
+#endif
+#if defined(CONFIG_AXP818_POWER)
+ "x-powers,axp818",
+ "x-powers,axp813",
+#endif
+ };
+ struct udevice *bus;
+ ofnode node;
+ int i, ret;
+
+ for (i = 0, node = ofnode_null(); i < ARRAY_SIZE(compatibles); i++) {
+ node = ofnode_by_compatible(ofnode_null(), compatibles[i]);
+ if (ofnode_valid(node))
+ break;
+ }
+
+ if (!ofnode_valid(node))
+ return -ENODEV;
+
+ ret = uclass_get_device_by_ofnode(UCLASS_I2C, ofnode_get_parent(node),
+ &bus);
+ if (ret)
+ return ret;
+
+ *busp = bus;
+ if (nodep)
+ *nodep = node;
+
+ return 0;
+}
+
+static int pmic_bus_get_i2c_chip(struct udevice **devp)
+{
+ struct udevice *bus;
+ ofnode node;
+ u32 addr;
+ int ret;
+
+ ret = pmic_bus_get_i2c_bus(&bus, &node);
+ if (ret)
+ return ret;
+
+ ret = ofnode_read_u32(node, "reg", &addr);
+ if (ret)
+ return ret;
+
+ return i2c_get_chip(bus, addr, 1, devp);
+}
+
+static int pmic_bus_init_i2c(void)
+{
+ struct udevice *bus;
+
+ return pmic_bus_get_i2c_bus(&bus, NULL);
+}
+#else
+static int __maybe_unused pmic_bus_init_i2c(void)
+{
+ return -ENODEV;
+}
+#endif
+
int pmic_bus_init(void)
{
/* This cannot be 0 because it is used in SPL before BSS is ready */
@@ -47,6 +146,8 @@ int pmic_bus_init(void)
ret = rsb_set_device_address(AXP_PMIC_PRI_DEVICE_ADDR,
AXP_PMIC_PRI_RUNTIME_ADDR);
+ } else if (CONFIG_IS_ENABLED(DM_I2C)) {
+ ret = pmic_bus_init_i2c();
}
#endif
@@ -60,13 +161,26 @@ int pmic_bus_read(u8 reg, u8 *data)
#if CONFIG_IS_ENABLED(PMIC_AXP)
return pmic_read(pmic, reg, data, 1);
#else
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct udevice *dev;
+ int ret;
+#endif
+
if (IS_ENABLED(CONFIG_SYS_I2C_SUN6I_P2WI))
return p2wi_read(reg, data);
if (IS_ENABLED(CONFIG_SYS_I2C_SUN8I_RSB))
return rsb_read(AXP_PMIC_PRI_RUNTIME_ADDR, reg, data);
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ret = pmic_bus_get_i2c_chip(&dev);
+ if (ret)
+ return ret;
+
+ return dm_i2c_read(dev, reg, data, 1);
+#else
return i2c_read(CONFIG_AXP_I2C_ADDRESS, reg, 1, data, 1);
#endif
+#endif
}
int pmic_bus_write(u8 reg, u8 data)
@@ -74,13 +188,26 @@ int pmic_bus_write(u8 reg, u8 data)
#if CONFIG_IS_ENABLED(PMIC_AXP)
return pmic_write(pmic, reg, &data, 1);
#else
+#if CONFIG_IS_ENABLED(DM_I2C)
+ struct udevice *dev;
+ int ret;
+#endif
+
if (IS_ENABLED(CONFIG_SYS_I2C_SUN6I_P2WI))
return p2wi_write(reg, data);
if (IS_ENABLED(CONFIG_SYS_I2C_SUN8I_RSB))
return rsb_write(AXP_PMIC_PRI_RUNTIME_ADDR, reg, data);
+#if CONFIG_IS_ENABLED(DM_I2C)
+ ret = pmic_bus_get_i2c_chip(&dev);
+ if (ret)
+ return ret;
+
+ return dm_i2c_write(dev, reg, &data, 1);
+#else
return i2c_write(CONFIG_AXP_I2C_ADDRESS, reg, 1, &data, 1);
#endif
+#endif
}
int pmic_bus_setbits(u8 reg, u8 bits)
diff --git a/include/i2c.h b/include/i2c.h
index b2572076236..00f33c9e8e2 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -613,6 +613,8 @@ int acpi_i2c_of_to_plat(struct udevice *dev);
void i2c_early_init_f(void);
#endif
+void i2c_init_board(void);
+
#if !CONFIG_IS_ENABLED(DM_I2C)
/*
@@ -700,7 +702,6 @@ struct i2c_adapter *i2c_get_adapter(int index);
* repeatedly to change the speed and slave addresses.
*/
void i2c_init(int speed, int slaveaddr);
-void i2c_init_board(void);
#if CONFIG_IS_ENABLED(SYS_I2C_LEGACY)
/*
--
2.53.0
More information about the U-Boot
mailing list