Skip to content

Commit e72ffcc

Browse files
Wolfram Sangopsiff
authored andcommitted
i2c: rcar: fix NACK handling when being a target
[ Upstream commit 093f70c ] 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 <[email protected]> Signed-off-by: Sasha Levin <[email protected]> (cherry picked from commit 0558c4e0fd6e49cdd0b16d52fcf47cfab88e04bf)
1 parent 6e7b783 commit e72ffcc

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
@@ -110,6 +110,8 @@
110110
#define ID_P_PM_BLOCKED BIT(31)
111111
#define ID_P_MASK GENMASK(31, 28)
112112

113+
#define ID_SLAVE_NACK BIT(0)
114+
113115
enum rcar_i2c_type {
114116
I2C_RCAR_GEN1,
115117
I2C_RCAR_GEN2,
@@ -143,6 +145,7 @@ struct rcar_i2c_priv {
143145
int irq;
144146

145147
struct i2c_client *host_notify_client;
148+
u8 slave_flags;
146149
};
147150

148151
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
@@ -597,6 +600,7 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
597600
{
598601
u32 ssr_raw, ssr_filtered;
599602
u8 value;
603+
int ret;
600604

601605
ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff;
602606
ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER);
@@ -612,7 +616,10 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
612616
rcar_i2c_write(priv, ICRXTX, value);
613617
rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
614618
} else {
615-
i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
619+
ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
620+
if (ret)
621+
priv->slave_flags |= ID_SLAVE_NACK;
622+
616623
rcar_i2c_read(priv, ICRXTX); /* dummy read */
617624
rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
618625
}
@@ -625,18 +632,21 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
625632
if (ssr_filtered & SSR) {
626633
i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
627634
rcar_i2c_write(priv, ICSCR, SIE | SDBS); /* clear our NACK */
635+
priv->slave_flags &= ~ID_SLAVE_NACK;
628636
rcar_i2c_write(priv, ICSIER, SAR);
629637
rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
630638
}
631639

632640
/* master wants to write to us */
633641
if (ssr_filtered & SDR) {
634-
int ret;
635-
636642
value = rcar_i2c_read(priv, ICRXTX);
637643
ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
638-
/* Send NACK in case of error */
639-
rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
644+
if (ret)
645+
priv->slave_flags |= ID_SLAVE_NACK;
646+
647+
/* Send NACK in case of error, but it will come 1 byte late :( */
648+
rcar_i2c_write(priv, ICSCR, SIE | SDBS |
649+
(priv->slave_flags & ID_SLAVE_NACK ? FNA : 0));
640650
rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
641651
}
642652

0 commit comments

Comments
 (0)