Skip to content

Commit 238904d

Browse files
Wolfram Sangwsakernel
authored andcommitted
i2c: rcar: refactor handling of first message
After moving ICMSR handling to interrupt handlers previously to fix a race condition, we can now also move ICMSR handling for the first message out of the function to prepare a message. By introducing a seperate function to initialize the first message, we can not only remove some code duplication but the remaining code is also easier to follow. The function to prepare a message is much simpler without ICMSR handling. Signed-off-by: Wolfram Sang <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent a0fb48c commit 238904d

File tree

1 file changed

+23
-27
lines changed

1 file changed

+23
-27
lines changed

drivers/i2c/busses/i2c-rcar.c

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@
9898
#define RCAR_IRQ_STOP (MST)
9999

100100
#define ID_LAST_MSG (1 << 0)
101-
#define ID_FIRST_MSG (1 << 1)
102101
#define ID_DONE (1 << 2)
103102
#define ID_ARBLOST (1 << 3)
104103
#define ID_NACK (1 << 4)
@@ -333,41 +332,47 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv)
333332
return 0;
334333
}
335334

335+
/*
336+
* We don't have a test case but the HW engineers say that the write order of
337+
* ICMSR and ICMCR depends on whether we issue START or REP_START. So, ICMSR
338+
* handling is outside of this function. First messages clear ICMSR before this
339+
* function, interrupt handlers clear the relevant bits after this function.
340+
*/
336341
static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
337342
{
338343
int read = !!rcar_i2c_is_recv(priv);
339344

340345
priv->pos = 0;
346+
priv->flags &= ID_P_MASK;
347+
341348
if (priv->msgs_left == 1)
342349
priv->flags |= ID_LAST_MSG;
343350

344351
rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg));
345352
if (!priv->atomic_xfer)
346353
rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
347354

348-
/*
349-
* We don't have a test case but the HW engineers say that the write order
350-
* of ICMSR and ICMCR depends on whether we issue START or REP_START. Since
351-
* it didn't cause a drawback for me, let's rather be safe than sorry.
352-
*/
353-
if (priv->flags & ID_FIRST_MSG) {
354-
rcar_i2c_write(priv, ICMSR, 0);
355+
if (priv->flags & ID_P_REP_AFTER_RD)
356+
priv->flags &= ~ID_P_REP_AFTER_RD;
357+
else
355358
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
356-
} else {
357-
if (priv->flags & ID_P_REP_AFTER_RD)
358-
priv->flags &= ~ID_P_REP_AFTER_RD;
359-
else
360-
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
361-
/* ICMSR is cleared in interrupt handlers */
362-
}
359+
}
360+
361+
static void rcar_i2c_first_msg(struct rcar_i2c_priv *priv,
362+
struct i2c_msg *msgs, int num)
363+
{
364+
priv->msg = msgs;
365+
priv->msgs_left = num;
366+
rcar_i2c_write(priv, ICMSR, 0); /* must be before preparing msg */
367+
rcar_i2c_prepare_msg(priv);
363368
}
364369

365370
static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
366371
{
367372
priv->msg++;
368373
priv->msgs_left--;
369-
priv->flags &= ID_P_MASK;
370374
rcar_i2c_prepare_msg(priv);
375+
/* ICMSR handling must come afterwards in the irq handler */
371376
}
372377

373378
static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv, bool terminate)
@@ -852,11 +857,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
852857
for (i = 0; i < num; i++)
853858
rcar_i2c_request_dma(priv, msgs + i);
854859

855-
/* init first message */
856-
priv->msg = msgs;
857-
priv->msgs_left = num;
858-
priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
859-
rcar_i2c_prepare_msg(priv);
860+
rcar_i2c_first_msg(priv, msgs, num);
860861

861862
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
862863
num * adap->timeout);
@@ -906,12 +907,7 @@ static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap,
906907
goto out;
907908

908909
rcar_i2c_init(priv);
909-
910-
/* init first message */
911-
priv->msg = msgs;
912-
priv->msgs_left = num;
913-
priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
914-
rcar_i2c_prepare_msg(priv);
910+
rcar_i2c_first_msg(priv, msgs, num);
915911

916912
j = jiffies + num * adap->timeout;
917913
do {

0 commit comments

Comments
 (0)