[PATCH 3/3] i2c: imx_lpi2c: Support read transfers longer than 256 bytes
Fedor Ross
fedorross at gmail.com
Tue Jul 30 14:41:06 CEST 2024
On Wed, Jul 24, 2024 at 12:57 PM Marek Vasut <marex at denx.de> wrote:
Hello Marek,
I'll do the changes. Thanks for your input.
Best regards,
Fedor
> On 7/24/24 11:59 AM, fedorross at gmail.com wrote:
> > From: Fedor Ross <fedor.ross at ifm.com>
> >
> > The TXFIFO register of LPI2C only has one byte length, and if the length
> > of the data that needs to be read exceeds 256 bytes, it needs to be
> > written to TXFIFO multiple times.
> >
> > Signed-off-by: Fedor Ross <fedor.ross at ifm.com>
>
> Add ---
>
> > Cc: Heiko Schocher <hs at denx.de>
> > Cc: Tom Rini <trini at konsulko.com>
> > Cc: Marek Vasut <marex at denx.de>
> > ---
> > drivers/i2c/imx_lpi2c.c | 72 +++++++++++++++++++++++++++--------------
> > 1 file changed, 47 insertions(+), 25 deletions(-)
> >
> > diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c
> > index 7b10b2b252d..dd97228ddc7 100644
> > --- a/drivers/i2c/imx_lpi2c.c
> > +++ b/drivers/i2c/imx_lpi2c.c
> > @@ -19,6 +19,8 @@
> > #define LPI2C_NACK_TOUT_MS 1
> > #define LPI2C_TIMEOUT_MS 100
> >
> > +#define CHUNK_DATA 256
>
> Use LPI2C_CHUNK_DATA to namespace this macro.
>
> > static int bus_i2c_init(struct udevice *bus, int speed);
> >
> > /* Weak linked function for overridden by some SoC power function */
> > @@ -118,8 +120,10 @@ static int bus_i2c_send(struct udevice *bus, u8 *txbuf, int len)
> >
> > static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len)
> > {
> > + struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
> > struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
> > struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
> > + unsigned int chunk_len, rx_remain, timeout;
> > lpi2c_status_t result = LPI2C_SUCESS;
> > u32 val;
> > ulong start_time = get_timer(0);
> > @@ -128,33 +132,51 @@ static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len)
> > if (!len)
> > return result;
> >
> > - result = bus_i2c_wait_for_tx_ready(regs);
> > - if (result) {
> > - debug("i2c: receive wait for tx ready: %d\n", result);
> > - return result;
> > - }
> > + /*
> > + * Extend the timeout for a bulk read if needed.
> > + * The calculated timeout is the result of multiplying the
> > + * transfer length with 8 bit + ACK + one clock of extra time,
> > + * considering the I2C bus frequency.
> > + */
> > + timeout = max(len * 10 * 1000 / i2c->speed_hz, LPI2C_TIMEOUT_MS);
> >
> > - /* clear all status flags */
> > - writel(0x7f00, ®s->msr);
> > - /* send receive command */
> > - val = LPI2C_MTDR_CMD(0x1) | LPI2C_MTDR_DATA(len - 1);
> > - writel(val, ®s->mtdr);
> > + rx_remain = len;
> > + while (rx_remain > 0) {
> > + chunk_len = clamp(rx_remain, 1, CHUNK_DATA) - 1;
> >
> > - while (len--) {
> > - do {
> > - result = imx_lpci2c_check_clear_error(regs);
> > - if (result) {
> > - debug("i2c: receive check clear error: %d\n",
> > - result);
> > - return result;
> > - }
> > - if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
> > - debug("i2c: receive mrdr: timeout\n");
> > - return -1;
> > - }
> > - val = readl(®s->mrdr);
> > - } while (val & LPI2C_MRDR_RXEMPTY_MASK);
> > - *rxbuf++ = LPI2C_MRDR_DATA(val);
> > + result = bus_i2c_wait_for_tx_ready(regs);
> > + if (result) {
> > + debug("i2c: receive wait for tx ready: %d\n", result);
> > + return result;
> > + }
> > +
> > + /* clear all status flags */
> > + writel(0x7f00, ®s->msr);
> > + /* send receive command */
> > + val = LPI2C_MTDR_CMD(0x1) | LPI2C_MTDR_DATA(chunk_len);
> > + writel(val, ®s->mtdr);
>
> writel(LPI2C_MTDR_CMD(0x1) | LPI2C_MTDR_DATA(chunk_len);, ®s->mtdr);
>
> and drop the val = assignment here.
>
> > + rx_remain = rx_remain - (chunk_len & 0xff) - 1;
> > +
> > + while (len--) {
> > + do {
> > + result = imx_lpci2c_check_clear_error(regs);
> > + if (result) {
> > + debug("i2c: receive check clear error: %d\n",
> > + result);
> > + return result;
> > + }
> > + if (get_timer(start_time) > timeout) {
> > + debug("i2c: receive mrdr: timeout\n");
> > + return -1;
> > + }
> > + val = readl(®s->mrdr);
> > + } while (val & LPI2C_MRDR_RXEMPTY_MASK);
> > + *rxbuf++ = LPI2C_MRDR_DATA(val);
> > +
> > + /* send next receive command before controller NACKs last byte */
> > + if ((len - rx_remain) < 2 && rx_remain > 0)
> > + break;
> > + }
> > }
More information about the U-Boot
mailing list