Skip to content

Commit 990489e

Browse files
mszyprowwsakernel
authored andcommitted
i2c: s3c24xx: fix transferring more than one message in polling mode
To properly handle ACK on the bus when transferring more than one message in polling mode, move the polling handling loop from s3c24xx_i2c_message_start() to s3c24xx_i2c_doxfer(). This way i2c_s3c_irq_nextbyte() is always executed till the end, properly acknowledging the IRQ bits and no recursive calls to i2c_s3c_irq_nextbyte() are made. While touching this, also fix finishing transfers in polling mode by using common code path and always waiting for the bus to become idle and disabled. Fixes: 117053f ("i2c: s3c2410: Add polling mode support") Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Andi Shyti <andi.shyti@kernel.org> Signed-off-by: Wolfram Sang <wsa@kernel.org>
1 parent 0d9cf23 commit 990489e

1 file changed

Lines changed: 10 additions & 17 deletions

File tree

drivers/i2c/busses/i2c-s3c2410.c

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -279,16 +279,6 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
279279

280280
stat |= S3C2410_IICSTAT_START;
281281
writel(stat, i2c->regs + S3C2410_IICSTAT);
282-
283-
if (i2c->quirks & QUIRK_POLL) {
284-
while ((i2c->msg_num != 0) && is_ack(i2c)) {
285-
i2c_s3c_irq_nextbyte(i2c, stat);
286-
stat = readl(i2c->regs + S3C2410_IICSTAT);
287-
288-
if (stat & S3C2410_IICSTAT_ARBITR)
289-
dev_err(i2c->dev, "deal with arbitration loss\n");
290-
}
291-
}
292282
}
293283

294284
static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
@@ -694,7 +684,7 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
694684
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
695685
struct i2c_msg *msgs, int num)
696686
{
697-
unsigned long timeout;
687+
unsigned long timeout = 0;
698688
int ret;
699689

700690
ret = s3c24xx_i2c_set_master(i2c);
@@ -714,16 +704,19 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
714704
s3c24xx_i2c_message_start(i2c, msgs);
715705

716706
if (i2c->quirks & QUIRK_POLL) {
717-
ret = i2c->msg_idx;
707+
while ((i2c->msg_num != 0) && is_ack(i2c)) {
708+
unsigned long stat = readl(i2c->regs + S3C2410_IICSTAT);
718709

719-
if (ret != num)
720-
dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
710+
i2c_s3c_irq_nextbyte(i2c, stat);
721711

722-
goto out;
712+
stat = readl(i2c->regs + S3C2410_IICSTAT);
713+
if (stat & S3C2410_IICSTAT_ARBITR)
714+
dev_err(i2c->dev, "deal with arbitration loss\n");
715+
}
716+
} else {
717+
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
723718
}
724719

725-
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
726-
727720
ret = i2c->msg_idx;
728721

729722
/*

0 commit comments

Comments
 (0)