Skip to content

Commit b31addf

Browse files
prabhakarladWolfram Sang
authored andcommitted
i2c: riic: Add riic_bus_barrier() to check bus availability
Introduce a new `riic_bus_barrier()` function to verify bus availability before initiating an I2C transfer. This function enhances the bus arbitration check by ensuring that the SDA and SCL lines are not held low, in addition to checking the BBSY flag using `readb_poll_timeout()`. Previously, only the BBSY flag was checked to determine bus availability. However, it is possible for the SDA line to remain low even when BBSY = 0. This new implementation performs an additional check on the SDA and SCL lines to avoid potential bus contention issues. Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> Reviewed-by: Andy Shevchenko <andy@kernel.org> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
1 parent 385bb1c commit b31addf

File tree

1 file changed

+26
-4
lines changed

1 file changed

+26
-4
lines changed

drivers/i2c/busses/i2c-riic.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <linux/i2c.h>
4242
#include <linux/interrupt.h>
4343
#include <linux/io.h>
44+
#include <linux/iopoll.h>
4445
#include <linux/module.h>
4546
#include <linux/of.h>
4647
#include <linux/platform_device.h>
@@ -51,6 +52,8 @@
5152
#define ICCR1_ICE BIT(7)
5253
#define ICCR1_IICRST BIT(6)
5354
#define ICCR1_SOWP BIT(4)
55+
#define ICCR1_SCLI BIT(1)
56+
#define ICCR1_SDAI BIT(0)
5457

5558
#define ICCR2_BBSY BIT(7)
5659
#define ICCR2_SP BIT(3)
@@ -136,6 +139,27 @@ static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u
136139
riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg);
137140
}
138141

142+
static int riic_bus_barrier(struct riic_dev *riic)
143+
{
144+
int ret;
145+
u8 val;
146+
147+
/*
148+
* The SDA line can still be low even when BBSY = 0. Therefore, after checking
149+
* the BBSY flag, also verify that the SDA and SCL lines are not being held low.
150+
*/
151+
ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val,
152+
!(val & ICCR2_BBSY), 10, riic->adapter.timeout);
153+
if (ret)
154+
return ret;
155+
156+
if ((riic_readb(riic, RIIC_ICCR1) & (ICCR1_SDAI | ICCR1_SCLI)) !=
157+
(ICCR1_SDAI | ICCR1_SCLI))
158+
return -EBUSY;
159+
160+
return 0;
161+
}
162+
139163
static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
140164
{
141165
struct riic_dev *riic = i2c_get_adapdata(adap);
@@ -148,13 +172,11 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
148172
if (ret)
149173
return ret;
150174

151-
if (riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) {
152-
riic->err = -EBUSY;
175+
riic->err = riic_bus_barrier(riic);
176+
if (riic->err)
153177
goto out;
154-
}
155178

156179
reinit_completion(&riic->msg_done);
157-
riic->err = 0;
158180

159181
riic_writeb(riic, 0, RIIC_ICSR2);
160182

0 commit comments

Comments
 (0)