Hi Carlos, Thanks for your patch, sorry for having taken so much time, looks good, just some nitpicks. ... > diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c > index 976d43f73f38..530ca5d76403 100644 > --- a/drivers/i2c/busses/i2c-imx-lpi2c.c > +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c > @@ -8,6 +8,8 @@ > #include <linux/clk.h> > #include <linux/completion.h> > #include <linux/delay.h> > +#include <linux/dmaengine.h> > +#include <linux/dma-mapping.h> please sort in alphabetical order > #include <linux/err.h> > #include <linux/errno.h> > #include <linux/i2c.h> ... > +struct lpi2c_imx_dma { > + bool using_pio_mode; > + u8 rx_cmd_buf_len; > + u8 *dma_buf; > + u16 *rx_cmd_buf; > + unsigned int dma_len; > + unsigned int tx_burst_num; > + unsigned int rx_burst_num; > + unsigned long dma_msg_flag; > + resource_size_t phy_addr; > + dma_addr_t dma_tx_addr; > + dma_addr_t dma_addr; > + enum dma_data_direction dma_direction; > + struct dma_chan *chan_tx; > + struct dma_chan *chan_rx; > +}; The alignment here is a bit off ... > +static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msg) > +{ > + if (!lpi2c_imx->can_use_dma) > + return false; > + > + /* > + * When the length of data is less than I2C_DMA_THRESHOLD, > + * cpu mode is used directly to avoid low performance. > + */ > + if (msg->len < I2C_DMA_THRESHOLD) > + return false; > + > + return true; You could do return !(msg->len < I2C_DMA_THRESHOLD); Just a matter of taste, your choice. > +} > + > +static int lpi2c_imx_pio_xfer(struct lpi2c_imx_struct *lpi2c_imx, > + struct i2c_msg *msg) > +{ > + int ret; > + > + reinit_completion(&lpi2c_imx->complete); > + > + if (msg->flags & I2C_M_RD) > + lpi2c_imx_read(lpi2c_imx, msg); > + else > + lpi2c_imx_write(lpi2c_imx, msg); > + > + ret = lpi2c_imx_pio_msg_complete(lpi2c_imx); > + if (ret) > + return ret; > + > + return 0; You could do return lpi2c_imx_pio_msg_complete(lpi2c_imx); Purely taste, your choice, still. > +} ... > +static void lpi2c_cleanup_rx_cmd_dma(struct lpi2c_imx_dma *dma) > +{ > + dmaengine_terminate_sync(dma->chan_tx); > + dma_unmap_single(dma->chan_tx->device->dev, dma->dma_tx_addr, > + dma->rx_cmd_buf_len, DMA_TO_DEVICE); alignment > +} ... > +static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx) > +{ > + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; > + struct dma_chan *txchan = dma->chan_tx; > + struct dma_async_tx_descriptor *rx_cmd_desc; > + dma_cookie_t cookie; > + > + dma->dma_tx_addr = dma_map_single(txchan->device->dev, > + dma->rx_cmd_buf, > + dma->rx_cmd_buf_len, DMA_TO_DEVICE); > + if (dma_mapping_error(txchan->device->dev, dma->dma_tx_addr)) { > + dev_err(&lpi2c_imx->adapter.dev, "dma map failed, use pio\n"); /dma/DMA/ and it's valid for every time you have used "dma". > + return -EINVAL; > + } > + > + rx_cmd_desc = dmaengine_prep_slave_single(txchan, dma->dma_tx_addr, > + dma->rx_cmd_buf_len, DMA_MEM_TO_DEV, > + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); alignment. > + if (!rx_cmd_desc) { > + dma_unmap_single(txchan->device->dev, dma->dma_tx_addr, > + dma->rx_cmd_buf_len, DMA_TO_DEVICE); put dma_unmap_single() in a goto exit path. > + dev_err(&lpi2c_imx->adapter.dev, "dma prep slave sg failed, use pio\n"); > + return -EINVAL; > + } > + > + cookie = dmaengine_submit(rx_cmd_desc); > + if (dma_submit_error(cookie)) { > + dma_unmap_single(txchan->device->dev, dma->dma_tx_addr, > + dma->rx_cmd_buf_len, DMA_TO_DEVICE); > + dmaengine_desc_free(rx_cmd_desc); > + dev_err(&lpi2c_imx->adapter.dev, "submitting dma failed, use pio\n"); > + return -EINVAL; > + } > + > + dma_async_issue_pending(txchan); > + > + return 0; > +} > + > +static int lpi2c_dma_submit(struct lpi2c_imx_struct *lpi2c_imx) > +{ > + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; > + bool read = dma->dma_msg_flag & I2C_M_RD; > + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; > + struct dma_chan *chan = read ? dma->chan_rx : dma->chan_tx; I generally prefer the assignment to be done after the declaration. It looks more clear. > + struct dma_async_tx_descriptor *desc; > + dma_cookie_t cookie; > + > + dma->dma_direction = dir; > + dma->dma_addr = dma_map_single(chan->device->dev, > + dma->dma_buf, > + dma->dma_len, dir); alignment is off. > + if (dma_mapping_error(chan->device->dev, dma->dma_addr)) { > + dev_err(&lpi2c_imx->adapter.dev, "dma map failed, use pio\n"); /dma/DMA/ > + return -EINVAL; > + } > + > + desc = dmaengine_prep_slave_single(chan, dma->dma_addr, > + dma->dma_len, read ? > + DMA_DEV_TO_MEM : DMA_MEM_TO_DEV, > + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); alignment off. > + if (!desc) { > + dev_err(&lpi2c_imx->adapter.dev, "dma prep slave sg failed, use pio\n"); > + lpi2c_dma_unmap(dma); put lpi2c_dma_unmape under a goto exit path. > + return -EINVAL; > + } > + > + reinit_completion(&lpi2c_imx->complete); > + desc->callback = lpi2c_dma_callback; > + desc->callback_param = (void *)lpi2c_imx; the cast is not needed. > + cookie = dmaengine_submit(desc); > + if (dma_submit_error(cookie)) { > + dev_err(&lpi2c_imx->adapter.dev, "submitting dma failed, use pio\n"); > + lpi2c_dma_unmap(dma); > + dmaengine_desc_free(desc); > + return -EINVAL; > + } > + > + /* Can't switch to PIO mode when DMA have started transfer */ > + dma->using_pio_mode = false; > + > + dma_async_issue_pending(chan); > + > + return 0; > +} > + > +static int lpi2c_imx_find_max_burst_num(unsigned int fifosize, unsigned int len) > +{ > + unsigned int i; > + > + for (i = fifosize / 2; i > 0; i--) { > + if (!(len % i)) > + break; > + } braces are not needed > + > + return i; > +} > + > +/* > + * For a highest DMA efficiency, tx/rx burst number should be calculated according > + * to the FIFO depth. > + */ > +static void lpi2c_imx_dma_burst_num_calculate(struct lpi2c_imx_struct *lpi2c_imx) > +{ > + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; > + unsigned int cmd_num; > + > + if (dma->dma_msg_flag & I2C_M_RD) { > + /* > + * One RX cmd word can trigger DMA receive no more than 256 bytes. > + * The number of RX cmd words should be calculated based on the data > + * length. > + */ > + cmd_num = DIV_ROUND_UP(dma->dma_len, CHUNK_DATA); > + dma->tx_burst_num = lpi2c_imx_find_max_burst_num(lpi2c_imx->txfifosize, > + cmd_num); > + dma->rx_burst_num = lpi2c_imx_find_max_burst_num(lpi2c_imx->rxfifosize, > + dma->dma_len); > + } else { > + dma->tx_burst_num = lpi2c_imx_find_max_burst_num(lpi2c_imx->txfifosize, > + dma->dma_len); Alignment is off. > + } > +} ... > +/* > + * When lpi2c in TX DMA mode we can use one DMA TX channel to write /in/is in/ > + * data word into TXFIFO, but in RX DMA mode it is different. > + * > + * LPI2C MTDR register is a command data and transmit data register. /LPI2C/The LPI2C/ > + * Bit 8-10 is command data field and Bit 0-7 is transmit data field. /Bit 8-10 is/Bits 8-10 are the/ /Bit 0-7 is/ Bits 0-7 are the/ > + * When the LPI2C master needs to read data, the data number to read /data number/number of bytes/ > + * should be set in transmit data field and RECV_DATA should be set > + * into the command data field to receive (DATA[7:0] + 1) bytes. The > + * recv data command word is made of RECV_DATA in command data field /in command/in the command/ > + * and the data number to read in transmit data field. When the length /data number/number of bytes/ > + * of data that needs to be read exceeds 256 bytes, recv data command /data that needs to be read/data to be read/ > + * word needs to be written to TXFIFO multiple times. > + * > + * So when in RX DMA mode, the TX channel also needs to be configured > + * additionally to send RX command words and the RX command word need /additionally// /need/must/ > + * be set in advance before transmitting. > + */ > +static int lpi2c_imx_dma_xfer(struct lpi2c_imx_struct *lpi2c_imx, > + struct i2c_msg *msg) The alignemnt here is off (did you run checkpatch.pl?) > +{ > + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; > + int ret; > + > + /* When DMA mode failed before transferring, CPU mode can be used. */ /failed/fails/ > + dma->using_pio_mode = true; > + > + dma->dma_len = msg->len; > + dma->dma_msg_flag = msg->flags; > + dma->dma_buf = i2c_get_dma_safe_msg_buf(msg, I2C_DMA_THRESHOLD); > + if (!dma->dma_buf) > + return -ENOMEM; > + > + ret = lpi2c_dma_config(lpi2c_imx); > + if (ret) { > + dev_err(&lpi2c_imx->adapter.dev, "DMA Config Fail, error %d\n", ret); Please rephrase as: ... "Failed to configure DMA (%d)\n", ret); > + goto disable_dma; > + } > + > + lpi2c_dma_enable(lpi2c_imx); > + > + ret = lpi2c_dma_submit(lpi2c_imx); > + if (ret) { > + dev_err(&lpi2c_imx->adapter.dev, "DMA submit Fail, error %d\n", ret); Please rephrase as: ... "DMA submission failed (%d)\n", ret); > + goto disable_dma; > + } > + > + if (dma->dma_msg_flag & I2C_M_RD) { > + ret = lpi2c_imx_alloc_rx_cmd_buf(lpi2c_imx); > + if (ret) { > + lpi2c_cleanup_dma(dma); > + goto disable_dma; > + } > + > + ret = lpi2c_dma_rx_cmd_submit(lpi2c_imx); > + if (ret) { > + lpi2c_cleanup_dma(dma); > + goto disable_dma; > + } > + } > + > + ret = lpi2c_imx_dma_msg_complete(lpi2c_imx); > + if (ret) { > + if (dma->dma_msg_flag & I2C_M_RD) > + lpi2c_cleanup_rx_cmd_dma(dma); > + lpi2c_cleanup_dma(dma); > + goto disable_dma; > + } > + > + /* When meet NACK in transfer, cleanup all DMA transfer */ Please rephrase as: /* When encountering NACK in transfer, clean up all DMA transfers */ > + if ((readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) && !ret) { > + if (dma->dma_msg_flag & I2C_M_RD) > + lpi2c_cleanup_rx_cmd_dma(dma); > + lpi2c_cleanup_dma(dma); > + ret = -EIO; > + goto disable_dma; > + } > + > + if (dma->dma_msg_flag & I2C_M_RD) > + dma_unmap_single(dma->chan_tx->device->dev, dma->dma_tx_addr, > + dma->rx_cmd_buf_len, DMA_TO_DEVICE); > + lpi2c_dma_unmap(dma); > + you could add here: disable_cleanup_dma: lpi2c_cleanup_dma(dma); and goto here instead of calling lpi2c_cleanup_dma(dma) at each phase. > +disable_dma: > + /* Disable I2C DMA function */ > + writel(0, lpi2c_imx->base + LPI2C_MDER); > + > + if (dma->dma_msg_flag & I2C_M_RD) > + kfree(dma->rx_cmd_buf); > + > + if (ret) > + i2c_put_dma_safe_msg_buf(dma->dma_buf, msg, false); > + else > + i2c_put_dma_safe_msg_buf(dma->dma_buf, msg, true); I could leave a blank line here to put some space between if...else and return. > + return ret; > +} ... Thanks, Andi