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

login
register
mail settings
Submitter Nobuhiro Iwamatsu
Date Sept. 26, 2013, 11:21 p.m.
Message ID <1380237685-1741-1-git-send-email-nobuhiro.iwamatsu.yj@renesas.com>
Download mbox | patch
Permalink /patch/278294/
State Superseded
Delegated to: Heiko Schocher
Headers show

Comments

Nobuhiro Iwamatsu - Sept. 26, 2013, 11:21 p.m.
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
Heiko Schocher - Sept. 27, 2013, 3:37 a.m.
Hello Nobuhiro,

Am 27.09.2013 01:21, schrieb Nobuhiro Iwamatsu:
> 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

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
Nobuhiro Iwamatsu - Sept. 27, 2013, 4:44 a.m.
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 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
>
> 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

Patch

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)