Message ID | 20241213175828.909987-9-prabhakar.mahadev-lad.rj@bp.renesas.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Geert Uytterhoeven |
Headers | show |
Series | Add support for I2C bus recovery for riic driver | expand |
Hi Prabhakar, On Fri, Dec 13, 2024 at 6:58 PM Prabhakar <prabhakar.csengg@gmail.com> wrote: > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> > > 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> Thanks for your patch! > --- a/drivers/i2c/busses/i2c-riic.c > +++ b/drivers/i2c/busses/i2c-riic.c > @@ -135,6 +138,27 @@ static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u > riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg); > } > > +static int riic_bus_barrier(struct riic_dev *riic) > +{ > + int ret; > + u8 val; > + > + /* > + * The SDA line can still be low even when BBSY = 0. Therefore, after checking > + * the BBSY flag, also verify that the SDA and SCL lines are not being held low. > + */ > + ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val, > + !(val & ICCR2_BBSY), 10, riic->adapter.timeout); > + if (ret) > + return -EBUSY; > + > + if (!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI) || > + !(riic_readb(riic, RIIC_ICCR1) & ICCR1_SCLI)) Surely you can read the register once, and check both bits? > + return -EBUSY; > + > + return 0; > +} > + > static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) > { > struct riic_dev *riic = i2c_get_adapdata(adap); Gr{oetje,eeting}s, Geert
Hi Geert, Thank you for the review. On Mon, Dec 16, 2024 at 4:09 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote: > > Hi Prabhakar, > > On Fri, Dec 13, 2024 at 6:58 PM Prabhakar <prabhakar.csengg@gmail.com> wrote: > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> > > > > 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> > > Thanks for your patch! > > > --- a/drivers/i2c/busses/i2c-riic.c > > +++ b/drivers/i2c/busses/i2c-riic.c > > > @@ -135,6 +138,27 @@ static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u > > riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg); > > } > > > > +static int riic_bus_barrier(struct riic_dev *riic) > > +{ > > + int ret; > > + u8 val; > > + > > + /* > > + * The SDA line can still be low even when BBSY = 0. Therefore, after checking > > + * the BBSY flag, also verify that the SDA and SCL lines are not being held low. > > + */ > > + ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val, > > + !(val & ICCR2_BBSY), 10, riic->adapter.timeout); > > + if (ret) > > + return -EBUSY; > > + > > + if (!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI) || > > + !(riic_readb(riic, RIIC_ICCR1) & ICCR1_SCLI)) > > Surely you can read the register once, and check both bits? > Agreed, I will add a helper func for this something like below, as this can be re-used in patch 9/9 static inline bool riic_lines_ok(struct riic_dev *riic) { u8 reg = riic_readb(riic, RIIC_ICCR1); if (!(reg & ICCR1_SDAI) || !(reg & ICCR1_SCLI)) return false; return true; } Cheers, Prabhakar
Hi Prabhakar, On Mon, Dec 16, 2024 at 7:19 PM Lad, Prabhakar <prabhakar.csengg@gmail.com> wrote: > On Mon, Dec 16, 2024 at 4:09 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote: > > On Fri, Dec 13, 2024 at 6:58 PM Prabhakar <prabhakar.csengg@gmail.com> wrote: > > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> > > > > > > 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> > > > > Thanks for your patch! > > > > > --- a/drivers/i2c/busses/i2c-riic.c > > > +++ b/drivers/i2c/busses/i2c-riic.c > > > > > @@ -135,6 +138,27 @@ static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u > > > riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg); > > > } > > > > > > +static int riic_bus_barrier(struct riic_dev *riic) > > > +{ > > > + int ret; > > > + u8 val; > > > + > > > + /* > > > + * The SDA line can still be low even when BBSY = 0. Therefore, after checking > > > + * the BBSY flag, also verify that the SDA and SCL lines are not being held low. > > > + */ > > > + ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val, > > > + !(val & ICCR2_BBSY), 10, riic->adapter.timeout); > > > + if (ret) > > > + return -EBUSY; > > > + > > > + if (!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI) || > > > + !(riic_readb(riic, RIIC_ICCR1) & ICCR1_SCLI)) > > > > Surely you can read the register once, and check both bits? > > > Agreed, I will add a helper func for this something like below, as > this can be re-used in patch 9/9 > > static inline bool riic_lines_ok(struct riic_dev *riic) > { > u8 reg = riic_readb(riic, RIIC_ICCR1); > > if (!(reg & ICCR1_SDAI) || !(reg & ICCR1_SCLI)) > return false; > > return true; > } A helper might be overkill... if ((riic_readb(riic, RIIC_ICCR1) & (ICCR1_SDAI | ICCR1_SCLI)) != ICCR1_SDAI | ICCR1_SCLI) ... Gr{oetje,eeting}s, Geert
Hi Geert, On Mon, Dec 16, 2024 at 7:13 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote: > > Hi Prabhakar, > > On Mon, Dec 16, 2024 at 7:19 PM Lad, Prabhakar > <prabhakar.csengg@gmail.com> wrote: > > On Mon, Dec 16, 2024 at 4:09 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote: > > > On Fri, Dec 13, 2024 at 6:58 PM Prabhakar <prabhakar.csengg@gmail.com> wrote: > > > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> > > > > > > > > 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> > > > > > > Thanks for your patch! > > > > > > > --- a/drivers/i2c/busses/i2c-riic.c > > > > +++ b/drivers/i2c/busses/i2c-riic.c > > > > > > > @@ -135,6 +138,27 @@ static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u > > > > riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg); > > > > } > > > > > > > > +static int riic_bus_barrier(struct riic_dev *riic) > > > > +{ > > > > + int ret; > > > > + u8 val; > > > > + > > > > + /* > > > > + * The SDA line can still be low even when BBSY = 0. Therefore, after checking > > > > + * the BBSY flag, also verify that the SDA and SCL lines are not being held low. > > > > + */ > > > > + ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val, > > > > + !(val & ICCR2_BBSY), 10, riic->adapter.timeout); > > > > + if (ret) > > > > + return -EBUSY; > > > > + > > > > + if (!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI) || > > > > + !(riic_readb(riic, RIIC_ICCR1) & ICCR1_SCLI)) > > > > > > Surely you can read the register once, and check both bits? > > > > > Agreed, I will add a helper func for this something like below, as > > this can be re-used in patch 9/9 > > > > static inline bool riic_lines_ok(struct riic_dev *riic) > > { > > u8 reg = riic_readb(riic, RIIC_ICCR1); > > > > if (!(reg & ICCR1_SDAI) || !(reg & ICCR1_SCLI)) > > return false; > > > > return true; > > } > > A helper might be overkill... > > if ((riic_readb(riic, RIIC_ICCR1) & (ICCR1_SDAI | ICCR1_SCLI)) != > ICCR1_SDAI | ICCR1_SCLI) > ... > Ok, I'll update as suggested above. Cheers, Prabhakar
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 48812e7d9cef..919da1bdcce5 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -40,6 +40,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -50,6 +51,8 @@ #define ICCR1_ICE BIT(7) #define ICCR1_IICRST BIT(6) #define ICCR1_SOWP BIT(4) +#define ICCR1_SCLI BIT(1) +#define ICCR1_SDAI BIT(0) #define ICCR2_BBSY BIT(7) #define ICCR2_SP BIT(3) @@ -135,6 +138,27 @@ static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg); } +static int riic_bus_barrier(struct riic_dev *riic) +{ + int ret; + u8 val; + + /* + * The SDA line can still be low even when BBSY = 0. Therefore, after checking + * the BBSY flag, also verify that the SDA and SCL lines are not being held low. + */ + ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val, + !(val & ICCR2_BBSY), 10, riic->adapter.timeout); + if (ret) + return -EBUSY; + + if (!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI) || + !(riic_readb(riic, RIIC_ICCR1) & ICCR1_SCLI)) + return -EBUSY; + + return 0; +} + static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct riic_dev *riic = i2c_get_adapdata(adap); @@ -147,10 +171,9 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (ret) return ret; - if (riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) { - riic->err = -EBUSY; + riic->err = riic_bus_barrier(riic); + if (riic->err) goto out; - } reinit_completion(&riic->msg_done); riic->err = 0;