[U-Boot] [PATCH v5 0/6] I2C fixes for the R-Car H3

This series is meant to be applied on top of the "i2c: rcar_i2c: Add Gen3 SoC support" patch.
v5 is just an edit over v4; a change ended up in the wrong commit in that version.
Ismael Luceno (6): i2c: rcar_i2c: Setup SCL/SDA delay at rcar_i2c_set_speed i2c: rcar_i2c: Add comments about registers & values i2c: rcar_i2c: Fix sending of slave addresses i2c: rcar_i2c: Don't mask errors with EREMOTEIO at rcar_i2c_xfer i2c: rcar_i2c: Set the slave address from rcar_i2c_xfer i2c: rcar_i2c: Move FSDA check to rcar_i2c_recover
drivers/i2c/rcar_i2c.c | 87 +++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 40 deletions(-)
base-commit: f08023c07d826fbc8e62fdd3367961b2f0b06844 prerequisite-patch-id: 9e5b0458bc15640eb483ccad91dbe85150f9f7be

Setting up the delay only needs to be done once; move it to rcar_i2c_set_speed so it's done at initialization time.
Signed-off-by: Ismael Luceno ismael.luceno@silicon-gears.com Reviewed-by: Marek Vasut marek.vasut+renesas@gmail.com Reviewed-by: Heiko Schocher hs@denx.de ---
Notes: Changes since v2: - Improved commit message - Style fixes
drivers/i2c/rcar_i2c.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c index 10b0f8bad4..a57f72a228 100644 --- a/drivers/i2c/rcar_i2c.c +++ b/drivers/i2c/rcar_i2c.c @@ -116,9 +116,7 @@ static int rcar_i2c_set_addr(struct udevice *dev, u8 chip, u8 read) writel(0, priv->base + RCAR_I2C_ICMSR); writel(priv->icccr, priv->base + RCAR_I2C_ICCCR);
- if (priv->type == RCAR_I2C_TYPE_GEN3) - writel(RCAR_I2C_ICFBSCR_TCYC17, priv->base + RCAR_I2C_ICFBSCR); - + /* Wait for the bus */ ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_FSDA, false, 2, true); if (ret) { @@ -304,6 +302,11 @@ scgd_find: priv->icccr = (scgd << RCAR_I2C_ICCCR_SCGD_OFF) | cdf; writel(priv->icccr, priv->base + RCAR_I2C_ICCCR);
+ if (priv->type == RCAR_I2C_TYPE_GEN3) { + /* Set SCL/SDA delay */ + writel(RCAR_I2C_ICFBSCR_TCYC17, priv->base + RCAR_I2C_ICFBSCR); + } + return 0; }

Document the meaning of macros related to registers and values to be written to them.
Signed-off-by: Ismael Luceno ismael.luceno@silicon-gears.com Reviewed-by: Marek Vasut marek.vasut+renesas@gmail.com Reviewed-by: Heiko Schocher hs@denx.de ---
Notes: Changes since v2: - Fixed style of comments
Changes since v1: - Rebased on top of patch 1050650 ("i2c: rcar_i2c: Add Gen3 SoC support")
drivers/i2c/rcar_i2c.c | 47 +++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 21 deletions(-)
diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c index a57f72a228..d7b27204cb 100644 --- a/drivers/i2c/rcar_i2c.c +++ b/drivers/i2c/rcar_i2c.c @@ -18,35 +18,40 @@ #include <asm/io.h> #include <wait_bit.h>
-#define RCAR_I2C_ICSCR 0x00 -#define RCAR_I2C_ICMCR 0x04 -#define RCAR_I2C_ICMCR_MDBS BIT(7) -#define RCAR_I2C_ICMCR_FSCL BIT(6) -#define RCAR_I2C_ICMCR_FSDA BIT(5) -#define RCAR_I2C_ICMCR_OBPC BIT(4) -#define RCAR_I2C_ICMCR_MIE BIT(3) +#define RCAR_I2C_ICSCR 0x00 /* slave ctrl */ +#define RCAR_I2C_ICMCR 0x04 /* master ctrl */ +#define RCAR_I2C_ICMCR_MDBS BIT(7) /* non-fifo mode switch */ +#define RCAR_I2C_ICMCR_FSCL BIT(6) /* override SCL pin */ +#define RCAR_I2C_ICMCR_FSDA BIT(5) /* override SDA pin */ +#define RCAR_I2C_ICMCR_OBPC BIT(4) /* override pins */ +#define RCAR_I2C_ICMCR_MIE BIT(3) /* master if enable */ #define RCAR_I2C_ICMCR_TSBE BIT(2) -#define RCAR_I2C_ICMCR_FSB BIT(1) -#define RCAR_I2C_ICMCR_ESG BIT(0) -#define RCAR_I2C_ICSSR 0x08 -#define RCAR_I2C_ICMSR 0x0c +#define RCAR_I2C_ICMCR_FSB BIT(1) /* force stop bit */ +#define RCAR_I2C_ICMCR_ESG BIT(0) /* enable start bit gen */ +#define RCAR_I2C_ICSSR 0x08 /* slave status */ +#define RCAR_I2C_ICMSR 0x0c /* master status */ #define RCAR_I2C_ICMSR_MASK 0x7f -#define RCAR_I2C_ICMSR_MNR BIT(6) -#define RCAR_I2C_ICMSR_MAL BIT(5) -#define RCAR_I2C_ICMSR_MST BIT(4) +#define RCAR_I2C_ICMSR_MNR BIT(6) /* Nack */ +#define RCAR_I2C_ICMSR_MAL BIT(5) /* Arbitration lost */ +#define RCAR_I2C_ICMSR_MST BIT(4) /* Stop */ #define RCAR_I2C_ICMSR_MDE BIT(3) #define RCAR_I2C_ICMSR_MDT BIT(2) #define RCAR_I2C_ICMSR_MDR BIT(1) #define RCAR_I2C_ICMSR_MAT BIT(0) -#define RCAR_I2C_ICSIER 0x10 -#define RCAR_I2C_ICMIER 0x14 -#define RCAR_I2C_ICCCR 0x18 +#define RCAR_I2C_ICSIER 0x10 /* slave irq enable */ +#define RCAR_I2C_ICMIER 0x14 /* master irq enable */ +#define RCAR_I2C_ICCCR 0x18 /* clock dividers */ #define RCAR_I2C_ICCCR_SCGD_OFF 3 -#define RCAR_I2C_ICSAR 0x1c -#define RCAR_I2C_ICMAR 0x20 -#define RCAR_I2C_ICRXD_ICTXD 0x24 +#define RCAR_I2C_ICSAR 0x1c /* slave address */ +#define RCAR_I2C_ICMAR 0x20 /* master address */ +#define RCAR_I2C_ICRXD_ICTXD 0x24 /* data port */ +/* + * First Bit Setup Cycle (Gen3). + * Defines 1st bit delay between SDA and SCL. + */ #define RCAR_I2C_ICFBSCR 0x38 -#define RCAR_I2C_ICFBSCR_TCYC17 0x0f +#define RCAR_I2C_ICFBSCR_TCYC17 0x0f /* 17*Tcyc */ +
enum rcar_i2c_type { RCAR_I2C_TYPE_GEN2,

Do the reset before clearing the MSR, otherwise it may result in a read or write operation instead if the start condition is repeated.
Signed-off-by: Ismael Luceno ismael.luceno@silicon-gears.com Reviewed-by: Marek Vasut marek.vasut+renesas@gmail.com Reviewed-by: Heiko Schocher hs@denx.de ---
Notes: Changes since v1: - Rebased on top of patch 1050650 ("i2c: rcar_i2c: Add Gen3 SoC support")
drivers/i2c/rcar_i2c.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c index d7b27204cb..a88fbcf34f 100644 --- a/drivers/i2c/rcar_i2c.c +++ b/drivers/i2c/rcar_i2c.c @@ -134,9 +134,11 @@ static int rcar_i2c_set_addr(struct udevice *dev, u8 chip, u8 read) }
writel((chip << 1) | read, priv->base + RCAR_I2C_ICMAR); - writel(0, priv->base + RCAR_I2C_ICMSR); + /* Reset */ writel(RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE | RCAR_I2C_ICMCR_ESG, priv->base + RCAR_I2C_ICMCR); + /* Clear Status */ + writel(0, priv->base + RCAR_I2C_ICMSR);
ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR, mask, true, 100, true);

Fix rcar_i2c_xfer return value, previously it was always returning -EREMOTEIO when dealing with errors from calls to the read/write functions.
Signed-off-by: Ismael Luceno ismael.luceno@silicon-gears.com Reviewed-by: Marek Vasut marek.vasut+renesas@gmail.com Reviewed-by: Heiko Schocher hs@denx.de ---
Notes: Changes since v2: - Fixed commit message
Changes since v1: - Rebased on top of patch 1050650 ("i2c: rcar_i2c: Add Gen3 SoC support")
drivers/i2c/rcar_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c index a88fbcf34f..9223eaecbf 100644 --- a/drivers/i2c/rcar_i2c.c +++ b/drivers/i2c/rcar_i2c.c @@ -221,7 +221,7 @@ static int rcar_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) ret = rcar_i2c_write_common(dev, msg);
if (ret) - return -EREMOTEIO; + return ret; }
return ret;

It needs to be done for both reads and writes, so do it at rcar_i2c_xfer to avoid duplication.
Signed-off-by: Ismael Luceno ismael.luceno@silicon-gears.com Reviewed-by: Marek Vasut marek.vasut+renesas@gmail.com Reviewed-by: Heiko Schocher hs@denx.de ---
Notes: Changes since v2: - Fixed commit message
Changes since v1: - Rebased on top of patch 1050650 ("i2c: rcar_i2c: Add Gen3 SoC support") - Fixed masking of return value from rcar_i2c_set_addr
drivers/i2c/rcar_i2c.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c index 9223eaecbf..78ef8acacc 100644 --- a/drivers/i2c/rcar_i2c.c +++ b/drivers/i2c/rcar_i2c.c @@ -158,10 +158,6 @@ static int rcar_i2c_read_common(struct udevice *dev, struct i2c_msg *msg) u32 icmcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE; int i, ret = -EREMOTEIO;
- ret = rcar_i2c_set_addr(dev, msg->addr, 1); - if (ret) - return ret; - for (i = 0; i < msg->len; i++) { if (msg->len - 1 == i) icmcr |= RCAR_I2C_ICMCR_FSB; @@ -188,10 +184,6 @@ static int rcar_i2c_write_common(struct udevice *dev, struct i2c_msg *msg) u32 icmcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE; int i, ret = -EREMOTEIO;
- ret = rcar_i2c_set_addr(dev, msg->addr, 0); - if (ret) - return ret; - for (i = 0; i < msg->len; i++) { writel(msg->buf[i], priv->base + RCAR_I2C_ICRXD_ICTXD); writel(icmcr, priv->base + RCAR_I2C_ICMCR); @@ -215,6 +207,10 @@ static int rcar_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) int ret;
for (; nmsgs > 0; nmsgs--, msg++) { + ret = rcar_i2c_set_addr(dev, msg->addr, 1); + if (ret) + return ret; + if (msg->flags & I2C_M_RD) ret = rcar_i2c_read_common(dev, msg); else @@ -224,7 +220,7 @@ static int rcar_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) return ret; }
- return ret; + return 0; }
static int rcar_i2c_probe_chip(struct udevice *dev, uint addr, uint flags)

Cosmetic change. Any call to the recover function would need to do the same check afterwards, so it's sensible to make it part of the function.
Signed-off-by: Ismael Luceno ismael.luceno@silicon-gears.com ---
Notes: Changes since v3: - Removed unused variable val @ rcar_i2c_set_addr
Changes since v2: - Fixed variable names - Fixed return value to be standard
Changes since v1: - Rebased on top of patch 1050650 ("i2c: rcar_i2c: Add Gen3 SoC support") - Explained the change - Replaced C99-style variable declaration
drivers/i2c/rcar_i2c.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c index 78ef8acacc..2ebae349ed 100644 --- a/drivers/i2c/rcar_i2c.c +++ b/drivers/i2c/rcar_i2c.c @@ -81,12 +81,13 @@ static int rcar_i2c_finish(struct udevice *dev) return ret; }
-static void rcar_i2c_recover(struct udevice *dev) +static int rcar_i2c_recover(struct udevice *dev) { struct rcar_i2c_priv *priv = dev_get_priv(dev); u32 mcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_OBPC; u32 mcra = mcr | RCAR_I2C_ICMCR_FSDA; int i; + u32 mstat;
/* Send 9 SCL pulses */ for (i = 0; i < 9; i++) { @@ -106,6 +107,9 @@ static void rcar_i2c_recover(struct udevice *dev) udelay(5); writel(mcra | RCAR_I2C_ICMCR_FSCL, priv->base + RCAR_I2C_ICMCR); udelay(5); + + mstat = readl(priv->base + RCAR_I2C_ICMSR); + return mstat & RCAR_I2C_ICMCR_FSDA ? -EBUSY : 0; }
static int rcar_i2c_set_addr(struct udevice *dev, u8 chip, u8 read) @@ -113,7 +117,6 @@ static int rcar_i2c_set_addr(struct udevice *dev, u8 chip, u8 read) struct rcar_i2c_priv *priv = dev_get_priv(dev); u32 mask = RCAR_I2C_ICMSR_MAT | (read ? RCAR_I2C_ICMSR_MDR : RCAR_I2C_ICMSR_MDE); - u32 val; int ret;
writel(0, priv->base + RCAR_I2C_ICMIER); @@ -125,9 +128,7 @@ static int rcar_i2c_set_addr(struct udevice *dev, u8 chip, u8 read) ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_FSDA, false, 2, true); if (ret) { - rcar_i2c_recover(dev); - val = readl(priv->base + RCAR_I2C_ICMSR); - if (val & RCAR_I2C_ICMCR_FSDA) { + if (rcar_i2c_recover(dev)) { dev_err(dev, "Bus busy, aborting\n"); return ret; }
participants (1)
-
Ismael Luceno Cortes