123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Renesas RCar IIC driver
- *
- * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
- *
- * Based on
- * Copyright (C) 2011, 2013 Renesas Solutions Corp.
- * Copyright (C) 2011, 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
- */
- #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);
- writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_SCP,
- priv->base + RCAR_IIC_ICCR);
- for (i = 0; i < msg->len; i++) {
- if (sh_irq_dte_with_tack(dev) != 0)
- goto err;
- msg->buf[i] = readb(priv->base + RCAR_IIC_ICDR) & 0xff;
- if (msg->len - 1 == i) {
- writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RACK,
- priv->base + RCAR_IIC_ICCR);
- }
- }
- sh_irq_busy(dev);
- ret = 0;
- err:
- rcar_iic_finish(dev);
- return ret;
- }
- static int rcar_iic_write_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, 0) != 0)
- goto err;
- udelay(10);
- for (i = 0; i < msg->len; i++) {
- writeb(msg->buf[i], priv->base + RCAR_IIC_ICDR);
- if (sh_irq_dte_with_tack(dev) != 0)
- goto err;
- }
- if (msg->flags & I2C_M_STOP) {
- writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RTS,
- priv->base + RCAR_IIC_ICCR);
- if (sh_irq_dte_with_tack(dev) != 0)
- goto err;
- }
- sh_irq_busy(dev);
- ret = 0;
- err:
- rcar_iic_finish(dev);
- return ret;
- }
- static int rcar_iic_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
- {
- int ret;
- for (; nmsgs > 0; nmsgs--, msg++) {
- if (msg->flags & I2C_M_RD)
- ret = rcar_iic_read_common(dev, msg);
- else
- ret = rcar_iic_write_common(dev, msg);
- if (ret)
- return -EREMOTEIO;
- }
- return ret;
- }
- static int rcar_iic_set_speed(struct udevice *dev, uint speed)
- {
- struct rcar_iic_priv *priv = dev_get_priv(dev);
- const unsigned int ratio_high = 4;
- const unsigned int ratio_low = 5;
- int clkrate, denom;
- clkrate = clk_get_rate(&priv->clk);
- if (clkrate < 0)
- return clkrate;
- /*
- * Calculate the value for ICCL and ICCH. From the data sheet:
- * iccl = (p-clock / transfer-rate) * (L / (L + H))
- * icch = (p clock / transfer rate) * (H / (L + H))
- * where L and H are the SCL low and high ratio.
- */
- denom = speed * (ratio_high + ratio_low);
- priv->iccl = DIV_ROUND_CLOSEST(clkrate * ratio_low, denom);
- priv->icch = DIV_ROUND_CLOSEST(clkrate * ratio_high, denom);
- return 0;
- }
- static int rcar_iic_probe_chip(struct udevice *dev, uint addr, uint flags)
- {
- struct rcar_iic_priv *priv = dev_get_priv(dev);
- int ret;
- rcar_iic_set_addr(dev, addr, 1);
- writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_SCP,
- priv->base + RCAR_IIC_ICCR);
- ret = sh_irq_dte_with_tack(dev);
- rcar_iic_finish(dev);
- return ret;
- }
- static int rcar_iic_probe(struct udevice *dev)
- {
- struct rcar_iic_priv *priv = dev_get_priv(dev);
- int ret;
- priv->base = dev_read_addr_ptr(dev);
- ret = clk_get_by_index(dev, 0, &priv->clk);
- if (ret)
- return ret;
- ret = clk_enable(&priv->clk);
- if (ret)
- return ret;
- rcar_iic_finish(dev);
- return rcar_iic_set_speed(dev, 100000);
- }
- static const struct dm_i2c_ops rcar_iic_ops = {
- .xfer = rcar_iic_xfer,
- .probe_chip = rcar_iic_probe_chip,
- .set_bus_speed = rcar_iic_set_speed,
- };
- static const struct udevice_id rcar_iic_ids[] = {
- { .compatible = "renesas,rmobile-iic" },
- { }
- };
- U_BOOT_DRIVER(iic_rcar) = {
- .name = "iic_rcar",
- .id = UCLASS_I2C,
- .of_match = rcar_iic_ids,
- .probe = rcar_iic_probe,
- .priv_auto_alloc_size = sizeof(struct rcar_iic_priv),
- .ops = &rcar_iic_ops,
- };
|