Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Lad Prabhakar and committed by
Wolfram Sang
b31addf2 385bb1c2

+26 -4
+26 -4
drivers/i2c/busses/i2c-riic.c
··· 41 41 #include <linux/i2c.h> 42 42 #include <linux/interrupt.h> 43 43 #include <linux/io.h> 44 + #include <linux/iopoll.h> 44 45 #include <linux/module.h> 45 46 #include <linux/of.h> 46 47 #include <linux/platform_device.h> ··· 52 51 #define ICCR1_ICE BIT(7) 53 52 #define ICCR1_IICRST BIT(6) 54 53 #define ICCR1_SOWP BIT(4) 54 + #define ICCR1_SCLI BIT(1) 55 + #define ICCR1_SDAI BIT(0) 55 56 56 57 #define ICCR2_BBSY BIT(7) 57 58 #define ICCR2_SP BIT(3) ··· 139 136 riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg); 140 137 } 141 138 139 + static int riic_bus_barrier(struct riic_dev *riic) 140 + { 141 + int ret; 142 + u8 val; 143 + 144 + /* 145 + * The SDA line can still be low even when BBSY = 0. Therefore, after checking 146 + * the BBSY flag, also verify that the SDA and SCL lines are not being held low. 147 + */ 148 + ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val, 149 + !(val & ICCR2_BBSY), 10, riic->adapter.timeout); 150 + if (ret) 151 + return ret; 152 + 153 + if ((riic_readb(riic, RIIC_ICCR1) & (ICCR1_SDAI | ICCR1_SCLI)) != 154 + (ICCR1_SDAI | ICCR1_SCLI)) 155 + return -EBUSY; 156 + 157 + return 0; 158 + } 159 + 142 160 static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) 143 161 { 144 162 struct riic_dev *riic = i2c_get_adapdata(adap); ··· 172 148 if (ret) 173 149 return ret; 174 150 175 - if (riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) { 176 - riic->err = -EBUSY; 151 + riic->err = riic_bus_barrier(riic); 152 + if (riic->err) 177 153 goto out; 178 - } 179 154 180 155 reinit_completion(&riic->msg_done); 181 - riic->err = 0; 182 156 183 157 riic_writeb(riic, 0, RIIC_ICSR2); 184 158