[U-Boot] [PATCH] i2c: Add support for Renesas rcar

This supports i2c controller for Renesas rcar.
Signed-off-by: Hisashi Nakamura hisashi.nakamura.ak@renesas.com Signed-off-by: Nobuhiro Iwamatsu nobuhiro.iwamatsu.yj@renesas.com --- drivers/i2c/Makefile | 1 + drivers/i2c/rcar_i2c.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 drivers/i2c/rcar_i2c.c
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 37ccbd1..f7cbd62 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -26,6 +26,7 @@ COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o COBJS-$(CONFIG_SH_I2C) += sh_i2c.o COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o +COBJS-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o COBJS-$(CONFIG_SYS_I2C) += i2c_core.o COBJS-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o COBJS-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c new file mode 100644 index 0000000..92f0700 --- /dev/null +++ b/drivers/i2c/rcar_i2c.c @@ -0,0 +1,289 @@ +/* + * drivers/i2c/rcar_i2c.c + * + * Copyright (C) 2013 Renesas Electronics Corporation + * Copyright (C) 2013 Nobuhiro Iwamatsu nobuhiro.iwamatsu.yj@renesas.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <i2c.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct rcar_i2c { + u32 icscr; + u32 icmcr; + u32 icssr; + u32 icmsr; + u32 icsier; + u32 icmier; + u32 icccr; + u32 icsar; + u32 icmar; + u32 icrxdtxd; + u32 icccr2; + u32 icmpr; + u32 ichpr; + u32 iclpr; +}; + +#define MCR_MDBS 0x80 /* non-fifo mode switch */ +#define MCR_FSCL 0x40 /* override SCL pin */ +#define MCR_FSDA 0x20 /* override SDA pin */ +#define MCR_OBPC 0x10 /* override pins */ +#define MCR_MIE 0x08 /* master if enable */ +#define MCR_TSBE 0x04 +#define MCR_FSB 0x02 /* force stop bit */ +#define MCR_ESG 0x01 /* en startbit gen. */ + +#define MSR_MASK 0x7f +#define MSR_MNR 0x40 /* nack received */ +#define MSR_MAL 0x20 /* arbitration lost */ +#define MSR_MST 0x10 /* sent a stop */ +#define MSR_MDE 0x08 +#define MSR_MDT 0x04 +#define MSR_MDR 0x02 +#define MSR_MAT 0x01 /* slave addr xfer done */ + +static const struct rcar_i2c *i2c_dev[CONFIF_SYS_RCAR_I2C_NUM_CONTROLLERS] = { + (struct rcar_i2c *)CONFIG_SYS_RCAR_I2C0_BASE, + (struct rcar_i2c *)CONFIG_SYS_RCAR_I2C1_BASE, + (struct rcar_i2c *)CONFIG_SYS_RCAR_I2C2_BASE, + (struct rcar_i2c *)CONFIG_SYS_RCAR_I2C3_BASE, +}; + +static void rcar_i2c_raw_rw_common(struct rcar_i2c *dev, u8 chip, uint addr) +{ + /* set slave address */ + writel(chip << 1, &dev->icmar); + /* set register address */ + writel(addr, &dev->icrxdtxd); + /* clear status */ + writel(0, &dev->icmsr); + /* start master send */ + writel(MCR_MDBS | MCR_MIE | MCR_ESG, &dev->icmcr); + + while ((readl(&dev->icmsr) & (MSR_MAT | MSR_MDE)) + != (MSR_MAT | MSR_MDE)) + udelay(10); + + /* clear ESG */ + writel(MCR_MDBS | MCR_MIE, &dev->icmcr); + /* start SCLclk */ + writel(~(MSR_MAT | MSR_MDE), &dev->icmsr); + + while (!(readl(&dev->icmsr) & MSR_MDE)) + udelay(10); +} + +static void rcar_i2c_raw_rw_finish(struct rcar_i2c *dev) +{ + while (!(readl(&dev->icmsr) & MSR_MST)) + udelay(10); + + writel(0, &dev->icmcr); +} + +static int +rcar_i2c_raw_write(struct rcar_i2c *dev, u8 chip, uint addr, u8 *val, int size) +{ + rcar_i2c_raw_rw_common(dev, chip, addr); + + /* set send date */ + writel(*val, &dev->icrxdtxd); + /* start SCLclk */ + writel(~MSR_MDE, &dev->icmsr); + + while (!(readl(&dev->icmsr) & MSR_MDE)) + udelay(10); + + /* set stop condition */ + writel(MCR_MDBS | MCR_MIE | MCR_FSB, &dev->icmcr); + /* start SCLclk */ + writel(~MSR_MDE, &dev->icmsr); + + rcar_i2c_raw_rw_finish(dev); + + return 0; +} + +static u8 +rcar_i2c_raw_read(struct rcar_i2c *dev, u8 chip, uint addr) +{ + u8 ret; + + rcar_i2c_raw_rw_common(dev, chip, addr); + + /* set slave address, receive */ + writel((chip << 1) | 1, &dev->icmar); + /* start master receive */ + writel(MCR_MDBS | MCR_MIE | MCR_ESG, &dev->icmcr); + + while ((readl(&dev->icmsr) & (MSR_MAT | MSR_MDE)) + != (MSR_MAT | MSR_MDE)) + udelay(10); + + /* clear ESG */ + writel(MCR_MDBS | MCR_MIE, &dev->icmcr); + /* prepare stop condition */ + writel(MCR_MDBS | MCR_MIE | MCR_FSB, &dev->icmcr); + /* start SCLclk */ + writel(~(MSR_MAT | MSR_MDR), &dev->icmsr); + + while (!(readl(&dev->icmsr) & MSR_MDR)) + udelay(10); + + /* get receive data */ + ret = (u8)readl(&dev->icrxdtxd); + /* start SCLclk */ + writel(~MSR_MDR, &dev->icmsr); + + rcar_i2c_raw_rw_finish(dev); + + return ret; +} + + +/* + * SCL = iicck / (20 + SCGD * 8 + F[(ticf + tr + intd) * iicck]) + * iicck : I2C internal clock < 20 MHz + * ticf : I2C SCL falling time: 35 ns + * tr : I2C SCL rising time: 200 ns + * intd : LSI internal delay: I2C0: 50 ns I2C1-3: 5 + * F[n] : n rounded up to an integer + */ +static u32 rcar_clock_gen(int i2c_no, u32 bus_speed) +{ + u32 iicck, f, scl, scgd; + u32 intd = 5; + + int bit = 0, cdf_width = 3; + for (bit = 0; bit < (1 << cdf_width); bit++) { + iicck = CONFIG_HP_CLK_FREQ / (1 + bit); + if (iicck < 20000000) + break; + } + + if (bit > (1 << cdf_width)) { + puts("rcar-i2c: Can not get CDF\n"); + return 0; + } + + if (i2c_no == 0) + intd = 50; + + f = (35 + 200 + intd) * (iicck / 1000000000); + + for (scgd = 0; scgd < 0x40; scgd++) { + scl = iicck / (20 + (scgd * 8) + f); + if (scl <= bus_speed) + break; + } + + if (scgd > 0x40) { + puts("rcar-i2c: Can not get SDGB\n"); + return 0; + } + + debug("%s: scl: %d\n", __func__, scl); + debug("%s: bit %x\n", __func__, bit); + debug("%s: scgd %x\n", __func__, scgd); + debug("%s: iccr %x\n", __func__, (scgd << (cdf_width) | bit)); + + return scgd << (cdf_width) | bit; +} + +static void +rcar_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd) +{ + struct rcar_i2c *dev = (struct rcar_i2c *)i2c_dev[adap->hwadapnr]; + u32 icccr = 0; + + /* No i2c support prior to relocation */ + if (!(gd->flags & GD_FLG_RELOC)) + return; + + /* + * reset slave mode. + * slave mode is not used on this driver + */ + writel(0, &dev->icsier); + writel(0, &dev->icsar); + writel(0, &dev->icscr); + writel(0, &dev->icssr); + + /* reset master mode */ + writel(0, &dev->icmier); + writel(0, &dev->icmcr); + writel(0, &dev->icmsr); + writel(0, &dev->icmar); + + icccr = rcar_clock_gen(adap->hwadapnr, adap->speed); + if (icccr == 0) + puts("I2C: Init failed\n"); + else + writel(icccr, &dev->icccr); +} + +static int rcar_i2c_read(struct i2c_adapter *adap, uint8_t chip, + uint addr, int alen, u8 *data, int len) +{ + struct rcar_i2c *dev = (struct rcar_i2c *)i2c_dev[adap->hwadapnr]; + int i; + + for (i = 0; i < len; i++) + data[i] = rcar_i2c_raw_read(dev, chip, addr + i); + + return 0; +} + +static int rcar_i2c_write(struct i2c_adapter *adap, uint8_t chip, uint addr, + int alen, u8 *data, int len) +{ + struct rcar_i2c *dev = (struct rcar_i2c *)i2c_dev[adap->hwadapnr]; + return rcar_i2c_raw_write(dev, chip, addr, data, len); +} + +static int +rcar_i2c_probe(struct i2c_adapter *adap, u8 dev) +{ + return rcar_i2c_read(adap, dev, 0, 0, NULL, 0); +} + +static unsigned int rcar_i2c_set_bus_speed(struct i2c_adapter *adap, + unsigned int speed) +{ + struct rcar_i2c *dev = (struct rcar_i2c *)i2c_dev[adap->hwadapnr]; + u32 icccr; + int ret = 0; + + rcar_i2c_raw_rw_finish(dev); + + icccr = rcar_clock_gen(adap->hwadapnr, speed); + if (icccr == 0) { + puts("I2C: Init failed\n"); + ret = -1; + } else { + writel(icccr, &dev->icccr); + } + return ret; +} + +/* + * Register RCAR i2c adapters + */ +U_BOOT_I2C_ADAP_COMPLETE(rcar_0, rcar_i2c_init, rcar_i2c_probe, rcar_i2c_read, + rcar_i2c_write, rcar_i2c_set_bus_speed, + CONFIG_SYS_RCAR_I2C0_SPEED, 0, 0) +U_BOOT_I2C_ADAP_COMPLETE(rcar_1, rcar_i2c_init, rcar_i2c_probe, rcar_i2c_read, + rcar_i2c_write, rcar_i2c_set_bus_speed, + CONFIG_SYS_RCAR_I2C1_SPEED, 0, 1) +U_BOOT_I2C_ADAP_COMPLETE(rcar_2, rcar_i2c_init, rcar_i2c_probe, rcar_i2c_read, + rcar_i2c_write, rcar_i2c_set_bus_speed, + CONFIG_SYS_RCAR_I2C2_SPEED, 0, 2) +U_BOOT_I2C_ADAP_COMPLETE(rcar_3, rcar_i2c_init, rcar_i2c_probe, rcar_i2c_read, + rcar_i2c_write, rcar_i2c_set_bus_speed, + CONFIG_SYS_RCAR_I2C3_SPEED, 0, 3)

Hello Nobuhiro,
Am 27.09.2013 01:21, schrieb Nobuhiro Iwamatsu:
This supports i2c controller for Renesas rcar.
Signed-off-by: Hisashi Nakamurahisashi.nakamura.ak@renesas.com Signed-off-by: Nobuhiro Iwamatsunobuhiro.iwamatsu.yj@renesas.com
drivers/i2c/Makefile | 1 + drivers/i2c/rcar_i2c.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 drivers/i2c/rcar_i2c.c
Thanks! Patch looks good to me, just some nitpicking comments:
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 37ccbd1..f7cbd62 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -26,6 +26,7 @@ COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o COBJS-$(CONFIG_SH_I2C) += sh_i2c.o COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o +COBJS-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o
Please keep this list sorted ...
COBJS-$(CONFIG_SYS_I2C) += i2c_core.o COBJS-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o COBJS-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c new file mode 100644 index 0000000..92f0700 --- /dev/null +++ b/drivers/i2c/rcar_i2c.c @@ -0,0 +1,289 @@
[...]
+static u8 +rcar_i2c_raw_read(struct rcar_i2c *dev, u8 chip, uint addr) +{
- u8 ret;
- rcar_i2c_raw_rw_common(dev, chip, addr);
- /* set slave address, receive */
- writel((chip<< 1) | 1,&dev->icmar);
^ ^ space please, please fix globally
Hmm.. checkpatch says for your patch:
total: 0 errors, 0 warnings, 0 checks, 296 lines checked
NOTE: Ignored message types: COMPLEX_MACRO CONSIDER_KSTRTO MINMAX MULTISTATEMENT_MACRO_USE_DO_WHILE NETWORKING_BLOCK_COMMENT_STYLE USLEEP_RANGE
mbox has no obvious style problems and is ready for submission.
Seems checpatch did not check this ...
- /* start master receive */
- writel(MCR_MDBS | MCR_MIE | MCR_ESG,&dev->icmcr);
- while ((readl(&dev->icmsr)& (MSR_MAT | MSR_MDE))
!= (MSR_MAT | MSR_MDE))
udelay(10);
- /* clear ESG */
- writel(MCR_MDBS | MCR_MIE,&dev->icmcr);
- /* prepare stop condition */
- writel(MCR_MDBS | MCR_MIE | MCR_FSB,&dev->icmcr);
- /* start SCLclk */
- writel(~(MSR_MAT | MSR_MDR),&dev->icmsr);
- while (!(readl(&dev->icmsr)& MSR_MDR))
udelay(10);
- /* get receive data */
- ret = (u8)readl(&dev->icrxdtxd);
- /* start SCLclk */
- writel(~MSR_MDR,&dev->icmsr);
- rcar_i2c_raw_rw_finish(dev);
- return ret;
+}
Please only one empty line.
[...]
bye, Heiko

Hi, Heiko.
Thank you for your review.
(2013/09/27 12:37), Heiko Schocher wrote:
Hello Nobuhiro,
Am 27.09.2013 01:21, schrieb Nobuhiro Iwamatsu:
This supports i2c controller for Renesas rcar.
Signed-off-by: Hisashi Nakamurahisashi.nakamura.ak@renesas.com Signed-off-by: Nobuhiro Iwamatsunobuhiro.iwamatsu.yj@renesas.com
drivers/i2c/Makefile | 1 + drivers/i2c/rcar_i2c.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 drivers/i2c/rcar_i2c.c
Thanks! Patch looks good to me, just some nitpicking comments:
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 37ccbd1..f7cbd62 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -26,6 +26,7 @@ COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o COBJS-$(CONFIG_SH_I2C) += sh_i2c.o COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o +COBJS-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o
Please keep this list sorted ...
OK, I will fix.
COBJS-$(CONFIG_SYS_I2C) += i2c_core.o COBJS-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o COBJS-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c new file mode 100644 index 0000000..92f0700 --- /dev/null +++ b/drivers/i2c/rcar_i2c.c @@ -0,0 +1,289 @@
[...]
+static u8 +rcar_i2c_raw_read(struct rcar_i2c *dev, u8 chip, uint addr) +{
- u8 ret;
- rcar_i2c_raw_rw_common(dev, chip, addr);
- /* set slave address, receive */
- writel((chip<< 1) | 1,&dev->icmar);
^ ^ space please, please fix globally
Hmm.. checkpatch says for your patch:
total: 0 errors, 0 warnings, 0 checks, 296 lines checked
NOTE: Ignored message types: COMPLEX_MACRO CONSIDER_KSTRTO MINMAX MULTISTATEMENT_MACRO_USE_DO_WHILE NETWORKING_BLOCK_COMMENT_STYLE USLEEP_RANGE
mbox has no obvious style problems and is ready for submission.
Seems checpatch did not check this ...
this is my mistake. I will fix and recheck.
- /* start master receive */
- writel(MCR_MDBS | MCR_MIE | MCR_ESG,&dev->icmcr);
- while ((readl(&dev->icmsr)& (MSR_MAT | MSR_MDE))
- != (MSR_MAT | MSR_MDE))
- udelay(10);
- /* clear ESG */
- writel(MCR_MDBS | MCR_MIE,&dev->icmcr);
- /* prepare stop condition */
- writel(MCR_MDBS | MCR_MIE | MCR_FSB,&dev->icmcr);
- /* start SCLclk */
- writel(~(MSR_MAT | MSR_MDR),&dev->icmsr);
- while (!(readl(&dev->icmsr)& MSR_MDR))
- udelay(10);
- /* get receive data */
- ret = (u8)readl(&dev->icrxdtxd);
- /* start SCLclk */
- writel(~MSR_MDR,&dev->icmsr);
- rcar_i2c_raw_rw_finish(dev);
- return ret;
+}
Please only one empty line.
[...]
OK, I will remove this line.
bye, Heiko
Best regards, Nobuhiro
participants (2)
-
Heiko Schocher
-
Nobuhiro Iwamatsu