summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-sunxi/Kconfig18
-rw-r--r--arch/arm/mach-sunxi/Makefile1
-rw-r--r--arch/arm/mach-sunxi/pmic_bus.c11
-rw-r--r--arch/arm/mach-sunxi/rsb.c175
-rw-r--r--configs/Cubieboard4_defconfig2
-rw-r--r--configs/Merrii_A80_Optimus_defconfig2
-rw-r--r--drivers/i2c/Kconfig8
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/sun8i_rsb.c281
-rw-r--r--include/axp_pmic.h6
10 files changed, 309 insertions, 196 deletions
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index f4a45284bd..10401d3249 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -100,14 +100,6 @@ config AXP_PMIC_BUS
Select this PMIC bus access helpers for Sunxi platform PRCM or other
AXP family PMIC devices.
-config SUN8I_RSB
- bool "Allwinner sunXi Reduced Serial Bus Driver"
- help
- Say y here to enable support for Allwinner's Reduced Serial Bus
- (RSB) support. This controller is responsible for communicating
- with various RSB based devices, such as AXP223, AXP8XX PMICs,
- and AC100/AC200 ICs.
-
config SUNXI_SRAM_ADDRESS
hex
default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
@@ -250,9 +242,10 @@ config MACH_SUN8I_A23
select ARCH_SUPPORT_PSCI
select DRAM_SUN8I_A23
select PHY_SUN4I_USB
- select SUN8I_RSB
+ select SPL_I2C
select SUNXI_GEN_SUN6I
select SUPPORT_SPL
+ select SYS_I2C_SUN8I_RSB
select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
imply CONS_INDEX_5 if !DM_SERIAL
@@ -264,9 +257,10 @@ config MACH_SUN8I_A33
select ARCH_SUPPORT_PSCI
select DRAM_SUN8I_A33
select PHY_SUN4I_USB
- select SUN8I_RSB
+ select SPL_I2C
select SUNXI_GEN_SUN6I
select SUPPORT_SPL
+ select SYS_I2C_SUN8I_RSB
select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
imply CONS_INDEX_5 if !DM_SERIAL
@@ -275,11 +269,12 @@ config MACH_SUN8I_A83T
select CPU_V7A
select DRAM_SUN8I_A83T
select PHY_SUN4I_USB
- select SUN8I_RSB
+ select SPL_I2C
select SUNXI_GEN_SUN6I
select MMC_SUNXI_HAS_NEW_MODE
select MMC_SUNXI_HAS_MODE_SWITCH
select SUPPORT_SPL
+ select SYS_I2C_SUN8I_RSB
config MACH_SUN8I_H3
bool "sun8i (Allwinner H3)"
@@ -320,6 +315,7 @@ config MACH_SUN9I
bool "sun9i (Allwinner A80)"
select CPU_V7A
select DRAM_SUN9I
+ select SPL_I2C
select SUN6I_PRCM
select SUNXI_GEN_SUN6I
select SUPPORT_SPL
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index c9312bb393..5d3fd70f74 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -13,7 +13,6 @@ obj-y += dram_helpers.o
obj-y += pinmux.o
obj-$(CONFIG_SUN6I_PRCM) += prcm.o
obj-$(CONFIG_AXP_PMIC_BUS) += pmic_bus.o
-obj-$(CONFIG_SUN8I_RSB) += rsb.o
obj-$(CONFIG_MACH_SUN4I) += clock_sun4i.o
obj-$(CONFIG_MACH_SUN5I) += clock_sun4i.o
obj-$(CONFIG_MACH_SUN6I) += clock_sun6i.o
diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c
index 673a05fdd1..827797249e 100644
--- a/arch/arm/mach-sunxi/pmic_bus.c
+++ b/arch/arm/mach-sunxi/pmic_bus.c
@@ -23,10 +23,6 @@
#define AXP221_CHIP_ADDR 0x68
-/* AXP818 device and runtime addresses are same as AXP223 */
-#define AXP223_DEVICE_ADDR 0x3a3
-#define AXP223_RUNTIME_ADDR 0x2d
-
int pmic_bus_init(void)
{
/* This cannot be 0 because it is used in SPL before BSS is ready */
@@ -49,7 +45,8 @@ int pmic_bus_init(void)
if (ret)
return ret;
- ret = rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
+ ret = rsb_set_device_address(AXP_PMIC_PRI_DEVICE_ADDR,
+ AXP_PMIC_PRI_RUNTIME_ADDR);
# endif
if (ret)
return ret;
@@ -73,7 +70,7 @@ int pmic_bus_read(u8 reg, u8 *data)
# elif defined CONFIG_MACH_SUN8I_R40
return i2c_read(AXP209_I2C_ADDR, reg, 1, data, 1);
# else
- return rsb_read(AXP223_RUNTIME_ADDR, reg, data);
+ return rsb_read(AXP_PMIC_PRI_RUNTIME_ADDR, reg, data);
# endif
#endif
}
@@ -92,7 +89,7 @@ int pmic_bus_write(u8 reg, u8 data)
# elif defined CONFIG_MACH_SUN8I_R40
return i2c_write(AXP209_I2C_ADDR, reg, 1, &data, 1);
# else
- return rsb_write(AXP223_RUNTIME_ADDR, reg, data);
+ return rsb_write(AXP_PMIC_PRI_RUNTIME_ADDR, reg, data);
# endif
#endif
}
diff --git a/arch/arm/mach-sunxi/rsb.c b/arch/arm/mach-sunxi/rsb.c
deleted file mode 100644
index 01bb09b747..0000000000
--- a/arch/arm/mach-sunxi/rsb.c
+++ /dev/null
@@ -1,175 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
- *
- * Based on allwinner u-boot sources rsb code which is:
- * (C) Copyright 2007-2013
- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
- * lixiang <lixiang@allwinnertech.com>
- */
-
-#include <common.h>
-#include <errno.h>
-#include <time.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
-#include <asm/arch/prcm.h>
-#include <asm/arch/rsb.h>
-
-static int rsb_set_device_mode(void);
-
-static void rsb_cfg_io(void)
-{
-#ifdef CONFIG_MACH_SUN8I
- sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL_R_RSB);
- sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL_R_RSB);
- sunxi_gpio_set_pull(SUNXI_GPL(0), 1);
- sunxi_gpio_set_pull(SUNXI_GPL(1), 1);
- sunxi_gpio_set_drv(SUNXI_GPL(0), 2);
- sunxi_gpio_set_drv(SUNXI_GPL(1), 2);
-#elif defined CONFIG_MACH_SUN9I
- sunxi_gpio_set_cfgpin(SUNXI_GPN(0), SUN9I_GPN_R_RSB);
- sunxi_gpio_set_cfgpin(SUNXI_GPN(1), SUN9I_GPN_R_RSB);
- sunxi_gpio_set_pull(SUNXI_GPN(0), 1);
- sunxi_gpio_set_pull(SUNXI_GPN(1), 1);
- sunxi_gpio_set_drv(SUNXI_GPN(0), 2);
- sunxi_gpio_set_drv(SUNXI_GPN(1), 2);
-#else
-#error unsupported MACH_SUNXI
-#endif
-}
-
-static void rsb_set_clk(void)
-{
- struct sunxi_rsb_reg * const rsb =
- (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
- u32 div = 0;
- u32 cd_odly = 0;
-
- /* Source is Hosc24M, set RSB clk to 3Mhz */
- div = 24000000 / 3000000 / 2 - 1;
- cd_odly = div >> 1;
- if (!cd_odly)
- cd_odly = 1;
-
- writel((cd_odly << 8) | div, &rsb->ccr);
-}
-
-int rsb_init(void)
-{
- struct sunxi_rsb_reg * const rsb =
- (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
-
- /* Enable RSB and PIO clk, and de-assert their resets */
- prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_RSB);
-
- /* Setup external pins */
- rsb_cfg_io();
-
- writel(RSB_CTRL_SOFT_RST, &rsb->ctrl);
- rsb_set_clk();
-
- return rsb_set_device_mode();
-}
-
-static int rsb_await_trans(void)
-{
- struct sunxi_rsb_reg * const rsb =
- (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
- unsigned long tmo = timer_get_us() + 1000000;
- u32 stat;
- int ret;
-
- while (1) {
- stat = readl(&rsb->stat);
- if (stat & RSB_STAT_LBSY_INT) {
- ret = -EBUSY;
- break;
- }
- if (stat & RSB_STAT_TERR_INT) {
- ret = -EIO;
- break;
- }
- if (stat & RSB_STAT_TOVER_INT) {
- ret = 0;
- break;
- }
- if (timer_get_us() > tmo) {
- ret = -ETIME;
- break;
- }
- }
- writel(stat, &rsb->stat); /* Clear status bits */
-
- return ret;
-}
-
-static int rsb_set_device_mode(void)
-{
- struct sunxi_rsb_reg * const rsb =
- (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
- unsigned long tmo = timer_get_us() + 1000000;
-
- writel(RSB_DMCR_DEVICE_MODE_START | RSB_DMCR_DEVICE_MODE_DATA,
- &rsb->dmcr);
-
- while (readl(&rsb->dmcr) & RSB_DMCR_DEVICE_MODE_START) {
- if (timer_get_us() > tmo)
- return -ETIME;
- }
-
- return rsb_await_trans();
-}
-
-static int rsb_do_trans(void)
-{
- struct sunxi_rsb_reg * const rsb =
- (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
-
- setbits_le32(&rsb->ctrl, RSB_CTRL_START_TRANS);
- return rsb_await_trans();
-}
-
-int rsb_set_device_address(u16 device_addr, u16 runtime_addr)
-{
- struct sunxi_rsb_reg * const rsb =
- (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
-
- writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr) |
- RSB_DEVADDR_DEVICE_ADDR(device_addr), &rsb->devaddr);
- writel(RSB_CMD_SET_RTSADDR, &rsb->cmd);
-
- return rsb_do_trans();
-}
-
-int rsb_write(const u16 runtime_device_addr, const u8 reg_addr, u8 data)
-{
- struct sunxi_rsb_reg * const rsb =
- (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
-
- writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_device_addr), &rsb->devaddr);
- writel(reg_addr, &rsb->addr);
- writel(data, &rsb->data);
- writel(RSB_CMD_BYTE_WRITE, &rsb->cmd);
-
- return rsb_do_trans();
-}
-
-int rsb_read(const u16 runtime_device_addr, const u8 reg_addr, u8 *data)
-{
- struct sunxi_rsb_reg * const rsb =
- (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
- int ret;
-
- writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_device_addr), &rsb->devaddr);
- writel(reg_addr, &rsb->addr);
- writel(RSB_CMD_BYTE_READ, &rsb->cmd);
-
- ret = rsb_do_trans();
- if (ret)
- return ret;
-
- *data = readl(&rsb->data) & 0xff;
-
- return 0;
-}
diff --git a/configs/Cubieboard4_defconfig b/configs/Cubieboard4_defconfig
index 0377bb83da..3848cab4b6 100644
--- a/configs/Cubieboard4_defconfig
+++ b/configs/Cubieboard4_defconfig
@@ -11,6 +11,6 @@ CONFIG_USB0_VBUS_DET="AXP0-VBUS-DETECT"
CONFIG_USB0_ID_DET="PH16"
CONFIG_USB1_VBUS_PIN="PH14"
CONFIG_USB3_VBUS_PIN="PH15"
-CONFIG_SUN8I_RSB=y
+CONFIG_SYS_I2C_SUN8I_RSB=y
CONFIG_AXP_GPIO=y
CONFIG_AXP809_POWER=y
diff --git a/configs/Merrii_A80_Optimus_defconfig b/configs/Merrii_A80_Optimus_defconfig
index 8fb6504209..35e575327f 100644
--- a/configs/Merrii_A80_Optimus_defconfig
+++ b/configs/Merrii_A80_Optimus_defconfig
@@ -11,6 +11,6 @@ CONFIG_USB0_VBUS_DET="AXP0-VBUS-DETECT"
CONFIG_USB0_ID_DET="PH3"
CONFIG_USB1_VBUS_PIN="PH4"
CONFIG_USB3_VBUS_PIN="PH5"
-CONFIG_SUN8I_RSB=y
+CONFIG_SYS_I2C_SUN8I_RSB=y
CONFIG_AXP_GPIO=y
CONFIG_AXP809_POWER=y
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 0adf143abf..66bd6fe2f3 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -583,6 +583,14 @@ config SYS_I2C_SUN6I_P2WI
in the Allwinner A31 and A31s SOCs. This interface is used to connect
to specific devices like the X-Powers AXP221 PMIC.
+config SYS_I2C_SUN8I_RSB
+ bool "Allwinner sun8i Reduced Serial Bus controller"
+ depends on ARCH_SUNXI
+ help
+ Support for Allwinner's Reduced Serial Bus (RSB) controller. This
+ controller is responsible for communicating with various RSB based
+ devices, such as X-Powers AXPxxx PMICs and AC100/AC200 CODEC ICs.
+
config SYS_I2C_SYNQUACER
bool "Socionext SynQuacer I2C controller"
depends on ARCH_SYNQUACER && DM_I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 0a2cc64193..916427452a 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o
obj-$(CONFIG_SYS_I2C_SUN6I_P2WI) += sun6i_p2wi.o
+obj-$(CONFIG_SYS_I2C_SUN8I_RSB) += sun8i_rsb.o
obj-$(CONFIG_SYS_I2C_SYNQUACER) += synquacer_i2c.o
obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
diff --git a/drivers/i2c/sun8i_rsb.c b/drivers/i2c/sun8i_rsb.c
new file mode 100644
index 0000000000..716b245a00
--- /dev/null
+++ b/drivers/i2c/sun8i_rsb.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on allwinner u-boot sources rsb code which is:
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * lixiang <lixiang@allwinnertech.com>
+ */
+
+#include <axp_pmic.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <time.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/prcm.h>
+#include <asm/arch/rsb.h>
+
+static int sun8i_rsb_await_trans(struct sunxi_rsb_reg *base)
+{
+ unsigned long tmo = timer_get_us() + 1000000;
+ u32 stat;
+ int ret;
+
+ while (1) {
+ stat = readl(&base->stat);
+ if (stat & RSB_STAT_LBSY_INT) {
+ ret = -EBUSY;
+ break;
+ }
+ if (stat & RSB_STAT_TERR_INT) {
+ ret = -EIO;
+ break;
+ }
+ if (stat & RSB_STAT_TOVER_INT) {
+ ret = 0;
+ break;
+ }
+ if (timer_get_us() > tmo) {
+ ret = -ETIME;
+ break;
+ }
+ }
+ writel(stat, &base->stat); /* Clear status bits */
+
+ return ret;
+}
+
+static int sun8i_rsb_do_trans(struct sunxi_rsb_reg *base)
+{
+ setbits_le32(&base->ctrl, RSB_CTRL_START_TRANS);
+
+ return sun8i_rsb_await_trans(base);
+}
+
+static int sun8i_rsb_read(struct sunxi_rsb_reg *base, u16 runtime_addr,
+ u8 reg_addr, u8 *data)
+{
+ int ret;
+
+ writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr), &base->devaddr);
+ writel(reg_addr, &base->addr);
+ writel(RSB_CMD_BYTE_READ, &base->cmd);
+
+ ret = sun8i_rsb_do_trans(base);
+ if (ret)
+ return ret;
+
+ *data = readl(&base->data) & 0xff;
+
+ return 0;
+}
+
+static int sun8i_rsb_write(struct sunxi_rsb_reg *base, u16 runtime_addr,
+ u8 reg_addr, u8 data)
+{
+ writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr), &base->devaddr);
+ writel(reg_addr, &base->addr);
+ writel(data, &base->data);
+ writel(RSB_CMD_BYTE_WRITE, &base->cmd);
+
+ return sun8i_rsb_do_trans(base);
+}
+
+static int sun8i_rsb_set_device_address(struct sunxi_rsb_reg *base,
+ u16 device_addr, u16 runtime_addr)
+{
+ writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr) |
+ RSB_DEVADDR_DEVICE_ADDR(device_addr), &base->devaddr);
+ writel(RSB_CMD_SET_RTSADDR, &base->cmd);
+
+ return sun8i_rsb_do_trans(base);
+}
+
+static void sun8i_rsb_cfg_io(void)
+{
+#ifdef CONFIG_MACH_SUN8I
+ sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL_R_RSB);
+ sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL_R_RSB);
+ sunxi_gpio_set_pull(SUNXI_GPL(0), 1);
+ sunxi_gpio_set_pull(SUNXI_GPL(1), 1);
+ sunxi_gpio_set_drv(SUNXI_GPL(0), 2);
+ sunxi_gpio_set_drv(SUNXI_GPL(1), 2);
+#elif defined CONFIG_MACH_SUN9I
+ sunxi_gpio_set_cfgpin(SUNXI_GPN(0), SUN9I_GPN_R_RSB);
+ sunxi_gpio_set_cfgpin(SUNXI_GPN(1), SUN9I_GPN_R_RSB);
+ sunxi_gpio_set_pull(SUNXI_GPN(0), 1);
+ sunxi_gpio_set_pull(SUNXI_GPN(1), 1);
+ sunxi_gpio_set_drv(SUNXI_GPN(0), 2);
+ sunxi_gpio_set_drv(SUNXI_GPN(1), 2);
+#else
+#error unsupported MACH_SUNXI
+#endif
+}
+
+static void sun8i_rsb_set_clk(struct sunxi_rsb_reg *base)
+{
+ u32 div = 0;
+ u32 cd_odly = 0;
+
+ /* Source is Hosc24M, set RSB clk to 3Mhz */
+ div = 24000000 / 3000000 / 2 - 1;
+ cd_odly = div >> 1;
+ if (!cd_odly)
+ cd_odly = 1;
+
+ writel((cd_odly << 8) | div, &base->ccr);
+}
+
+static int sun8i_rsb_set_device_mode(struct sunxi_rsb_reg *base)
+{
+ unsigned long tmo = timer_get_us() + 1000000;
+
+ writel(RSB_DMCR_DEVICE_MODE_START | RSB_DMCR_DEVICE_MODE_DATA,
+ &base->dmcr);
+
+ while (readl(&base->dmcr) & RSB_DMCR_DEVICE_MODE_START) {
+ if (timer_get_us() > tmo)
+ return -ETIME;
+ }
+
+ return sun8i_rsb_await_trans(base);
+}
+
+static int sun8i_rsb_init(struct sunxi_rsb_reg *base)
+{
+ /* Enable RSB and PIO clk, and de-assert their resets */
+ prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_RSB);
+
+ /* Setup external pins */
+ sun8i_rsb_cfg_io();
+
+ writel(RSB_CTRL_SOFT_RST, &base->ctrl);
+ sun8i_rsb_set_clk(base);
+
+ return sun8i_rsb_set_device_mode(base);
+}
+
+#if IS_ENABLED(CONFIG_AXP_PMIC_BUS)
+int rsb_read(const u16 runtime_addr, const u8 reg_addr, u8 *data)
+{
+ struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+ return sun8i_rsb_read(base, runtime_addr, reg_addr, data);
+}
+
+int rsb_write(const u16 runtime_addr, const u8 reg_addr, u8 data)
+{
+ struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+ return sun8i_rsb_write(base, runtime_addr, reg_addr, data);
+}
+
+int rsb_set_device_address(u16 device_addr, u16 runtime_addr)
+{
+ struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+ return sun8i_rsb_set_device_address(base, device_addr, runtime_addr);
+}
+
+int rsb_init(void)
+{
+ struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+ return sun8i_rsb_init(base);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+struct sun8i_rsb_priv {
+ struct sunxi_rsb_reg *base;
+};
+
+/*
+ * The mapping from hardware address to runtime address is fixed, and shared
+ * among all RSB drivers. See the comment in drivers/bus/sunxi-rsb.c in Linux.
+ */
+static int sun8i_rsb_get_runtime_address(u16 device_addr)
+{
+ if (device_addr == AXP_PMIC_PRI_DEVICE_ADDR)
+ return AXP_PMIC_PRI_RUNTIME_ADDR;
+ if (device_addr == AXP_PMIC_SEC_DEVICE_ADDR)
+ return AXP_PMIC_SEC_RUNTIME_ADDR;
+
+ return -ENXIO;
+}
+
+static int sun8i_rsb_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ int runtime_addr = sun8i_rsb_get_runtime_address(msg->addr);
+ struct sun8i_rsb_priv *priv = dev_get_priv(bus);
+
+ if (runtime_addr < 0)
+ return runtime_addr;
+
+ /* The hardware only supports SMBus-style transfers. */
+ if (nmsgs == 2 && msg[1].flags == I2C_M_RD && msg[1].len == 1)
+ return sun8i_rsb_read(priv->base, runtime_addr,
+ msg[0].buf[0], &msg[1].buf[0]);
+
+ if (nmsgs == 1 && msg[0].len == 2)
+ return sun8i_rsb_write(priv->base, runtime_addr,
+ msg[0].buf[0], msg[0].buf[1]);
+
+ return -EINVAL;
+}
+
+static int sun8i_rsb_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ int runtime_addr = sun8i_rsb_get_runtime_address(chip_addr);
+ struct sun8i_rsb_priv *priv = dev_get_priv(bus);
+
+ if (runtime_addr < 0)
+ return runtime_addr;
+
+ return sun8i_rsb_set_device_address(priv->base, chip_addr, runtime_addr);
+}
+
+static int sun8i_rsb_probe(struct udevice *bus)
+{
+ struct sun8i_rsb_priv *priv = dev_get_priv(bus);
+
+ priv->base = dev_read_addr_ptr(bus);
+
+ return sun8i_rsb_init(priv->base);
+}
+
+static int sun8i_rsb_child_pre_probe(struct udevice *child)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(child);
+
+ /* Ensure each transfer is for a single register. */
+ chip->flags |= DM_I2C_CHIP_RD_ADDRESS | DM_I2C_CHIP_WR_ADDRESS;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops sun8i_rsb_ops = {
+ .xfer = sun8i_rsb_xfer,
+ .probe_chip = sun8i_rsb_probe_chip,
+};
+
+static const struct udevice_id sun8i_rsb_ids[] = {
+ { .compatible = "allwinner,sun8i-a23-rsb" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sun8i_rsb) = {
+ .name = "sun8i_rsb",
+ .id = UCLASS_I2C,
+ .of_match = sun8i_rsb_ids,
+ .probe = sun8i_rsb_probe,
+ .child_pre_probe = sun8i_rsb_child_pre_probe,
+ .priv_auto = sizeof(struct sun8i_rsb_priv),
+ .ops = &sun8i_rsb_ops,
+};
+#endif /* CONFIG_IS_ENABLED(DM_I2C) */
diff --git a/include/axp_pmic.h b/include/axp_pmic.h
index 0db3e143ed..46a017d2ef 100644
--- a/include/axp_pmic.h
+++ b/include/axp_pmic.h
@@ -30,6 +30,12 @@
#define AXP_PMIC_MODE_REG 0x3e
#define AXP_PMIC_MODE_I2C 0x00
#define AXP_PMIC_MODE_P2WI 0x3e
+#define AXP_PMIC_MODE_RSB 0x7c
+
+#define AXP_PMIC_PRI_DEVICE_ADDR 0x3a3
+#define AXP_PMIC_PRI_RUNTIME_ADDR 0x2d
+#define AXP_PMIC_SEC_DEVICE_ADDR 0x745
+#define AXP_PMIC_SEC_RUNTIME_ADDR 0x3a
int axp_set_dcdc1(unsigned int mvolt);
int axp_set_dcdc2(unsigned int mvolt);