From eb54682e91a0a3f9ca8629d67c5195ae54cfb1e9 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 7 Mar 2019 03:41:08 +0100 Subject: [PATCH 01/10] i2c: rcar_iic: Read ICSR only once Read ICSR only once to avoid missing interrupts. This happens on R8A7791 Porter during reset, when reading the PMIC register 0x13, which may fail sometimes because of the missed DTE interrupt. Signed-off-by: Marek Vasut Cc: Heiko Schocher Cc: Nobuhiro Iwamatsu Reviewed-by: Heiko Schocher --- drivers/i2c/rcar_iic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/rcar_iic.c b/drivers/i2c/rcar_iic.c index e91fc86c1a..9d45f547d1 100644 --- a/drivers/i2c/rcar_iic.c +++ b/drivers/i2c/rcar_iic.c @@ -58,12 +58,14 @@ static void sh_irq_dte(struct udevice *dev) static int sh_irq_dte_with_tack(struct udevice *dev) { struct rcar_iic_priv *priv = dev_get_priv(dev); + u8 icsr; int i; for (i = 0; i < IRQ_WAIT; i++) { - if (RCAR_IC_DTE & readb(priv->base + RCAR_IIC_ICSR)) + icsr = readb(priv->base + RCAR_IIC_ICSR); + if (RCAR_IC_DTE & icsr) break; - if (RCAR_IC_TACK & readb(priv->base + RCAR_IIC_ICSR)) + if (RCAR_IC_TACK & icsr) return -ETIMEDOUT; udelay(10); } From da53b0543dc3b85a79874e17faf25fccefef24d2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 2 Mar 2019 17:17:11 +0100 Subject: [PATCH 02/10] i2c: rcar_i2c: Add Gen3 SoC support Add support for R-Car Gen3 SoCs into the driver, which encompases the Gen3 SoC extra timing register handling and 64bit build fixes. Signed-off-by: Marek Vasut Cc: Heiko Schocher Reviewed-by: Heiko Schocher --- drivers/i2c/rcar_i2c.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c index 8d87c73713..10b0f8bad4 100644 --- a/drivers/i2c/rcar_i2c.c +++ b/drivers/i2c/rcar_i2c.c @@ -45,12 +45,20 @@ #define RCAR_I2C_ICSAR 0x1c #define RCAR_I2C_ICMAR 0x20 #define RCAR_I2C_ICRXD_ICTXD 0x24 +#define RCAR_I2C_ICFBSCR 0x38 +#define RCAR_I2C_ICFBSCR_TCYC17 0x0f + +enum rcar_i2c_type { + RCAR_I2C_TYPE_GEN2, + RCAR_I2C_TYPE_GEN3, +}; struct rcar_i2c_priv { void __iomem *base; struct clk clk; u32 intdelay; u32 icccr; + enum rcar_i2c_type type; }; static int rcar_i2c_finish(struct udevice *dev) @@ -108,6 +116,9 @@ 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); + ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_FSDA, false, 2, true); if (ret) { @@ -151,7 +162,7 @@ static int rcar_i2c_read_common(struct udevice *dev, struct i2c_msg *msg) icmcr |= RCAR_I2C_ICMCR_FSB; writel(icmcr, priv->base + RCAR_I2C_ICMCR); - writel(~RCAR_I2C_ICMSR_MDR, priv->base + RCAR_I2C_ICMSR); + writel((u32)~RCAR_I2C_ICMSR_MDR, priv->base + RCAR_I2C_ICMSR); ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR, RCAR_I2C_ICMSR_MDR, true, 100, true); @@ -161,7 +172,7 @@ static int rcar_i2c_read_common(struct udevice *dev, struct i2c_msg *msg) msg->buf[i] = readl(priv->base + RCAR_I2C_ICRXD_ICTXD) & 0xff; } - writel(~RCAR_I2C_ICMSR_MDR, priv->base + RCAR_I2C_ICMSR); + writel((u32)~RCAR_I2C_ICMSR_MDR, priv->base + RCAR_I2C_ICMSR); return rcar_i2c_finish(dev); } @@ -179,7 +190,7 @@ static int rcar_i2c_write_common(struct udevice *dev, struct i2c_msg *msg) for (i = 0; i < msg->len; i++) { writel(msg->buf[i], priv->base + RCAR_I2C_ICRXD_ICTXD); writel(icmcr, priv->base + RCAR_I2C_ICMCR); - writel(~RCAR_I2C_ICMSR_MDE, priv->base + RCAR_I2C_ICMSR); + writel((u32)~RCAR_I2C_ICMSR_MDE, priv->base + RCAR_I2C_ICMSR); ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR, RCAR_I2C_ICMSR_MDE, true, 100, true); @@ -187,7 +198,7 @@ static int rcar_i2c_write_common(struct udevice *dev, struct i2c_msg *msg) return ret; } - writel(~RCAR_I2C_ICMSR_MDE, priv->base + RCAR_I2C_ICMSR); + writel((u32)~RCAR_I2C_ICMSR_MDE, priv->base + RCAR_I2C_ICMSR); icmcr |= RCAR_I2C_ICMCR_FSB; writel(icmcr, priv->base + RCAR_I2C_ICMCR); @@ -304,6 +315,7 @@ static int rcar_i2c_probe(struct udevice *dev) priv->base = dev_read_addr_ptr(dev); priv->intdelay = dev_read_u32_default(dev, "i2c-scl-internal-delay-ns", 5); + priv->type = dev_get_driver_data(dev); ret = clk_get_by_index(dev, 0, &priv->clk); if (ret) @@ -339,7 +351,8 @@ static const struct dm_i2c_ops rcar_i2c_ops = { }; static const struct udevice_id rcar_i2c_ids[] = { - { .compatible = "renesas,rcar-gen2-i2c" }, + { .compatible = "renesas,rcar-gen2-i2c", .data = RCAR_I2C_TYPE_GEN2 }, + { .compatible = "renesas,rcar-gen3-i2c", .data = RCAR_I2C_TYPE_GEN3 }, { } }; From 006265d063789ffbf58c51213f1a27462875931c Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 7 Mar 2019 11:52:48 +0100 Subject: [PATCH 03/10] i2c: i2c_cdns: Fix clearing of all interrupts The arbitration lost interrupt was not getting cleared while clearing interrupts. This patch fixes this by adding arbitration lost interrupt as well during clear. This patch also removes hardcoded value and defined a macro for it. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek Reviewed-by: Heiko Schocher --- drivers/i2c/i2c-cdns.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index 4330d28c2b..b391c0ba49 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -64,6 +64,16 @@ struct cdns_i2c_regs { #define CDNS_I2C_INTERRUPT_RXUNF 0x00000080 #define CDNS_I2C_INTERRUPT_ARBLOST 0x00000200 +#define CDNS_I2C_INTERRUPTS_MASK (CDNS_I2C_INTERRUPT_COMP | \ + CDNS_I2C_INTERRUPT_DATA | \ + CDNS_I2C_INTERRUPT_NACK | \ + CDNS_I2C_INTERRUPT_TO | \ + CDNS_I2C_INTERRUPT_SLVRDY | \ + CDNS_I2C_INTERRUPT_RXOVF | \ + CDNS_I2C_INTERRUPT_TXOVF | \ + CDNS_I2C_INTERRUPT_RXUNF | \ + CDNS_I2C_INTERRUPT_ARBLOST) + #define CDNS_I2C_FIFO_DEPTH 16 #define CDNS_I2C_TRANSFER_SIZE_MAX 255 /* Controller transfer limit */ #define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_TRANSFER_SIZE_MAX - 3) @@ -241,7 +251,7 @@ static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data, setbits_le32(®s->control, CDNS_I2C_CONTROL_HOLD); /* Clear the interrupts in status register */ - writel(0xFF, ®s->interrupt_status); + writel(CDNS_I2C_INTERRUPTS_MASK, ®s->interrupt_status); writel(addr, ®s->address); From bc00512438e8df139477908b79663d81df594261 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 7 Mar 2019 11:52:49 +0100 Subject: [PATCH 04/10] i2c: i2c_cdns: Add support for handling arbitration lost This patch adds support for handling arbitration lost in case of multi master mode. When an arbitration lost is detected, it retries for 10 times before failing. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek Reviewed-by: Heiko Schocher --- drivers/i2c/i2c-cdns.c | 66 +++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index b391c0ba49..1af94d1761 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -80,6 +80,8 @@ struct cdns_i2c_regs { #define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) +#define CDNS_I2C_ARB_LOST_MAX_RETRIES 10 + #ifdef DEBUG static void cdns_i2c_debug_status(struct cdns_i2c_regs *cdns_i2c) { @@ -234,11 +236,17 @@ static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) return 0; } +static inline u32 is_arbitration_lost(struct cdns_i2c_regs *regs) +{ + return (readl(®s->interrupt_status) & CDNS_I2C_INTERRUPT_ARBLOST); +} + static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data, u32 len) { u8 *cur_data = data; struct cdns_i2c_regs *regs = i2c_bus->regs; + u32 ret; /* Set the controller in Master transmit mode and clear FIFO */ setbits_le32(®s->control, CDNS_I2C_CONTROL_CLR_FIFO); @@ -255,25 +263,38 @@ static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data, writel(addr, ®s->address); - while (len--) { + while (len-- && !is_arbitration_lost(regs)) { writel(*(cur_data++), ®s->data); if (readl(®s->transfer_size) == CDNS_I2C_FIFO_DEPTH) { - if (!cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP)) { - /* Release the bus */ - clrbits_le32(®s->control, - CDNS_I2C_CONTROL_HOLD); - return -ETIMEDOUT; - } + ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP | + CDNS_I2C_INTERRUPT_ARBLOST); + if (ret & CDNS_I2C_INTERRUPT_ARBLOST) + return -EAGAIN; + if (ret & CDNS_I2C_INTERRUPT_COMP) + continue; + /* Release the bus */ + clrbits_le32(®s->control, + CDNS_I2C_CONTROL_HOLD); + return -ETIMEDOUT; } } + if (len && is_arbitration_lost(regs)) + return -EAGAIN; + /* All done... release the bus */ if (!i2c_bus->hold_flag) clrbits_le32(®s->control, CDNS_I2C_CONTROL_HOLD); /* Wait for the address and data to be sent */ - if (!cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP)) + ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP | + CDNS_I2C_INTERRUPT_ARBLOST); + if (!(ret & (CDNS_I2C_INTERRUPT_ARBLOST | + CDNS_I2C_INTERRUPT_COMP))) return -ETIMEDOUT; + if (ret & CDNS_I2C_INTERRUPT_ARBLOST) + return -EAGAIN; + return 0; } @@ -289,6 +310,7 @@ static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data, struct cdns_i2c_regs *regs = i2c_bus->regs; int curr_recv_count; int updatetx, hold_quirk; + u32 ret; /* Check the hardware can handle the requested bytes */ if ((recv_count < 0)) @@ -317,7 +339,7 @@ static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data, hold_quirk = (i2c_bus->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx; - while (recv_count) { + while (recv_count && !is_arbitration_lost(regs)) { while (readl(®s->status) & CDNS_I2C_STATUS_RXDV) { if (recv_count < CDNS_I2C_FIFO_DEPTH && !i2c_bus->hold_flag) { @@ -366,8 +388,13 @@ static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data, } /* Wait for the address and data to be sent */ - if (!cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP)) + ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP | + CDNS_I2C_INTERRUPT_ARBLOST); + if (!(ret & (CDNS_I2C_INTERRUPT_ARBLOST | + CDNS_I2C_INTERRUPT_COMP))) return -ETIMEDOUT; + if (ret & CDNS_I2C_INTERRUPT_ARBLOST) + return -EAGAIN; return 0; } @@ -376,8 +403,11 @@ static int cdns_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) { struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev); - int ret, count; + int ret = 0; + int count; bool hold_quirk; + struct i2c_msg *message = msg; + int num_msgs = nmsgs; hold_quirk = !!(i2c_bus->quirks & CDNS_I2C_BROKEN_HOLD_BIT); @@ -403,7 +433,8 @@ static int cdns_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, } debug("i2c_xfer: %d messages\n", nmsgs); - for (; nmsgs > 0; nmsgs--, msg++) { + for (u8 retry = 0; retry < CDNS_I2C_ARB_LOST_MAX_RETRIES && + nmsgs > 0; nmsgs--, msg++) { debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); if (msg->flags & I2C_M_RD) { ret = cdns_i2c_read_data(i2c_bus, msg->addr, msg->buf, @@ -412,13 +443,22 @@ static int cdns_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, ret = cdns_i2c_write_data(i2c_bus, msg->addr, msg->buf, msg->len); } + if (ret == -EAGAIN) { + msg = message; + nmsgs = num_msgs; + retry++; + printf("%s,arbitration lost, retrying:%d\n", __func__, + retry); + continue; + } + if (ret) { debug("i2c_write: error sending\n"); return -EREMOTEIO; } } - return 0; + return ret; } static int cdns_i2c_ofdata_to_platdata(struct udevice *dev) From 4fcff08c4b4fe4e8e0e000fd2c2d97b8dec68d35 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Cortes Date: Thu, 7 Mar 2019 18:00:49 +0000 Subject: [PATCH 05/10] i2c: rcar_i2c: Setup SCL/SDA delay at rcar_i2c_set_speed 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 Reviewed-by: Marek Vasut Reviewed-by: Heiko Schocher --- 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; } From 3b59eaef4fa6139b86203db55b2e90aad1befa61 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Cortes Date: Thu, 7 Mar 2019 18:00:51 +0000 Subject: [PATCH 06/10] i2c: rcar_i2c: Add comments about registers & values Document the meaning of macros related to registers and values to be written to them. Signed-off-by: Ismael Luceno Reviewed-by: Marek Vasut Reviewed-by: Heiko Schocher --- 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 #include -#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, From 3ad31eb1cc6ed4b9a54529df5a30c8321a0ec0de Mon Sep 17 00:00:00 2001 From: Ismael Luceno Cortes Date: Thu, 7 Mar 2019 18:00:52 +0000 Subject: [PATCH 07/10] i2c: rcar_i2c: Fix sending of slave addresses 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 Reviewed-by: Marek Vasut Reviewed-by: Heiko Schocher --- 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); From ff4035be9bd1ef60f5cf772539304ac1ee728fbb Mon Sep 17 00:00:00 2001 From: Ismael Luceno Cortes Date: Thu, 7 Mar 2019 18:00:53 +0000 Subject: [PATCH 08/10] i2c: rcar_i2c: Don't mask errors with EREMOTEIO at rcar_i2c_xfer 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 Reviewed-by: Marek Vasut Reviewed-by: Heiko Schocher --- 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; From 7c8f821e5dde39dd507925168cd38b1e3d9d46d5 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Cortes Date: Thu, 7 Mar 2019 18:00:54 +0000 Subject: [PATCH 09/10] i2c: rcar_i2c: Set the slave address from rcar_i2c_xfer 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 Reviewed-by: Marek Vasut Reviewed-by: Heiko Schocher --- 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) From c64eb297e7b8cc49ff9ba047ee437e093f2d0446 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Cortes Date: Thu, 7 Mar 2019 18:00:55 +0000 Subject: [PATCH 10/10] i2c: rcar_i2c: Move FSDA check to rcar_i2c_recover 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 --- 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; }