Skip to content

Commit 093f70c

Browse files
author
Wolfram Sang
committed
i2c: rcar: fix NACK handling when being a target
When this controller is a target, the NACK handling had two issues. First, the return value from the backend was not checked on the initial WRITE_REQUESTED. So, the driver missed to send a NACK in this case. Also, the NACK always arrives one byte late on the bus, even in the WRITE_RECEIVED case. This seems to be a HW issue. We should then not rely on the backend to correctly NACK the superfluous byte as well. Fix both issues by introducing a flag which gets set whenever the backend requests a NACK and keep sending it until we get a STOP condition. Fixes: de20d18 ("i2c: rcar: add slave support") Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
1 parent 385f2db commit 093f70c

File tree

1 file changed

+15
-5
lines changed

1 file changed

+15
-5
lines changed

drivers/i2c/busses/i2c-rcar.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@
130130
#define ID_P_PM_BLOCKED BIT(31)
131131
#define ID_P_MASK GENMASK(31, 27)
132132

133+
#define ID_SLAVE_NACK BIT(0)
134+
133135
enum rcar_i2c_type {
134136
I2C_RCAR_GEN1,
135137
I2C_RCAR_GEN2,
@@ -166,6 +168,7 @@ struct rcar_i2c_priv {
166168
int irq;
167169

168170
struct i2c_client *host_notify_client;
171+
u8 slave_flags;
169172
};
170173

171174
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
@@ -655,6 +658,7 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
655658
{
656659
u32 ssr_raw, ssr_filtered;
657660
u8 value;
661+
int ret;
658662

659663
ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff;
660664
ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER);
@@ -670,7 +674,10 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
670674
rcar_i2c_write(priv, ICRXTX, value);
671675
rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
672676
} else {
673-
i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
677+
ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
678+
if (ret)
679+
priv->slave_flags |= ID_SLAVE_NACK;
680+
674681
rcar_i2c_read(priv, ICRXTX); /* dummy read */
675682
rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
676683
}
@@ -683,18 +690,21 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
683690
if (ssr_filtered & SSR) {
684691
i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
685692
rcar_i2c_write(priv, ICSCR, SIE | SDBS); /* clear our NACK */
693+
priv->slave_flags &= ~ID_SLAVE_NACK;
686694
rcar_i2c_write(priv, ICSIER, SAR);
687695
rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
688696
}
689697

690698
/* master wants to write to us */
691699
if (ssr_filtered & SDR) {
692-
int ret;
693-
694700
value = rcar_i2c_read(priv, ICRXTX);
695701
ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
696-
/* Send NACK in case of error */
697-
rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
702+
if (ret)
703+
priv->slave_flags |= ID_SLAVE_NACK;
704+
705+
/* Send NACK in case of error, but it will come 1 byte late :( */
706+
rcar_i2c_write(priv, ICSCR, SIE | SDBS |
707+
(priv->slave_flags & ID_SLAVE_NACK ? FNA : 0));
698708
rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
699709
}
700710

0 commit comments

Comments
 (0)