Skip to content

Commit 445522f

Browse files
TroyMitchell911Wolfram Sang
authored andcommitted
i2c: spacemit: remove stop function to avoid bus error
Previously, STOP handling was split into two separate steps: 1) clear TB/STOP/START/ACK bits 2) issue STOP by calling spacemit_i2c_stop() This left a small window where the control register was updated twice, which can confuse the controller. While this race has not been observed with interrupt-driven transfers, it reliably causes bus errors in PIO mode. Inline the STOP sequence into the IRQ handler and ensure that control register bits are updated atomically in a single writel(). Fixes: 5ea5584 ("i2c: spacemit: add support for SpacemiT K1 SoC") Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
1 parent 41d6f90 commit 445522f

1 file changed

Lines changed: 7 additions & 19 deletions

File tree

drivers/i2c/busses/i2c-k1.c

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -267,19 +267,6 @@ static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
267267
writel(val, i2c->base + SPACEMIT_ICR);
268268
}
269269

270-
static void spacemit_i2c_stop(struct spacemit_i2c_dev *i2c)
271-
{
272-
u32 val;
273-
274-
val = readl(i2c->base + SPACEMIT_ICR);
275-
val |= SPACEMIT_CR_STOP | SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
276-
277-
if (i2c->read)
278-
val |= SPACEMIT_CR_ACKNAK;
279-
280-
writel(val, i2c->base + SPACEMIT_ICR);
281-
}
282-
283270
static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)
284271
{
285272
unsigned long time_left;
@@ -412,7 +399,6 @@ static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
412399

413400
val = readl(i2c->base + SPACEMIT_ICR);
414401
val &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK | SPACEMIT_CR_STOP | SPACEMIT_CR_START);
415-
writel(val, i2c->base + SPACEMIT_ICR);
416402

417403
switch (i2c->state) {
418404
case SPACEMIT_STATE_START:
@@ -429,14 +415,16 @@ static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
429415
}
430416

431417
if (i2c->state != SPACEMIT_STATE_IDLE) {
418+
val |= SPACEMIT_CR_TB | SPACEMIT_CR_ALDIE;
419+
432420
if (spacemit_i2c_is_last_msg(i2c)) {
433421
/* trigger next byte with stop */
434-
spacemit_i2c_stop(i2c);
435-
} else {
436-
/* trigger next byte */
437-
val |= SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
438-
writel(val, i2c->base + SPACEMIT_ICR);
422+
val |= SPACEMIT_CR_STOP;
423+
424+
if (i2c->read)
425+
val |= SPACEMIT_CR_ACKNAK;
439426
}
427+
writel(val, i2c->base + SPACEMIT_ICR);
440428
}
441429

442430
err_out:

0 commit comments

Comments
 (0)