From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 17A2FC433EF for ; Tue, 12 Oct 2021 10:49:43 +0000 (UTC) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7FC3461050 for ; Tue, 12 Oct 2021 10:49:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 7FC3461050 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=lists.denx.de Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 18C6783745; Tue, 12 Oct 2021 12:49:40 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id 78A0583743; Tue, 12 Oct 2021 12:49:38 +0200 (CEST) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id 005938373B for ; Tue, 12 Oct 2021 12:49:29 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=andre.przywara@arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 41505101E; Tue, 12 Oct 2021 03:49:29 -0700 (PDT) Received: from donnerap.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.121.207.14]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3B3CC3F694; Tue, 12 Oct 2021 03:49:27 -0700 (PDT) Date: Tue, 12 Oct 2021 11:49:24 +0100 From: Andre Przywara To: Samuel Holland Cc: u-boot@lists.denx.de, Jagan Teki , Jaehoon Chung , Heiko Schocher , Anatolij Gustschin , Arnaud Ferraris , Bharat Gooty , Igor Opaniuk , Jernej Skrabec , Minkyu Kang , Rayagonda Kokatanur , Simon Glass , Stephan Gerhold , Tim Harvey , Tom Rini Subject: Re: [PATCH v2 08/12] i2c: Add a DM_I2C driver for the sun8i RSB controller Message-ID: <20211012114924.2d54f616@donnerap.cambridge.arm.com> In-Reply-To: <20211008051725.29401-9-samuel@sholland.org> References: <20211008051725.29401-1-samuel@sholland.org> <20211008051725.29401-9-samuel@sholland.org> Organization: ARM X-Mailer: Claws Mail 3.17.5 (GTK+ 2.24.32; aarch64-unknown-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean On Fri, 8 Oct 2021 00:17:21 -0500 Samuel Holland wrote: > This bus controller is used to communicate with an X-Powers AXP PMIC. > Currently, various drivers access PMIC registers through a platform- > specific non-DM "pmic_bus" interface, which depends on the legacy I2C > framework. In order to convert those drivers to use DM_PMIC, this bus > needs a DM_I2C driver. > > Refactor the rsb functions to take the base address as a parameter, > and implement both the existing interface (which is still needed in > SPL) and the DM_I2C interface on top of them. I diff'ed the (slightly tweaked) old version and the new file, and can indeed confirm that it's a conversion that preserves the actual functionality. The new DM wrappers look good as well. > The register for switching between I2C/P2WI/RSB mode is the same across > all PMIC variants, so move that to the common header. > > There are only a couple of pairs of hardware/runtime addresses used > across all PMIC variants. So far the code expected only the "primary" > pair, but some PMICs like the AXP305 and AXP805 use the secondary pair, > so add support for that to the DM driver as well. > > Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Cheers, Andre > --- > > Changes in v2: > - Renamed Kconfig symbol to SYS_I2C_SUN8I_RSB > - Moved entire RSB driver source to drivers/i2c > > arch/arm/mach-sunxi/Kconfig | 20 +-- > arch/arm/mach-sunxi/Makefile | 1 - > arch/arm/mach-sunxi/pmic_bus.c | 11 +- > arch/arm/mach-sunxi/rsb.c | 175 -------------------- > drivers/i2c/Kconfig | 8 + > drivers/i2c/Makefile | 1 + > drivers/i2c/sun8i_rsb.c | 281 +++++++++++++++++++++++++++++++++ > include/axp_pmic.h | 6 + > 8 files changed, 308 insertions(+), 195 deletions(-) > delete mode 100644 arch/arm/mach-sunxi/rsb.c > create mode 100644 drivers/i2c/sun8i_rsb.c > > diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig > index ae3b7974f09..df160c9a775 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,10 +315,11 @@ config MACH_SUN9I > bool "sun9i (Allwinner A80)" > select CPU_V7A > select DRAM_SUN9I > + select SPL_I2C > select SUN6I_PRCM > select SUNXI_GEN_SUN6I > - select SUN8I_RSB > select SUPPORT_SPL > + select SYS_I2C_SUN8I_RSB > > config MACH_SUN50I > bool "sun50i (Allwinner A64)" > diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile > index c9312bb3934..5d3fd70f749 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 673a05fdd16..827797249ea 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 01bb09b7478..00000000000 > --- 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 > - * > - * Based on allwinner u-boot sources rsb code which is: > - * (C) Copyright 2007-2013 > - * Allwinner Technology Co., Ltd. > - * lixiang > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -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/drivers/i2c/Kconfig b/drivers/i2c/Kconfig > index 0adf143abfd..66bd6fe2f34 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 0a2cc641930..916427452a5 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 00000000000..716b245a003 > --- /dev/null > +++ b/drivers/i2c/sun8i_rsb.c > @@ -0,0 +1,281 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * (C) Copyright 2014 Hans de Goede > + * > + * Based on allwinner u-boot sources rsb code which is: > + * (C) Copyright 2007-2013 > + * Allwinner Technology Co., Ltd. > + * lixiang > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +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 0db3e143eda..46a017d2efa 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);