mbox series

[V2,00/18] i2c: imx-lpi2c: New features and bug fixes

Message ID 20210406113306.2633595-1-xiaoning.wang@nxp.com
Headers show
Series i2c: imx-lpi2c: New features and bug fixes | expand

Message

Clark Wang April 6, 2021, 11:32 a.m. UTC
Hi,

According to V1's feedback, V2 has been modified.
For summary of the changes, please refer to the header of each patch file.

Added some dt-bindings and dts patches.
At the same time, a patch has been added to fix the problem that data larger
than 256 bytes cannot be sent in one frame in PIO mode.

Clark Wang (14):
  i2c: imx-lpi2c: add ipg clk for lpi2c driver
  ARM: dts: imx7ulp: add the missing lpi2c ipg clock
  ARM: dts: imx7ulp: add the missing lpi2c nodes
  ARM64: dts: imx8: add the missing lpi2c ipg clock
  ARM64: dts: imx8: change i2c irq number to non-combined
  i2c: imx-lpi2c: increase PM timeout to avoid operate clk frequently
  i2c: imx-lpi2c: add bus recovery feature
  dt-bindings: i2c: imx-lpi2c: Add bus recovery example
  i2c: imx-lpi2c: fix i2c timing issue
  i2c: imx-lpi2c: fix type char overflow issue when calculating the
    clock cycle
  i2c: imx-lpi2c: add edma mode support
  dt-bindings: i2c: imx-lpi2c: Add dma configuration example
  ARM: dts: imx7ulp: add dma configurations for lpi2c
  ARM: dts: imx7ulp: add the missing status property of lpi2c5
  i2c: imx-lpi2c: fix pio mode cannot send 256+ bytes in one frame

Fugang Duan (1):
  i2c: imx-lpi2c: manage irq resource request/release in runtime pm

Gao Pan (2):
  i2c: imx-lpi2c: directly retrun ISR when detect a NACK
  i2c: imx-lpi2c: add debug message when i2c peripheral clk doesn't work

 .../bindings/i2c/i2c-imx-lpi2c.yaml           |  26 +
 arch/arm/boot/dts/imx7ulp.dtsi                |  50 +-
 .../arm64/boot/dts/freescale/imx8-ss-dma.dtsi |  32 +-
 drivers/i2c/busses/i2c-imx-lpi2c.c            | 506 ++++++++++++++++--
 4 files changed, 548 insertions(+), 66 deletions(-)

Comments

Clark Wang April 6, 2021, 11:41 a.m. UTC | #1
> -----Original Message-----
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 19:33
> To: Aisheng Dong <aisheng.dong@nxp.com>; robh+dt@kernel.org;
> shawnguo@kernel.org; s.hauer@pengutronix.de; festevam@gmail.com
> Cc: kernel@pengutronix.de; dl-linux-imx <linux-imx@nxp.com>; linux-
> i2c@vger.kernel.org; devicetree@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: [PATCH V2 14/18] i2c: imx-lpi2c: add edma mode support
> 
> Add eDMA receive and send mode support.
> Support to read and write data larger than 256 bytes in one frame.
> 
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
> Reviewed-by: Li Jun <jun.li@nxp.com>
> ---
> V2 changes:
>  - change marco I2C_USE_PIO to DMA_ERR_I2C_USE_PIO. It is a error code
> defined
>    in this driver to

It is an error code defined in this driver to identify the DMA sending
error, then driver will try to use PIO to send data.

Best Regards,
Clark Wang
> ---
>  drivers/i2c/busses/i2c-imx-lpi2c.c | 290 ++++++++++++++++++++++++++++-
>  1 file changed, 288 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c
b/drivers/i2c/busses/i2c-imx-
> lpi2c.c
> index c2f8e49660ea..d1a56d52f19f 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>
>  #include <linux/err.h>
>  #include <linux/errno.h>
>  #include <linux/i2c.h>
> @@ -31,6 +33,7 @@
>  #define LPI2C_MCR	0x10	/* i2c contrl register */
>  #define LPI2C_MSR	0x14	/* i2c status register */
>  #define LPI2C_MIER	0x18	/* i2c interrupt enable */
> +#define LPI2C_MDER	0x1C	/* i2c DMA enable */
>  #define LPI2C_MCFGR0	0x20	/* i2c master configuration */
>  #define LPI2C_MCFGR1	0x24	/* i2c master configuration */
>  #define LPI2C_MCFGR2	0x28	/* i2c master configuration */
> @@ -72,11 +75,15 @@
>  #define MCFGR1_AUTOSTOP	BIT(8)
>  #define MCFGR1_IGNACK	BIT(9)
>  #define MRDR_RXEMPTY	BIT(14)
> +#define MDER_TDDE	BIT(0)
> +#define MDER_RDDE	BIT(1)
> 
>  #define I2C_CLK_RATIO	24 / 59
>  #define CHUNK_DATA	256
> 
>  #define I2C_PM_TIMEOUT		1000 /* ms */
> +#define I2C_DMA_THRESHOLD	16 /* bytes */
> +#define DMA_ERR_I2C_USE_PIO	(-150)
> 
>  enum lpi2c_imx_mode {
>  	STANDARD,	/* <=100Kbps */
> @@ -95,6 +102,7 @@ enum lpi2c_imx_pincfg {
> 
>  struct lpi2c_imx_struct {
>  	struct i2c_adapter	adapter;
> +	resource_size_t		phy_addr;
>  	int			irq;
>  	struct clk		*clk_per;
>  	struct clk		*clk_ipg;
> @@ -114,6 +122,17 @@ struct lpi2c_imx_struct {
>  	struct pinctrl *pinctrl;
>  	struct pinctrl_state *pinctrl_pins_default;
>  	struct pinctrl_state *pinctrl_pins_gpio;
> +
> +	bool			can_use_dma;
> +	bool			using_dma;
> +	bool			xferred;
> +	struct i2c_msg		*msg;
> +	dma_addr_t		dma_addr;
> +	struct dma_chan		*dma_tx;
> +	struct dma_chan		*dma_rx;
> +	enum dma_data_direction dma_direction;
> +	u8			*dma_buf;
> +	unsigned int		dma_len;
>  };
> 
>  static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx, @@
-289,6
> +308,9 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct
> *lpi2c_imx)
>  	if (ret)
>  		goto rpm_put;
> 
> +	if (lpi2c_imx->can_use_dma)
> +		writel(MDER_TDDE | MDER_RDDE, lpi2c_imx->base +
> LPI2C_MDER);
> +
>  	temp = readl(lpi2c_imx->base + LPI2C_MCR);
>  	temp |= MCR_MEN;
>  	writel(temp, lpi2c_imx->base + LPI2C_MCR); @@ -462,6 +484,154 @@
> static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
>  	lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);  }
> 
> +static void lpi2c_dma_unmap(struct lpi2c_imx_struct *lpi2c_imx) {
> +	struct dma_chan *chan = lpi2c_imx->dma_direction ==
> DMA_FROM_DEVICE
> +				? lpi2c_imx->dma_rx : lpi2c_imx->dma_tx;
> +
> +	dma_unmap_single(chan->device->dev, lpi2c_imx->dma_addr,
> +			 lpi2c_imx->dma_len, lpi2c_imx->dma_direction);
> +
> +	lpi2c_imx->dma_direction = DMA_NONE;
> +}
> +
> +static void lpi2c_cleanup_dma(struct lpi2c_imx_struct *lpi2c_imx) {
> +	if (lpi2c_imx->dma_direction == DMA_NONE)
> +		return;
> +	else if (lpi2c_imx->dma_direction == DMA_FROM_DEVICE)
> +		dmaengine_terminate_all(lpi2c_imx->dma_rx);
> +	else if (lpi2c_imx->dma_direction == DMA_TO_DEVICE)
> +		dmaengine_terminate_all(lpi2c_imx->dma_tx);
> +
> +	lpi2c_dma_unmap(lpi2c_imx);
> +}
> +
> +static void lpi2c_dma_callback(void *data) {
> +	struct lpi2c_imx_struct *lpi2c_imx = (struct lpi2c_imx_struct
*)data;
> +
> +	lpi2c_dma_unmap(lpi2c_imx);
> +	writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
> +	lpi2c_imx->xferred = true;
> +
> +	complete(&lpi2c_imx->complete);
> +}
> +
> +static int lpi2c_dma_submit(struct lpi2c_imx_struct *lpi2c_imx,
> +			   struct i2c_msg *msg)
> +{
> +	bool read = msg->flags & I2C_M_RD;
> +	enum dma_data_direction dir = read ? DMA_FROM_DEVICE :
> DMA_TO_DEVICE;
> +	struct dma_chan *chan = read ? lpi2c_imx->dma_rx :
lpi2c_imx->dma_tx;
> +	struct dma_async_tx_descriptor *txdesc;
> +	dma_cookie_t cookie;
> +
> +	lpi2c_imx->dma_len = read ? msg->len - 1 : msg->len;
> +	lpi2c_imx->msg = msg;
> +	lpi2c_imx->dma_direction = dir;
> +
> +	if (IS_ERR(chan))
> +		return PTR_ERR(chan);
> +
> +	lpi2c_imx->dma_addr = dma_map_single(chan->device->dev,
> +					     lpi2c_imx->dma_buf,
> +					     lpi2c_imx->dma_len, dir);
> +	if (dma_mapping_error(chan->device->dev, lpi2c_imx->dma_addr)) {
> +		dev_err(&lpi2c_imx->adapter.dev, "dma map failed, use
pio\n");
> +		return -EINVAL;
> +	}
> +
> +	txdesc = dmaengine_prep_slave_single(chan, lpi2c_imx->dma_addr,
> +					lpi2c_imx->dma_len, read ?
> +					DMA_DEV_TO_MEM :
> DMA_MEM_TO_DEV,
> +					DMA_PREP_INTERRUPT |
> DMA_CTRL_ACK);
> +	if (!txdesc) {
> +		dev_err(&lpi2c_imx->adapter.dev, "dma prep slave sg failed,
> use pio\n");
> +		lpi2c_cleanup_dma(lpi2c_imx);
> +		return -EINVAL;
> +	}
> +
> +	reinit_completion(&lpi2c_imx->complete);
> +	txdesc->callback = lpi2c_dma_callback;
> +	txdesc->callback_param = (void *)lpi2c_imx;
> +
> +	cookie = dmaengine_submit(txdesc);
> +	if (dma_submit_error(cookie)) {
> +		dev_err(&lpi2c_imx->adapter.dev, "submitting dma failed, use
> pio\n");
> +		lpi2c_cleanup_dma(lpi2c_imx);
> +		return -EINVAL;
> +	}
> +
> +	lpi2c_imx_intctrl(lpi2c_imx, MIER_NDIE);
> +
> +	dma_async_issue_pending(chan);
> +
> +	return 0;
> +}
> +
> +static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct
> +i2c_msg *msg) {
> +	if (!lpi2c_imx->can_use_dma)
> +		return false;
> +
> +	if (msg->len < I2C_DMA_THRESHOLD)
> +		return false;
> +
> +	return true;
> +}
> +
> +static int lpi2c_imx_dma_push_rx_cmd(struct lpi2c_imx_struct *lpi2c_imx,
> +				 struct i2c_msg *msg)
> +{
> +	unsigned int temp, rx_remain;
> +	unsigned long orig_jiffies = jiffies;
> +
> +	if ((msg->flags & I2C_M_RD)) {
> +		rx_remain = msg->len;
> +		do {
> +			temp = rx_remain > CHUNK_DATA ?
> +				CHUNK_DATA - 1 : rx_remain - 1;
> +			temp |= (RECV_DATA << 8);
> +			while ((readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff)
>
> (lpi2c_imx->rxfifosize >> 1)) {
> +				if (time_after(jiffies, orig_jiffies +
> msecs_to_jiffies(1000))) {
> +					dev_dbg(&lpi2c_imx->adapter.dev,
> "txfifo empty timeout\n");
> +					if (lpi2c_imx-
> >adapter.bus_recovery_info)
> +						i2c_recover_bus(&lpi2c_imx-
> >adapter);
> +					return -ETIMEDOUT;
> +				}
> +				schedule();
> +			}
> +			writel(temp, lpi2c_imx->base + LPI2C_MTDR);
> +			rx_remain = rx_remain - (temp & 0xff) - 1;
> +		} while (rx_remain > 0);
> +	}
> +
> +	return 0;
> +}
> +
> +static int lpi2c_dma_xfer(struct lpi2c_imx_struct *lpi2c_imx,
> +			   struct i2c_msg *msg)
> +{
> +	int result;
> +
> +	result = lpi2c_dma_submit(lpi2c_imx, msg);
> +	if (!result) {
> +		result = lpi2c_imx_dma_push_rx_cmd(lpi2c_imx, msg);
> +		if (result)
> +			return result;
> +		result = lpi2c_imx_msg_complete(lpi2c_imx);
> +		return result;
> +	}
> +
> +	/* DMA xfer failed, try to use PIO, clean up dma things */
> +	i2c_put_dma_safe_msg_buf(lpi2c_imx->dma_buf, lpi2c_imx->msg,
> +				 lpi2c_imx->xferred);
> +	lpi2c_cleanup_dma(lpi2c_imx);
> +
> +	return DMA_ERR_I2C_USE_PIO;
> +}
> +
>  static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
>  			  struct i2c_msg *msgs, int num)
>  {
> @@ -474,6 +644,9 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
>  		return result;
> 
>  	for (i = 0; i < num; i++) {
> +		lpi2c_imx->xferred = false;
> +		lpi2c_imx->using_dma = false;
> +
>  		result = lpi2c_imx_start(lpi2c_imx, &msgs[i]);
>  		if (result)
>  			goto disable;
> @@ -482,9 +655,24 @@ static int lpi2c_imx_xfer(struct i2c_adapter
*adapter,
>  		if (num == 1 && msgs[0].len == 0)
>  			goto stop;
> 
> +		if (is_use_dma(lpi2c_imx, &msgs[i])) {
> +			lpi2c_imx->using_dma = true;
> +
> +			writel(0x1, lpi2c_imx->base + LPI2C_MFCR);
> +
> +			lpi2c_imx->dma_buf =
> i2c_get_dma_safe_msg_buf(&msgs[i],
> +
> I2C_DMA_THRESHOLD);
> +			if (lpi2c_imx->dma_buf) {
> +				result = lpi2c_dma_xfer(lpi2c_imx,
&msgs[i]);
> +				if (result != DMA_ERR_I2C_USE_PIO)
> +					goto stop;
> +			}
> +		}
> +
> +		lpi2c_imx->using_dma = false;
>  		lpi2c_imx->delivered = 0;
>  		lpi2c_imx->msglen = msgs[i].len;
> -		init_completion(&lpi2c_imx->complete);
> +		reinit_completion(&lpi2c_imx->complete);
> 
>  		if (msgs[i].flags & I2C_M_RD)
>  			lpi2c_imx_read(lpi2c_imx, &msgs[i]); @@ -503,7
> +691,16 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
>  	}
> 
>  stop:
> -	lpi2c_imx_stop(lpi2c_imx);
> +	if (!lpi2c_imx->using_dma)
> +		lpi2c_imx_stop(lpi2c_imx);
> +	else {
> +		i2c_put_dma_safe_msg_buf(lpi2c_imx->dma_buf, lpi2c_imx-
> >msg,
> +					 lpi2c_imx->xferred);
> +		if (result) {
> +			lpi2c_cleanup_dma(lpi2c_imx);
> +			writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
> +		}
> +	}
> 
>  	temp = readl(lpi2c_imx->base + LPI2C_MSR);
>  	if ((temp & MSR_NDF) && !result)
> @@ -528,6 +725,10 @@ static irqreturn_t lpi2c_imx_isr(int irq, void
*dev_id)
>  	temp = readl(lpi2c_imx->base + LPI2C_MSR);
> 
>  	if (temp & MSR_NDF) {
> +		if (lpi2c_imx->using_dma) {
> +			lpi2c_cleanup_dma(lpi2c_imx);
> +			writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
> +		}
>  		complete(&lpi2c_imx->complete);
>  		goto ret;
>  	}
> @@ -623,6 +824,77 @@ static const struct of_device_id lpi2c_imx_of_match[]
> = {  };  MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
> 
> +static void lpi2c_dma_exit(struct lpi2c_imx_struct *lpi2c_imx) {
> +	if (lpi2c_imx->dma_rx) {
> +		dma_release_channel(lpi2c_imx->dma_rx);
> +		lpi2c_imx->dma_rx = NULL;
> +	}
> +
> +	if (lpi2c_imx->dma_tx) {
> +		dma_release_channel(lpi2c_imx->dma_tx);
> +		lpi2c_imx->dma_tx = NULL;
> +	}
> +}
> +
> +static int lpi2c_dma_init(struct device *dev,
> +			  struct lpi2c_imx_struct *lpi2c_imx) {
> +	int ret;
> +	struct dma_slave_config dma_sconfig;
> +
> +	/* Prepare for TX DMA: */
> +	lpi2c_imx->dma_tx = dma_request_chan(dev, "tx");
> +	if (IS_ERR(lpi2c_imx->dma_tx)) {
> +		ret = PTR_ERR(lpi2c_imx->dma_tx);
> +		dev_err(dev, "can't get the TX DMA channel, error %d!\n",
ret);
> +		lpi2c_imx->dma_tx = NULL;
> +		goto err;
> +	}
> +
> +	dma_sconfig.dst_addr = lpi2c_imx->phy_addr + LPI2C_MTDR;
> +	dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +	dma_sconfig.dst_maxburst = 1;
> +	dma_sconfig.direction = DMA_MEM_TO_DEV;
> +	ret = dmaengine_slave_config(lpi2c_imx->dma_tx, &dma_sconfig);
> +	if (ret < 0) {
> +		dev_err(dev, "can't configure tx channel (%d)\n", ret);
> +		goto fail_tx;
> +	}
> +
> +	/* Prepare for RX DMA: */
> +	lpi2c_imx->dma_rx = dma_request_chan(dev, "rx");
> +	if (IS_ERR(lpi2c_imx->dma_rx)) {
> +		ret = PTR_ERR(lpi2c_imx->dma_rx);
> +		dev_err(dev, "can't get the RX DMA channel, error %d\n",
ret);
> +		lpi2c_imx->dma_rx = NULL;
> +		goto fail_tx;
> +	}
> +
> +	dma_sconfig.src_addr = lpi2c_imx->phy_addr + LPI2C_MRDR;
> +	dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +	dma_sconfig.src_maxburst = 1;
> +	dma_sconfig.direction = DMA_DEV_TO_MEM;
> +	ret = dmaengine_slave_config(lpi2c_imx->dma_rx, &dma_sconfig);
> +	if (ret < 0) {
> +		dev_err(dev, "can't configure rx channel (%d)\n", ret);
> +		goto fail_rx;
> +	}
> +
> +	lpi2c_imx->can_use_dma = true;
> +	lpi2c_imx->using_dma = false;
> +
> +	return 0;
> +fail_rx:
> +	dma_release_channel(lpi2c_imx->dma_rx);
> +fail_tx:
> +	dma_release_channel(lpi2c_imx->dma_tx);
> +err:
> +	lpi2c_dma_exit(lpi2c_imx);
> +	lpi2c_imx->can_use_dma = false;
> +	return ret;
> +}
> +
>  static int lpi2c_imx_clocks_prepare(struct lpi2c_imx_struct *lpi2c_imx)
{
>  	int ret = 0;
> @@ -656,15 +928,18 @@ static int lpi2c_imx_probe(struct platform_device
> *pdev)
>  	struct lpi2c_imx_struct *lpi2c_imx;
>  	unsigned int temp;
>  	int ret;
> +	struct resource *res;
> 
>  	lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx),
GFP_KERNEL);
>  	if (!lpi2c_imx)
>  		return -ENOMEM;
> 
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	lpi2c_imx->base = devm_platform_ioremap_resource(pdev, 0);
>  	if (IS_ERR(lpi2c_imx->base))
>  		return PTR_ERR(lpi2c_imx->base);
> 
> +	lpi2c_imx->phy_addr = (dma_addr_t)res->start;
>  	lpi2c_imx->irq = platform_get_irq(pdev, 0);
>  	if (lpi2c_imx->irq < 0)
>  		return lpi2c_imx->irq;
> @@ -716,6 +991,17 @@ static int lpi2c_imx_probe(struct platform_device
> *pdev)
>  	if (ret == -EPROBE_DEFER)
>  		goto rpm_disable;
> 
> +	/* Init DMA */
> +	lpi2c_imx->dma_direction = DMA_NONE;
> +	ret = lpi2c_dma_init(&pdev->dev, lpi2c_imx);
> +	if (ret) {
> +		dev_err_probe(&pdev->dev, ret, "dma setup error %d, use
> pio\n", ret);
> +		if (ret == -EPROBE_DEFER)
> +			goto rpm_disable;
> +	}
> +
> +	init_completion(&lpi2c_imx->complete);
> +
>  	ret = i2c_add_adapter(&lpi2c_imx->adapter);
>  	if (ret)
>  		goto rpm_disable;
> --
> 2.25.1
Shawn Guo May 11, 2021, 2:59 a.m. UTC | #2
On Tue, Apr 06, 2021 at 07:32:53PM +0800, Clark Wang wrote:
> The lpi2c driver has add the missing ipg clock.
> So add the ipg clock here for all lpi2c nodes.
> 
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>

Historically, we use 'arm64: dts: ...' as subject prefix for arm64 DTS
patch, and 'ARM: dts: ...' for arm.

Shawn

> ---
> V2 changes:
>  - New patch added in V2
> ---
>  .../arm64/boot/dts/freescale/imx8-ss-dma.dtsi | 24 ++++++++++++-------
>  1 file changed, 16 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> index 960a802b8b6e..b5ed12a06538 100644
> --- a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> @@ -111,8 +111,10 @@ uart3_lpcg: clock-controller@5a490000 {
>  	i2c0: i2c@5a800000 {
>  		reg = <0x5a800000 0x4000>;
>  		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
> -		clocks = <&i2c0_lpcg IMX_LPCG_CLK_0>;
> -		clock-names = "per";
> +		interrupt-parent = <&gic>;
> +		clocks = <&i2c0_lpcg IMX_LPCG_CLK_0>,
> +			 <&i2c0_lpcg IMX_LPCG_CLK_4>;
> +		clock-names = "per", "ipg";
>  		assigned-clocks = <&clk IMX_SC_R_I2C_0 IMX_SC_PM_CLK_PER>;
>  		assigned-clock-rates = <24000000>;
>  		power-domains = <&pd IMX_SC_R_I2C_0>;
> @@ -122,8 +124,10 @@ i2c0: i2c@5a800000 {
>  	i2c1: i2c@5a810000 {
>  		reg = <0x5a810000 0x4000>;
>  		interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
> -		clocks = <&i2c1_lpcg IMX_LPCG_CLK_0>;
> -		clock-names = "per";
> +		interrupt-parent = <&gic>;
> +		clocks = <&i2c1_lpcg IMX_LPCG_CLK_0>,
> +			 <&i2c1_lpcg IMX_LPCG_CLK_4>;
> +		clock-names = "per", "ipg";
>  		assigned-clocks = <&clk IMX_SC_R_I2C_1 IMX_SC_PM_CLK_PER>;
>  		assigned-clock-rates = <24000000>;
>  		power-domains = <&pd IMX_SC_R_I2C_1>;
> @@ -133,8 +137,10 @@ i2c1: i2c@5a810000 {
>  	i2c2: i2c@5a820000 {
>  		reg = <0x5a820000 0x4000>;
>  		interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
> -		clocks = <&i2c2_lpcg IMX_LPCG_CLK_0>;
> -		clock-names = "per";
> +		interrupt-parent = <&gic>;
> +		clocks = <&i2c2_lpcg IMX_LPCG_CLK_0>,
> +			 <&i2c2_lpcg IMX_LPCG_CLK_4>;
> +		clock-names = "per", "ipg";
>  		assigned-clocks = <&clk IMX_SC_R_I2C_2 IMX_SC_PM_CLK_PER>;
>  		assigned-clock-rates = <24000000>;
>  		power-domains = <&pd IMX_SC_R_I2C_2>;
> @@ -144,8 +150,10 @@ i2c2: i2c@5a820000 {
>  	i2c3: i2c@5a830000 {
>  		reg = <0x5a830000 0x4000>;
>  		interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
> -		clocks = <&i2c3_lpcg IMX_LPCG_CLK_0>;
> -		clock-names = "per";
> +		interrupt-parent = <&gic>;
> +		clocks = <&i2c3_lpcg IMX_LPCG_CLK_0>,
> +			 <&i2c3_lpcg IMX_LPCG_CLK_4>;
> +		clock-names = "per", "ipg";
>  		assigned-clocks = <&clk IMX_SC_R_I2C_3 IMX_SC_PM_CLK_PER>;
>  		assigned-clock-rates = <24000000>;
>  		power-domains = <&pd IMX_SC_R_I2C_3>;
> -- 
> 2.25.1
>
Aisheng Dong May 21, 2021, 6:14 a.m. UTC | #3
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 7:33 PM
> 
> The lpi2c IP needs two clks: ipg clk and per clk. The old lpi2c driver missed ipg
> clk. This patch adds ipg clk for lpi2c driver.
> 
> Signed-off-by: Gao Pan <pandy.gao@nxp.com>
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
> Acked-by: Fugang Duan <fugang.duan@nxp.com>

You can drop the original Ack or signed-off if there're significant changes

BTW, please move the binding doc change before this patch.

> ---
> V2 changes:
>  - Merge two clocks' prepare funtions to lpi2c_imx_clocks_prepare().
> ---
>  drivers/i2c/busses/i2c-imx-lpi2c.c | 61 +++++++++++++++++++++---------
>  1 file changed, 44 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c
> b/drivers/i2c/busses/i2c-imx-lpi2c.c
> index bbf44ac95021..89b7b0795f51 100644
> --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> @@ -94,7 +94,8 @@ enum lpi2c_imx_pincfg {
> 
>  struct lpi2c_imx_struct {
>  	struct i2c_adapter	adapter;
> -	struct clk		*clk;
> +	struct clk		*clk_per;
> +	struct clk		*clk_ipg;
>  	void __iomem		*base;
>  	__u8			*rx_buf;
>  	__u8			*tx_buf;
> @@ -207,7 +208,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct
> *lpi2c_imx)
> 
>  	lpi2c_imx_set_mode(lpi2c_imx);
> 
> -	clk_rate = clk_get_rate(lpi2c_imx->clk);
> +	clk_rate = clk_get_rate(lpi2c_imx->clk_per);
>  	if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
>  		filt = 0;
>  	else
> @@ -538,6 +539,34 @@ static const struct of_device_id lpi2c_imx_of_match[]
> = {  };  MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
> 
> +static int lpi2c_imx_clocks_prepare(struct lpi2c_imx_struct *lpi2c_imx)
> +{
> +	int ret = 0;

Unnecessary initialization

> +
> +	ret = clk_prepare_enable(lpi2c_imx->clk_per);
> +	if (ret) {
> +		dev_err(lpi2c_imx->adapter.dev.parent,
> +				"can't enable I2C per clock, ret=%d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(lpi2c_imx->clk_ipg);
> +	if (ret) {
> +		clk_disable_unprepare(lpi2c_imx->clk_per);
> +		dev_err(lpi2c_imx->adapter.dev.parent,
> +				"can't enable I2C ipg clock, ret=%d\n", ret);
> +		return ret;
> +	}
> +
> +	return ret;

Return 0

> +}
> +
> +static void lpi2c_imx_clocks_unprepare(struct lpi2c_imx_struct
> +*lpi2c_imx) {
> +	clk_disable_unprepare(lpi2c_imx->clk_ipg);
> +	clk_disable_unprepare(lpi2c_imx->clk_per);
> +}
> +
>  static int lpi2c_imx_probe(struct platform_device *pdev)  {
>  	struct lpi2c_imx_struct *lpi2c_imx;
> @@ -563,10 +592,16 @@ static int lpi2c_imx_probe(struct platform_device
> *pdev)
>  	strlcpy(lpi2c_imx->adapter.name, pdev->name,
>  		sizeof(lpi2c_imx->adapter.name));
> 
> -	lpi2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
> -	if (IS_ERR(lpi2c_imx->clk)) {
> +	lpi2c_imx->clk_per = devm_clk_get(&pdev->dev, "per");
> +	if (IS_ERR(lpi2c_imx->clk_per)) {
>  		dev_err(&pdev->dev, "can't get I2C peripheral clock\n");
> -		return PTR_ERR(lpi2c_imx->clk);
> +		return PTR_ERR(lpi2c_imx->clk_per);
> +	}

Will this patch break imx7ulp which doesn't have per clock?

> +
> +	lpi2c_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
> +	if (IS_ERR(lpi2c_imx->clk_ipg)) {
> +		dev_err(&pdev->dev, "can't get I2C ipg clock\n");
> +		return PTR_ERR(lpi2c_imx->clk_ipg);
>  	}
> 
>  	ret = of_property_read_u32(pdev->dev.of_node,
> @@ -584,11 +619,9 @@ static int lpi2c_imx_probe(struct platform_device
> *pdev)
>  	i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
>  	platform_set_drvdata(pdev, lpi2c_imx);
> 
> -	ret = clk_prepare_enable(lpi2c_imx->clk);
> -	if (ret) {
> -		dev_err(&pdev->dev, "clk enable failed %d\n", ret);
> +	ret = lpi2c_imx_clocks_prepare(lpi2c_imx);
> +	if (ret)
>  		return ret;
> -	}
> 
>  	pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
>  	pm_runtime_use_autosuspend(&pdev->dev);
> @@ -635,7 +668,7 @@ static int __maybe_unused
> lpi2c_runtime_suspend(struct device *dev)  {
>  	struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
> 
> -	clk_disable_unprepare(lpi2c_imx->clk);
> +	lpi2c_imx_clocks_unprepare(lpi2c_imx);
>  	pinctrl_pm_select_sleep_state(dev);
> 
>  	return 0;
> @@ -644,16 +677,10 @@ static int __maybe_unused
> lpi2c_runtime_suspend(struct device *dev)  static int __maybe_unused
> lpi2c_runtime_resume(struct device *dev)  {
>  	struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
> -	int ret;
> 
>  	pinctrl_pm_select_default_state(dev);
> -	ret = clk_prepare_enable(lpi2c_imx->clk);
> -	if (ret) {
> -		dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
> -		return ret;
> -	}
> 
> -	return 0;
> +	return lpi2c_imx_clocks_prepare(lpi2c_imx);
>  }
> 
>  static const struct dev_pm_ops lpi2c_pm_ops = {
> --
> 2.25.1
Aisheng Dong May 21, 2021, 6:17 a.m. UTC | #4
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 7:33 PM
> 
> The lpi2c driver has add the missing ipg clock.

Pls drop this line as binding is not decided by driver 

> So add the ipg clock here for all lpi2c nodes.

Per clock?

Maybe better refined as add the missing per clock ....

> 
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
> ---
> V2 changes:
>  - New patch added in V2
> ---
>  arch/arm/boot/dts/imx7ulp.dtsi | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi
> index b7ea37ad4e55..eb0d4b8f624d 100644
> --- a/arch/arm/boot/dts/imx7ulp.dtsi
> +++ b/arch/arm/boot/dts/imx7ulp.dtsi
> @@ -328,8 +328,9 @@ lpi2c6: i2c@40a40000 {
>  			compatible = "fsl,imx7ulp-lpi2c";
>  			reg = <0x40a40000 0x10000>;
>  			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
> -			clocks = <&pcc3 IMX7ULP_CLK_LPI2C6>;
> -			clock-names = "ipg";
> +			clocks = <&pcc3 IMX7ULP_CLK_LPI2C6>,
> +				 <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>;
> +			clock-names = "per", "ipg";
>  			assigned-clocks = <&pcc3 IMX7ULP_CLK_LPI2C6>;
>  			assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
>  			assigned-clock-rates = <48000000>;
> @@ -340,8 +341,9 @@ lpi2c7: i2c@40a50000 {
>  			compatible = "fsl,imx7ulp-lpi2c";
>  			reg = <0x40a50000 0x10000>;
>  			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> -			clocks = <&pcc3 IMX7ULP_CLK_LPI2C7>;
> -			clock-names = "ipg";
> +			clocks = <&pcc3 IMX7ULP_CLK_LPI2C7>,
> +				 <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>;
> +			clock-names = "per", "ipg";
>  			assigned-clocks = <&pcc3 IMX7ULP_CLK_LPI2C7>;
>  			assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
>  			assigned-clock-rates = <48000000>;
> --
> 2.25.1
Aisheng Dong May 21, 2021, 6:25 a.m. UTC | #5
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 7:33 PM
> 
> Add the missing lpi2c4/5 nodes for imx7ulp.
> 
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
> ---
> V2 changes:
>  - New patch added in V2
> ---
>  arch/arm/boot/dts/imx7ulp.dtsi | 31 +++++++++++++++++++++++++++++--
>  1 file changed, 29 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi
> index eb0d4b8f624d..0c51fa79c0bc 100644
> --- a/arch/arm/boot/dts/imx7ulp.dtsi
> +++ b/arch/arm/boot/dts/imx7ulp.dtsi
> @@ -22,8 +22,10 @@ aliases {
>  		gpio1 = &gpio_ptd;
>  		gpio2 = &gpio_pte;
>  		gpio3 = &gpio_ptf;
> -		i2c0 = &lpi2c6;
> -		i2c1 = &lpi2c7;
> +		i2c0 = &lpi2c4;
> +		i2c1 = &lpi2c5;
> +		i2c2 = &lpi2c6;
> +		i2c3 = &lpi2c7;
>  		mmc0 = &usdhc0;
>  		mmc1 = &usdhc1;
>  		serial0 = &lpuart4;
> @@ -145,6 +147,31 @@ sec_jr1: jr@2000 {
>  			};
>  		};
> 
> +		lpi2c4: lpi2c4@402b0000 {

Generic node name is preferred. E.g. I2c@xxxxx

> +			compatible = "fsl,imx7ulp-lpi2c";
> +			reg = <0x402b0000 0x10000>;
> +			interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&pcc2 IMX7ULP_CLK_LPI2C4>,
> +				 <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>;
> +			clock-names = "per", "ipg";
> +			assigned-clocks = <&pcc2 IMX7ULP_CLK_LPI2C4>;
> +			assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
> +			assigned-clock-rates = <48000000>;
> +			status = "disabled";
> +		};
> +
> +		lpi2c5: lpi2c5@402c0000 {

Ditto

> +			compatible = "fsl,imx7ulp-lpi2c";
> +			reg = <0x402c0000 0x10000>;
> +			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&pcc2 IMX7ULP_CLK_LPI2C5>,
> +				 <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>;
> +			clock-names = "per", "ipg";
> +			assigned-clocks = <&pcc2 IMX7ULP_CLK_LPI2C5>;
> +			assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
> +			assigned-clock-rates = <48000000>;
> +		};
> +
>  		lpuart4: serial@402d0000 {
>  			compatible = "fsl,imx7ulp-lpuart";
>  			reg = <0x402d0000 0x1000>;
> --
> 2.25.1
Aisheng Dong May 21, 2021, 6:28 a.m. UTC | #6
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 7:33 PM
> 
> The lpi2c driver has add the missing ipg clock.
> So add the ipg clock here for all lpi2c nodes.
> 
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
> ---
> V2 changes:
>  - New patch added in V2
> ---
>  .../arm64/boot/dts/freescale/imx8-ss-dma.dtsi | 24 ++++++++++++-------
>  1 file changed, 16 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> index 960a802b8b6e..b5ed12a06538 100644
> --- a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> @@ -111,8 +111,10 @@ uart3_lpcg: clock-controller@5a490000 {
>  	i2c0: i2c@5a800000 {
>  		reg = <0x5a800000 0x4000>;
>  		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
> -		clocks = <&i2c0_lpcg IMX_LPCG_CLK_0>;
> -		clock-names = "per";
> +		interrupt-parent = <&gic>;

Added by mistake?

> +		clocks = <&i2c0_lpcg IMX_LPCG_CLK_0>,
> +			 <&i2c0_lpcg IMX_LPCG_CLK_4>;
> +		clock-names = "per", "ipg";
>  		assigned-clocks = <&clk IMX_SC_R_I2C_0 IMX_SC_PM_CLK_PER>;
>  		assigned-clock-rates = <24000000>;
>  		power-domains = <&pd IMX_SC_R_I2C_0>; @@ -122,8 +124,10 @@
> i2c0: i2c@5a800000 {
>  	i2c1: i2c@5a810000 {
>  		reg = <0x5a810000 0x4000>;
>  		interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
> -		clocks = <&i2c1_lpcg IMX_LPCG_CLK_0>;
> -		clock-names = "per";
> +		interrupt-parent = <&gic>;

Ditto

> +		clocks = <&i2c1_lpcg IMX_LPCG_CLK_0>,
> +			 <&i2c1_lpcg IMX_LPCG_CLK_4>;
> +		clock-names = "per", "ipg";
>  		assigned-clocks = <&clk IMX_SC_R_I2C_1 IMX_SC_PM_CLK_PER>;
>  		assigned-clock-rates = <24000000>;
>  		power-domains = <&pd IMX_SC_R_I2C_1>; @@ -133,8 +137,10 @@
> i2c1: i2c@5a810000 {
>  	i2c2: i2c@5a820000 {
>  		reg = <0x5a820000 0x4000>;
>  		interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
> -		clocks = <&i2c2_lpcg IMX_LPCG_CLK_0>;
> -		clock-names = "per";
> +		interrupt-parent = <&gic>;
> +		clocks = <&i2c2_lpcg IMX_LPCG_CLK_0>,
> +			 <&i2c2_lpcg IMX_LPCG_CLK_4>;
> +		clock-names = "per", "ipg";
>  		assigned-clocks = <&clk IMX_SC_R_I2C_2 IMX_SC_PM_CLK_PER>;
>  		assigned-clock-rates = <24000000>;
>  		power-domains = <&pd IMX_SC_R_I2C_2>; @@ -144,8 +150,10 @@
> i2c2: i2c@5a820000 {
>  	i2c3: i2c@5a830000 {
>  		reg = <0x5a830000 0x4000>;
>  		interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
> -		clocks = <&i2c3_lpcg IMX_LPCG_CLK_0>;
> -		clock-names = "per";
> +		interrupt-parent = <&gic>;
> +		clocks = <&i2c3_lpcg IMX_LPCG_CLK_0>,
> +			 <&i2c3_lpcg IMX_LPCG_CLK_4>;
> +		clock-names = "per", "ipg";
>  		assigned-clocks = <&clk IMX_SC_R_I2C_3 IMX_SC_PM_CLK_PER>;
>  		assigned-clock-rates = <24000000>;
>  		power-domains = <&pd IMX_SC_R_I2C_3>;
> --
> 2.25.1
Aisheng Dong May 21, 2021, 6:32 a.m. UTC | #7
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 7:33 PM
> 
> Combined interrupt number may cause unexcepted irq event when using DMA
> and too many interrupts will be generated.
> So change all i2c interrupts number to non-combined for imx8qxp/8qm/8dxl.

Still no mx8dxl support in upstream, I guess imx8 is enough.
BTW, pls changing tile format as below as pointed by Shawn in another patch:
arm64: dts: xxxx

Otherwise:
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>

Regards
Aisheng

> 
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
> ---
> V2 changes:
>  - New patch added in V2
> ---
>  arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> index b5ed12a06538..9ba57f04859b 100644
> --- a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
> @@ -110,7 +110,7 @@ uart3_lpcg: clock-controller@5a490000 {
> 
>  	i2c0: i2c@5a800000 {
>  		reg = <0x5a800000 0x4000>;
> -		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupts = <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>;
>  		interrupt-parent = <&gic>;
>  		clocks = <&i2c0_lpcg IMX_LPCG_CLK_0>,
>  			 <&i2c0_lpcg IMX_LPCG_CLK_4>;
> @@ -123,7 +123,7 @@ i2c0: i2c@5a800000 {
> 
>  	i2c1: i2c@5a810000 {
>  		reg = <0x5a810000 0x4000>;
> -		interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>;
>  		interrupt-parent = <&gic>;
>  		clocks = <&i2c1_lpcg IMX_LPCG_CLK_0>,
>  			 <&i2c1_lpcg IMX_LPCG_CLK_4>;
> @@ -136,7 +136,7 @@ i2c1: i2c@5a810000 {
> 
>  	i2c2: i2c@5a820000 {
>  		reg = <0x5a820000 0x4000>;
> -		interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupts = <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>;
>  		interrupt-parent = <&gic>;
>  		clocks = <&i2c2_lpcg IMX_LPCG_CLK_0>,
>  			 <&i2c2_lpcg IMX_LPCG_CLK_4>;
> @@ -149,7 +149,7 @@ i2c2: i2c@5a820000 {
> 
>  	i2c3: i2c@5a830000 {
>  		reg = <0x5a830000 0x4000>;
> -		interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupts = <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>;
>  		interrupt-parent = <&gic>;
>  		clocks = <&i2c3_lpcg IMX_LPCG_CLK_0>,
>  			 <&i2c3_lpcg IMX_LPCG_CLK_4>;
> --
> 2.25.1
Aisheng Dong May 21, 2021, 6:38 a.m. UTC | #8
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 7:33 PM
> 
> Manage irq resource request/release in runtime pm to save irq domain's
> power.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>

Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>

Regards
Aisheng

> ---
> V2 changes:
>  - Change to use request_irq/free_irq.
> ---
>  drivers/i2c/busses/i2c-imx-lpi2c.c | 30 ++++++++++++++++++------------
>  1 file changed, 18 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c
> b/drivers/i2c/busses/i2c-imx-lpi2c.c
> index 89b7b0795f51..333209ba81c1 100644
> --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> @@ -94,6 +94,7 @@ enum lpi2c_imx_pincfg {
> 
>  struct lpi2c_imx_struct {
>  	struct i2c_adapter	adapter;
> +	int			irq;
>  	struct clk		*clk_per;
>  	struct clk		*clk_ipg;
>  	void __iomem		*base;
> @@ -571,7 +572,7 @@ static int lpi2c_imx_probe(struct platform_device
> *pdev)  {
>  	struct lpi2c_imx_struct *lpi2c_imx;
>  	unsigned int temp;
> -	int irq, ret;
> +	int ret;
> 
>  	lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL);
>  	if (!lpi2c_imx)
> @@ -581,9 +582,9 @@ static int lpi2c_imx_probe(struct platform_device
> *pdev)
>  	if (IS_ERR(lpi2c_imx->base))
>  		return PTR_ERR(lpi2c_imx->base);
> 
> -	irq = platform_get_irq(pdev, 0);
> -	if (irq < 0)
> -		return irq;
> +	lpi2c_imx->irq = platform_get_irq(pdev, 0);
> +	if (lpi2c_imx->irq < 0)
> +		return lpi2c_imx->irq;
> 
>  	lpi2c_imx->adapter.owner	= THIS_MODULE;
>  	lpi2c_imx->adapter.algo		= &lpi2c_imx_algo;
> @@ -609,13 +610,6 @@ static int lpi2c_imx_probe(struct platform_device
> *pdev)
>  	if (ret)
>  		lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
> 
> -	ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, 0,
> -			       pdev->name, lpi2c_imx);
> -	if (ret) {
> -		dev_err(&pdev->dev, "can't claim irq %d\n", irq);
> -		return ret;
> -	}
> -
>  	i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
>  	platform_set_drvdata(pdev, lpi2c_imx);
> 
> @@ -668,6 +662,7 @@ static int __maybe_unused
> lpi2c_runtime_suspend(struct device *dev)  {
>  	struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
> 
> +	free_irq(lpi2c_imx->irq, lpi2c_imx);
>  	lpi2c_imx_clocks_unprepare(lpi2c_imx);
>  	pinctrl_pm_select_sleep_state(dev);
> 
> @@ -677,10 +672,21 @@ static int __maybe_unused
> lpi2c_runtime_suspend(struct device *dev)  static int __maybe_unused
> lpi2c_runtime_resume(struct device *dev)  {
>  	struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
> +	int ret = 0;
> 
>  	pinctrl_pm_select_default_state(dev);
> +	ret = lpi2c_imx_clocks_prepare(lpi2c_imx);
> +	if (ret)
> +		return ret;
> 
> -	return lpi2c_imx_clocks_prepare(lpi2c_imx);
> +	ret = request_irq(lpi2c_imx->irq, lpi2c_imx_isr, 0,
> +			       dev_name(dev), lpi2c_imx);
> +	if (ret) {
> +		dev_err(dev, "can't claim irq %d\n", lpi2c_imx->irq);
> +		return ret;
> +	}
> +
> +	return ret;
>  }
> 
>  static const struct dev_pm_ops lpi2c_pm_ops = {
> --
> 2.25.1
Aisheng Dong May 21, 2021, 6:43 a.m. UTC | #9
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 7:33 PM
> 
> add debug message when i2c peripheral clk rate is 0, then directly return
> -EINVAL.
> 
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>

You sign-off should be put after the original patch author

> Signed-off-by: Gao Pan <pandy.gao@nxp.com>
> Reviewed-by: Andy Duan <fugang.duan@nxp.com>

Drop the original review when they're significant changes

> ---
> V2 changes:
>  - Add my signed-off.
> ---
>  drivers/i2c/busses/i2c-imx-lpi2c.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c
> b/drivers/i2c/busses/i2c-imx-lpi2c.c
> index 333209ba81c1..dfec334712c2 100644
> --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> @@ -210,6 +210,11 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct
> *lpi2c_imx)
>  	lpi2c_imx_set_mode(lpi2c_imx);
> 
>  	clk_rate = clk_get_rate(lpi2c_imx->clk_per);
> +	if (!clk_rate) {
> +		dev_dbg(&lpi2c_imx->adapter.dev, "clk_per rate is 0\n");

s/dev_dbg/dev_err

> +		return -EINVAL;
> +	}
> +
>  	if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
>  		filt = 0;
>  	else
> --
> 2.25.1
Aisheng Dong May 21, 2021, 6:44 a.m. UTC | #10
> From: Clark Wang <xiaoning.wang@nxp.com>
> Sent: Tuesday, April 6, 2021 7:33 PM
> 
> Add bus recovery feature for LPI2C.
> Need add gpio pinctrl, scl-gpios and sda-gpios configuration in dts.
> 
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
> ---
> V2 changes:
>  - No change. Add dt-bindings in the next patch.

Dt binding patch should be sent before driver change

> ---
>  drivers/i2c/busses/i2c-imx-lpi2c.c | 83 ++++++++++++++++++++++++++++++
>  1 file changed, 83 insertions(+)
> 
> diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c
> b/drivers/i2c/busses/i2c-imx-lpi2c.c
> index 77ceb743b282..77dd6ee5a4a8 100644
> --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> @@ -18,6 +18,7 @@
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> +#include <linux/of_gpio.h>
>  #include <linux/pinctrl/consumer.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
> @@ -108,6 +109,11 @@ struct lpi2c_imx_struct {
>  	unsigned int		txfifosize;
>  	unsigned int		rxfifosize;
>  	enum lpi2c_imx_mode	mode;
> +
> +	struct i2c_bus_recovery_info rinfo;
> +	struct pinctrl *pinctrl;
> +	struct pinctrl_state *pinctrl_pins_default;
> +	struct pinctrl_state *pinctrl_pins_gpio;
>  };
> 
>  static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx, @@ -135,6
> +141,8 @@ static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
> 
>  		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
>  			dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
> +			if (lpi2c_imx->adapter.bus_recovery_info)
> +				i2c_recover_bus(&lpi2c_imx->adapter);
>  			return -ETIMEDOUT;
>  		}
>  		schedule();
> @@ -192,6 +200,8 @@ static void lpi2c_imx_stop(struct lpi2c_imx_struct
> *lpi2c_imx)
> 
>  		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
>  			dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
> +			if (lpi2c_imx->adapter.bus_recovery_info)
> +				i2c_recover_bus(&lpi2c_imx->adapter);
>  			break;
>  		}
>  		schedule();
> @@ -329,6 +339,8 @@ static int lpi2c_imx_txfifo_empty(struct
> lpi2c_imx_struct *lpi2c_imx)
> 
>  		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
>  			dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
> +			if (lpi2c_imx->adapter.bus_recovery_info)
> +				i2c_recover_bus(&lpi2c_imx->adapter);
>  			return -ETIMEDOUT;
>  		}
>  		schedule();
> @@ -528,6 +540,71 @@ static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
> 
> +static void lpi2c_imx_prepare_recovery(struct i2c_adapter *adap) {
> +	struct lpi2c_imx_struct *lpi2c_imx;
> +
> +	lpi2c_imx = container_of(adap, struct lpi2c_imx_struct, adapter);
> +
> +	pinctrl_select_state(lpi2c_imx->pinctrl,
> +lpi2c_imx->pinctrl_pins_gpio); }
> +
> +static void lpi2c_imx_unprepare_recovery(struct i2c_adapter *adap) {
> +	struct lpi2c_imx_struct *lpi2c_imx;
> +
> +	lpi2c_imx = container_of(adap, struct lpi2c_imx_struct, adapter);
> +
> +	pinctrl_select_state(lpi2c_imx->pinctrl,
> +lpi2c_imx->pinctrl_pins_default); }
> +
> +/*
> + * We switch SCL and SDA to their GPIO function and do some bitbanging
> + * for bus recovery. These alternative pinmux settings can be
> + * described in the device tree by a separate pinctrl state "gpio". If
> + * this is missing this is not a big problem, the only implication is
> + * that we can't do bus recovery.
> + */
> +static int lpi2c_imx_init_recovery_info(struct lpi2c_imx_struct *lpi2c_imx,
> +		struct platform_device *pdev)
> +{
> +	struct i2c_bus_recovery_info *rinfo = &lpi2c_imx->rinfo;
> +
> +	lpi2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
> +	if (!lpi2c_imx->pinctrl || IS_ERR(lpi2c_imx->pinctrl)) {
> +		dev_info(&pdev->dev, "can't get pinctrl, bus recovery not
> supported\n");
> +		return PTR_ERR(lpi2c_imx->pinctrl);
> +	}
> +
> +	lpi2c_imx->pinctrl_pins_default = pinctrl_lookup_state(lpi2c_imx->pinctrl,
> +			PINCTRL_STATE_DEFAULT);
> +	lpi2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(lpi2c_imx->pinctrl,
> +			"gpio");
> +	rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
> +	rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl",
> +GPIOD_OUT_HIGH_OPEN_DRAIN);
> +
> +	if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
> +	    PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
> +		return -EPROBE_DEFER;
> +	} else if (IS_ERR(rinfo->sda_gpiod) ||
> +		   IS_ERR(rinfo->scl_gpiod) ||
> +		   IS_ERR(lpi2c_imx->pinctrl_pins_default) ||
> +		   IS_ERR(lpi2c_imx->pinctrl_pins_gpio)) {
> +		dev_dbg(&pdev->dev, "recovery information incomplete\n");
> +		return 0;
> +	}
> +
> +	dev_info(&pdev->dev, "using scl%s for recovery\n",
> +		 rinfo->sda_gpiod ? ",sda" : "");
> +
> +	rinfo->prepare_recovery = lpi2c_imx_prepare_recovery;
> +	rinfo->unprepare_recovery = lpi2c_imx_unprepare_recovery;
> +	rinfo->recover_bus = i2c_generic_scl_recovery;
> +	lpi2c_imx->adapter.bus_recovery_info = rinfo;
> +
> +	return 0;
> +}
> +
>  static u32 lpi2c_imx_func(struct i2c_adapter *adapter)  {
>  	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | @@ -632,6 +709,12
> @@ static int lpi2c_imx_probe(struct platform_device *pdev)
>  	lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
>  	lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
> 
> +	/* Init optional bus recovery function */
> +	ret = lpi2c_imx_init_recovery_info(lpi2c_imx, pdev);
> +	/* Give it another chance if pinctrl used is not ready yet */
> +	if (ret == -EPROBE_DEFER)
> +		goto rpm_disable;
> +
>  	ret = i2c_add_adapter(&lpi2c_imx->adapter);
>  	if (ret)
>  		goto rpm_disable;
> --
> 2.25.1