Commit e5a7effa authored by Wolfram Sang's avatar Wolfram Sang Committed by Wolfram Sang

i2c: rcar: revoke START request early

If we don't clear START generation as soon as possible, it may cause
another message to be generated. To keep the race window as small as
possible, we clear it right at the beginning of the interrupt. We don't
need checking since we always want to stop START and STOP generation on
the next occasion after we started it.

This patch improves the situation but sadly does not completely fix it.
It is still to be researched if we can do better given this HW design.
Signed-off-by: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 2151ba75
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG) #define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
#define RCAR_BUS_PHASE_DATA (MDBS | MIE) #define RCAR_BUS_PHASE_DATA (MDBS | MIE)
#define RCAR_BUS_MASK_DATA (~(ESG | FSB) & 0xFF)
#define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB) #define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB)
#define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE) #define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE)
...@@ -288,13 +289,6 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) ...@@ -288,13 +289,6 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
if (!(msr & MDE)) if (!(msr & MDE))
return 0; return 0;
/*
* If address transfer phase finished,
* goto data phase.
*/
if (msr & MAT)
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
if (priv->pos < msg->len) { if (priv->pos < msg->len) {
/* /*
* Prepare next data to ICRXTX register. * Prepare next data to ICRXTX register.
...@@ -346,11 +340,7 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) ...@@ -346,11 +340,7 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
return 0; return 0;
if (msr & MAT) { if (msr & MAT) {
/* /* Address transfer phase finished, but no data at this point. */
* Address transfer phase finished,
* but, there is no data at this point.
* Do nothing.
*/
} else if (priv->pos < msg->len) { } else if (priv->pos < msg->len) {
/* /*
* get received data * get received data
...@@ -366,8 +356,6 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) ...@@ -366,8 +356,6 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
*/ */
if (priv->pos + 1 >= msg->len) if (priv->pos + 1 >= msg->len)
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
else
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG)) if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
rcar_i2c_next_msg(priv); rcar_i2c_next_msg(priv);
...@@ -435,7 +423,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) ...@@ -435,7 +423,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
static irqreturn_t rcar_i2c_irq(int irq, void *ptr) static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
{ {
struct rcar_i2c_priv *priv = ptr; struct rcar_i2c_priv *priv = ptr;
u32 msr; u32 msr, val;
/* Clear START or STOP as soon as we can */
val = rcar_i2c_read(priv, ICMCR);
rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
msr = rcar_i2c_read(priv, ICMSR); msr = rcar_i2c_read(priv, ICMSR);
...@@ -457,7 +449,6 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) ...@@ -457,7 +449,6 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
/* Nack */ /* Nack */
if (msr & MNR) { if (msr & MNR) {
/* HW automatically sends STOP after received NACK */ /* HW automatically sends STOP after received NACK */
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP); rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
rcar_i2c_flags_set(priv, ID_NACK); rcar_i2c_flags_set(priv, ID_NACK);
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment