[U-Boot] [PATCH] i2c: rcar_iic: Add RCar IIC driver
Marek Vasut
marek.vasut at gmail.com
Thu Nov 30 00:33:55 UTC 2017
On 11/29/2017 06:59 AM, Heiko Schocher wrote:
> Hello Marek,
>
> Am 29.11.2017 um 03:48 schrieb Marek Vasut:
>> Add driver for the RCar IIC or DVFS I2C controller. This driver is based
>> on the SH I2C driver, but supports DM and DT probing as well as modern
>> I2C framework API.
>>
>> Signed-off-by: Marek Vasut <marek.vasut+renesas at gmail.com>
>> Cc: Nobuhiro Iwamatsu <iwamatsu at nigauri.org>
>> ---
>> drivers/i2c/Kconfig | 6 ++
>> drivers/i2c/Makefile | 1 +
>> drivers/i2c/rcar_iic.c | 271
>> +++++++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 278 insertions(+)
>> create mode 100644 drivers/i2c/rcar_iic.c
>
> Reviewed-by: Heiko Schocher <hs at denx.de>
>
> Just some dummy question below...
>
> [...]
>> diff --git a/drivers/i2c/rcar_iic.c b/drivers/i2c/rcar_iic.c
>> new file mode 100644
>> index 0000000000..57ae2f51fc
>> --- /dev/null
>> +++ b/drivers/i2c/rcar_iic.c
>> @@ -0,0 +1,271 @@
>> +/*
>> + * Renesas RCar IIC driver
>> + *
>> + * Copyright (C) 2017 Marek Vasut <marek.vasut at gmail.com>
>> + *
>> + * Based on
>> + * Copyright (C) 2011, 2013 Renesas Solutions Corp.
>> + * Copyright (C) 2011, 2013 Nobuhiro Iwamatsu
>> <nobuhiro.iwamatsu.yj at renesas.com>
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + */
>> +
>> +#include <common.h>
>> +#include <clk.h>
>> +#include <dm.h>
>> +#include <i2c.h>
>> +#include <asm/io.h>
>> +
>> +struct rcar_iic_priv {
>> + void __iomem *base;
>> + struct clk clk;
>> + u8 iccl;
>> + u8 icch;
>> +};
>> +
>> +#define RCAR_IIC_ICDR 0x00
>> +#define RCAR_IIC_ICCR 0x04
>> +#define RCAR_IIC_ICSR 0x08
>> +#define RCAR_IIC_ICIC 0x0c
>> +#define RCAR_IIC_ICCL 0x10
>> +#define RCAR_IIC_ICCH 0x14
>> +
>> +/* ICCR */
>> +#define RCAR_IIC_ICCR_ICE BIT(7)
>> +#define RCAR_IIC_ICCR_RACK BIT(6)
>> +#define RCAR_IIC_ICCR_RTS BIT(4)
>> +#define RCAR_IIC_ICCR_BUSY BIT(2)
>> +#define RCAR_IIC_ICCR_SCP BIT(0)
>> +
>> +/* ICSR / ICIC */
>> +#define RCAR_IC_BUSY BIT(4)
>> +#define RCAR_IC_TACK BIT(2)
>> +#define RCAR_IC_DTE BIT(0)
>> +
>> +#define IRQ_WAIT 1000
>> +
>> +static void sh_irq_dte(struct udevice *dev)
>> +{
>> + struct rcar_iic_priv *priv = dev_get_priv(dev);
>> + int i;
>> +
>> + for (i = 0; i < IRQ_WAIT; i++) {
>> + if (RCAR_IC_DTE & readb(priv->base + RCAR_IIC_ICSR))
>> + break;
>> + udelay(10);
>> + }
>> +}
>> +
>> +static int sh_irq_dte_with_tack(struct udevice *dev)
>> +{
>> + struct rcar_iic_priv *priv = dev_get_priv(dev);
>> + int i;
>> +
>> + for (i = 0; i < IRQ_WAIT; i++) {
>> + if (RCAR_IC_DTE & readb(priv->base + RCAR_IIC_ICSR))
>> + break;
>> + if (RCAR_IC_TACK & readb(priv->base + RCAR_IIC_ICSR))
>> + return -ETIMEDOUT;
>> + udelay(10);
>> + }
>> + return 0;
>> +}
>> +
>> +static void sh_irq_busy(struct udevice *dev)
>> +{
>> + struct rcar_iic_priv *priv = dev_get_priv(dev);
>> + int i;
>> +
>> + for (i = 0; i < IRQ_WAIT; i++) {
>> + if (!(RCAR_IC_BUSY & readb(priv->base + RCAR_IIC_ICSR)))
>> + break;
>> + udelay(10);
>> + }
>> +}
>> +
>> +static int rcar_iic_set_addr(struct udevice *dev, u8 chip, u8 read)
>> +{
>> + struct rcar_iic_priv *priv = dev_get_priv(dev);
>> +
>> + clrbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
>> + setbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
>> +
>> + writeb(priv->iccl, priv->base + RCAR_IIC_ICCL);
>> + writeb(priv->icch, priv->base + RCAR_IIC_ICCH);
>> + writeb(RCAR_IC_TACK, priv->base + RCAR_IIC_ICIC);
>> +
>> + writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RTS | RCAR_IIC_ICCR_BUSY,
>> + priv->base + RCAR_IIC_ICCR);
>> + sh_irq_dte(dev);
>> +
>> + clrbits_8(priv->base + RCAR_IIC_ICSR, RCAR_IC_TACK);
>> + writeb(chip << 1 | read, priv->base + RCAR_IIC_ICDR);
>> + return sh_irq_dte_with_tack(dev);
>> +}
>> +
>> +static void rcar_iic_finish(struct udevice *dev)
>> +{
>> + struct rcar_iic_priv *priv = dev_get_priv(dev);
>> +
>> + writeb(0, priv->base + RCAR_IIC_ICSR);
>> + clrbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
>> +}
>> +
>> +static int rcar_iic_read_common(struct udevice *dev, struct i2c_msg
>> *msg)
>> +{
>> + struct rcar_iic_priv *priv = dev_get_priv(dev);
>> + int i, ret = -EREMOTEIO;
>> +
>> + if (rcar_iic_set_addr(dev, msg->addr, 1) != 0)
>> + goto err;
>> +
>> + udelay(10);
>
> There are a lot of places with udelay(10) ... Is this documented in the
> docs?
Nope, but it is needed.
> Does it work with different i2c bus clock settings?
Yes, 100 and 400 kHz operation works.
--
Best regards,
Marek Vasut
More information about the U-Boot
mailing list