[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