aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfram Sang <wsa+renesas@sang-engineering.com>2018-08-08 03:59:28 -0400
committerWolfram Sang <wsa@the-dreams.de>2018-08-20 08:49:41 -0400
commit19358d4488db7e6a04e940730cc75909d7d1e0d8 (patch)
tree34e8ef30c493874ed7705a463f99e79dc9ec627d
parentb07531acd55180efc95e334605f04ca1eaf4e003 (diff)
i2c: rcar: implement STOP and REP_START according to docs
When doing a REP_START after a read message, the driver used to trigger a STOP first which would then be overwritten by REP_START. This was the only stable method found when doing the last refactoring. However, this was not in accordance with the documentation. After research from our BSP team and myself, we now can implement a version which works and is according to the documentation. The new approach ensures the ICMCR register is only changed when really needed. Tested on a R-Car Gen2 (H2) and Gen3 with DMA (M3N). Signed-off-by: Hiromitsu Yamasaki <hiromitsu.yamasaki.ym@renesas.com> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Reviewed-by: Ulrich Hecht <uli+renesas@fpond.eu> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r--drivers/i2c/busses/i2c-rcar.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index a9f1880e2eae..43ad933df0f0 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -113,9 +113,10 @@
113#define ID_ARBLOST (1 << 3) 113#define ID_ARBLOST (1 << 3)
114#define ID_NACK (1 << 4) 114#define ID_NACK (1 << 4)
115/* persistent flags */ 115/* persistent flags */
116#define ID_P_REP_AFTER_RD BIT(29)
116#define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */ 117#define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */
117#define ID_P_PM_BLOCKED BIT(31) 118#define ID_P_PM_BLOCKED BIT(31)
118#define ID_P_MASK GENMASK(31, 30) 119#define ID_P_MASK GENMASK(31, 29)
119 120
120enum rcar_i2c_type { 121enum rcar_i2c_type {
121 I2C_RCAR_GEN1, 122 I2C_RCAR_GEN1,
@@ -345,7 +346,10 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
345 rcar_i2c_write(priv, ICMSR, 0); 346 rcar_i2c_write(priv, ICMSR, 0);
346 rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); 347 rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
347 } else { 348 } else {
348 rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); 349 if (priv->flags & ID_P_REP_AFTER_RD)
350 priv->flags &= ~ID_P_REP_AFTER_RD;
351 else
352 rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
349 rcar_i2c_write(priv, ICMSR, 0); 353 rcar_i2c_write(priv, ICMSR, 0);
350 } 354 }
351 rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); 355 rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
@@ -550,15 +554,15 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
550 priv->pos++; 554 priv->pos++;
551 } 555 }
552 556
553 /* 557 /* If next received data is the _LAST_, go to new phase. */
554 * If next received data is the _LAST_, go to STOP phase. Might be 558 if (priv->pos + 1 == msg->len) {
555 * overwritten by REP START when setting up a new msg. Not elegant 559 if (priv->flags & ID_LAST_MSG) {
556 * but the only stable sequence for REP START I have found so far. 560 rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
557 * If you want to change this code, make sure sending one transfer with 561 } else {
558 * four messages (WR-RD-WR-RD) works! 562 rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
559 */ 563 priv->flags |= ID_P_REP_AFTER_RD;
560 if (priv->pos + 1 >= msg->len) 564 }
561 rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); 565 }
562 566
563 if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG)) 567 if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
564 rcar_i2c_next_msg(priv); 568 rcar_i2c_next_msg(priv);
@@ -626,9 +630,11 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
626 struct rcar_i2c_priv *priv = ptr; 630 struct rcar_i2c_priv *priv = ptr;
627 u32 msr, val; 631 u32 msr, val;
628 632
629 /* Clear START or STOP as soon as we can */ 633 /* Clear START or STOP immediately, except for REPSTART after read */
630 val = rcar_i2c_read(priv, ICMCR); 634 if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) {
631 rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA); 635 val = rcar_i2c_read(priv, ICMCR);
636 rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
637 }
632 638
633 msr = rcar_i2c_read(priv, ICMSR); 639 msr = rcar_i2c_read(priv, ICMSR);
634 640