diff mbox series

[V2] i2c: imx-lpi2c: add target mode support

Message ID 20240829105444.2885653-1-carlos.song@nxp.com (mailing list archive)
State New
Headers show
Series [V2] i2c: imx-lpi2c: add target mode support | expand

Commit Message

Carlos Song Aug. 29, 2024, 10:54 a.m. UTC
From: Carlos Song <carlos.song@nxp.com>

Add target mode support for LPI2C.

Signed-off-by: Carlos Song <carlos.song@nxp.com>
---
Change for V2:
- remove unused variable ‘lpi2c_imx’ in lpi2c_suspend_noirq.
---
 drivers/i2c/busses/i2c-imx-lpi2c.c | 252 ++++++++++++++++++++++++++++-
 1 file changed, 248 insertions(+), 4 deletions(-)

Comments

Andi Shyti Sept. 5, 2024, 10:09 p.m. UTC | #1
Hi Carlos,

Looks good, just few little comments.

On Thu, Aug 29, 2024 at 06:54:44PM GMT, carlos.song@nxp.com wrote:
> From: Carlos Song <carlos.song@nxp.com>
> 
> Add target mode support for LPI2C.

Can you please be a bit more descriptive? What is this mode
doing, how it works, what are you adding, etc. etc. etc.

> Signed-off-by: Carlos Song <carlos.song@nxp.com>
> ---
> Change for V2:
> - remove unused variable ‘lpi2c_imx’ in lpi2c_suspend_noirq.

this was part of a 5 patches series. Is that series superseded?

(please, next time when you send a series with more than one
patch, include a cover letter).

...

> +#define SCR_SEN		BIT(0)
> +#define SCR_RST		BIT(1)
> +#define SCR_FILTEN	BIT(4)
> +#define SCR_RTF		BIT(8)
> +#define SCR_RRF		BIT(9)
> +#define SCFGR1_RXSTALL	BIT(1)
> +#define SCFGR1_TXDSTALL	BIT(2)
> +#define SCFGR2_FILTSDA_SHIFT	24
> +#define SCFGR2_FILTSCL_SHIFT	16
> +#define SCFGR2_CLKHOLD(x)	(x)
> +#define SCFGR2_FILTSDA(x)	((x) << SCFGR2_FILTSDA_SHIFT)
> +#define SCFGR2_FILTSCL(x)	((x) << SCFGR2_FILTSCL_SHIFT)
> +#define SSR_TDF		BIT(0)
> +#define SSR_RDF		BIT(1)
> +#define SSR_AVF		BIT(2)
> +#define SSR_TAF		BIT(3)
> +#define SSR_RSF		BIT(8)
> +#define SSR_SDF		BIT(9)
> +#define SSR_BEF		BIT(10)
> +#define SSR_FEF		BIT(11)
> +#define SSR_SBF		BIT(24)
> +#define SSR_BBF		BIT(25)
> +#define SSR_CLEAR_BITS	(SSR_RSF | SSR_SDF | SSR_BEF | SSR_FEF)
> +#define SIER_TDIE	BIT(0)
> +#define SIER_RDIE	BIT(1)
> +#define SIER_AVIE	BIT(2)
> +#define SIER_TAIE	BIT(3)
> +#define SIER_RSIE	BIT(8)
> +#define SIER_SDIE	BIT(9)
> +#define SIER_BEIE	BIT(10)
> +#define SIER_FEIE	BIT(11)
> +#define SIER_AM0F	BIT(12)
> +#define SASR_READ_REQ	0x1
> +#define SLAVE_INT_FLAG	(SIER_TDIE | SIER_RDIE | SIER_AVIE | \
> +						SIER_SDIE | SIER_BEIE)

I'm not happy about the alignment here, can we have the columns
well aligned, please?

> +
>  #define I2C_CLK_RATIO	2
>  #define CHUNK_DATA	256

...

> +	if (sier_filter & SSR_SDF) {
> +		/* STOP */
> +		i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_STOP, &value);
> +	}

nit: no need for brackets here.

...

> +static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
> +{
> +	struct lpi2c_imx_struct *lpi2c_imx = dev_id;
> +	u32 ssr, sier_filter;
> +	unsigned int scr;

why is ssr unsigned int and not u32?

Can we define ssr, sier_filter and scr in the innermost section?
i.e. inside the "if () { ... }"

> +
> +	if (lpi2c_imx->target) {
> +		scr = readl(lpi2c_imx->base + LPI2C_SCR);
> +		ssr = readl(lpi2c_imx->base + LPI2C_SSR);
> +		sier_filter = ssr & readl(lpi2c_imx->base + LPI2C_SIER);
> +		if ((scr & SCR_SEN) && sier_filter)
> +			return lpi2c_imx_target_isr(lpi2c_imx, ssr, sier_filter);
> +		else
> +			return lpi2c_imx_master_isr(lpi2c_imx);
> +	} else {
> +		return lpi2c_imx_master_isr(lpi2c_imx);
> +	}

this can be simplified a bit:

	if (...) {
		scr = ...
		ssr = ...
		sier_filter = ...

		/* a nice comment */
		if (...)
			return lpi2c_imx_target_isr(...)
	}

	return lpi2c_imx_master_isr(lpi2c_imx);

Not a binding comment. Your choice.

> +}
> +
> +static void lpi2c_imx_target_init(struct lpi2c_imx_struct *lpi2c_imx)
> +{
> +	int temp;

u32?

Thanks,
Andi
Carlos Song Sept. 9, 2024, 2 a.m. UTC | #2
> 
> Hi Carlos,
> 
> Looks good, just few little comments.
> 
> On Thu, Aug 29, 2024 at 06:54:44PM GMT, carlos.song@nxp.com wrote:
> > From: Carlos Song <carlos.song@nxp.com>
> >
> > Add target mode support for LPI2C.
> 
> Can you please be a bit more descriptive? What is this mode doing, how it works,
> what are you adding, etc. etc. etc.
> 

Hi, Andi

Thank you for your suggestion! I will enrich it as much as possible.

> > Signed-off-by: Carlos Song <carlos.song@nxp.com>
> > ---
> > Change for V2:
> > - remove unused variable ‘lpi2c_imx’ in lpi2c_suspend_noirq.
> 
> this was part of a 5 patches series. Is that series superseded?
> 

Oh... so sorry about this, it was my mistake.

Before my true intention is only to fix it using V2 patch not replace the series.
Other patches are used to fix other problems. No change in other patches
So I don't send out them. Now I know this is completely wrong.

I need to send all patches in one serials with a cover letter even if other
patches have not changed. I should update all patches status at the same time
using change log, it will be more clear. Next I will follow this rule.

> (please, next time when you send a series with more than one patch, include a
> cover letter).
> 

Yes. I will do this in the future. Thank you.

One thing bother me, for other patches in this series, I plan to separate this series patches
and send them out in different series(maybe it looks like I dropped this patches series, later I will use other series).
So for this patch, can you accept that I only send this V3 patch fix without other patches?(Later other patches will send out
in other series separately, one patches series for fixing one issue).

> ...
> 
> > +#define SCR_SEN              BIT(0)
> > +#define SCR_RST              BIT(1)
> > +#define SCR_FILTEN   BIT(4)
> > +#define SCR_RTF              BIT(8)
> > +#define SCR_RRF              BIT(9)
> > +#define SCFGR1_RXSTALL       BIT(1)
> > +#define SCFGR1_TXDSTALL      BIT(2)
> > +#define SCFGR2_FILTSDA_SHIFT 24
> > +#define SCFGR2_FILTSCL_SHIFT 16
> > +#define SCFGR2_CLKHOLD(x)    (x)
> > +#define SCFGR2_FILTSDA(x)    ((x) << SCFGR2_FILTSDA_SHIFT)
> > +#define SCFGR2_FILTSCL(x)    ((x) << SCFGR2_FILTSCL_SHIFT)
> > +#define SSR_TDF              BIT(0)
> > +#define SSR_RDF              BIT(1)
> > +#define SSR_AVF              BIT(2)
> > +#define SSR_TAF              BIT(3)
> > +#define SSR_RSF              BIT(8)
> > +#define SSR_SDF              BIT(9)
> > +#define SSR_BEF              BIT(10)
> > +#define SSR_FEF              BIT(11)
> > +#define SSR_SBF              BIT(24)
> > +#define SSR_BBF              BIT(25)
> > +#define SSR_CLEAR_BITS       (SSR_RSF | SSR_SDF | SSR_BEF | SSR_FEF)
> > +#define SIER_TDIE    BIT(0)
> > +#define SIER_RDIE    BIT(1)
> > +#define SIER_AVIE    BIT(2)
> > +#define SIER_TAIE    BIT(3)
> > +#define SIER_RSIE    BIT(8)
> > +#define SIER_SDIE    BIT(9)
> > +#define SIER_BEIE    BIT(10)
> > +#define SIER_FEIE    BIT(11)
> > +#define SIER_AM0F    BIT(12)
> > +#define SASR_READ_REQ        0x1
> > +#define SLAVE_INT_FLAG       (SIER_TDIE | SIER_RDIE | SIER_AVIE | \
> > +                                             SIER_SDIE |
> SIER_BEIE)
> 
> I'm not happy about the alignment here, can we have the columns well aligned,
> please?
> 
> > +
> >  #define I2C_CLK_RATIO        2
> >  #define CHUNK_DATA   256
> 
> ...
> 
> > +     if (sier_filter & SSR_SDF) {
> > +             /* STOP */
> > +             i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_STOP,
> &value);
> > +     }
> 
> nit: no need for brackets here.
> 
> ...
> 
> > +static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id) {
> > +     struct lpi2c_imx_struct *lpi2c_imx = dev_id;
> > +     u32 ssr, sier_filter;
> > +     unsigned int scr;
> 
> why is ssr unsigned int and not u32?
> 
> Can we define ssr, sier_filter and scr in the innermost section?
> i.e. inside the "if () { ... }"
> 
> > +
> > +     if (lpi2c_imx->target) {
> > +             scr = readl(lpi2c_imx->base + LPI2C_SCR);
> > +             ssr = readl(lpi2c_imx->base + LPI2C_SSR);
> > +             sier_filter = ssr & readl(lpi2c_imx->base + LPI2C_SIER);
> > +             if ((scr & SCR_SEN) && sier_filter)
> > +                     return lpi2c_imx_target_isr(lpi2c_imx, ssr,
> sier_filter);
> > +             else
> > +                     return lpi2c_imx_master_isr(lpi2c_imx);
> > +     } else {
> > +             return lpi2c_imx_master_isr(lpi2c_imx);
> > +     }
> 
> this can be simplified a bit:
> 
>         if (...) {
>                 scr = ...
>                 ssr = ...
>                 sier_filter = ...
> 
>                 /* a nice comment */
>                 if (...)
>                         return lpi2c_imx_target_isr(...)
>         }
> 
>         return lpi2c_imx_master_isr(lpi2c_imx);
> 
> Not a binding comment. Your choice.
> 
> > +}
> > +
> > +static void lpi2c_imx_target_init(struct lpi2c_imx_struct *lpi2c_imx)
> > +{
> > +     int temp;
> 
> u32?
> 
> Thanks,
> Andi
Andi Shyti Sept. 9, 2024, 1:02 p.m. UTC | #3
Hi Carlos,

> > (please, next time when you send a series with more than one patch, include a
> > cover letter).
> > 
> 
> Yes. I will do this in the future. Thank you.
> 
> One thing bother me, for other patches in this series, I plan to separate this series patches
> and send them out in different series(maybe it looks like I dropped this patches series, later I will use other series).
> So for this patch, can you accept that I only send this V3 patch fix without other patches?(Later other patches will send out
> in other series separately, one patches series for fixing one issue).

fine with me.

Thanks,
Andi

PS I have other patches from you to review, I will provide an
answer tonight... sorry for being late.
diff mbox series

Patch

diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index 530ca5d76403..73eb04c04466 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -43,6 +43,20 @@ 
 #define LPI2C_MTDR	0x60	/* i2c master TX data register */
 #define LPI2C_MRDR	0x70	/* i2c master RX data register */
 
+#define LPI2C_SCR	0x110	/* i2c target contrl register */
+#define LPI2C_SSR	0x114	/* i2c target status register */
+#define LPI2C_SIER	0x118	/* i2c target interrupt enable */
+#define LPI2C_SDER	0x11C	/* i2c target DMA enable */
+#define LPI2C_SCFGR0	0x120	/* i2c target configuration */
+#define LPI2C_SCFGR1	0x124	/* i2c target configuration */
+#define LPI2C_SCFGR2	0x128	/* i2c target configuration */
+#define LPI2C_SAMR	0x140	/* i2c target address match */
+#define LPI2C_SASR	0x150	/* i2c target address status */
+#define LPI2C_STAR	0x154	/* i2c target transmit ACK */
+#define LPI2C_STDR	0x160	/* i2c target transmit data */
+#define LPI2C_SRDR	0x170	/* i2c target receive data */
+#define LPI2C_SRDROR	0x178	/* i2c target receive data read only */
+
 /* i2c command */
 #define TRAN_DATA	0X00
 #define RECV_DATA	0X01
@@ -76,6 +90,42 @@ 
 #define MDER_TDDE	BIT(0)
 #define MDER_RDDE	BIT(1)
 
+#define SCR_SEN		BIT(0)
+#define SCR_RST		BIT(1)
+#define SCR_FILTEN	BIT(4)
+#define SCR_RTF		BIT(8)
+#define SCR_RRF		BIT(9)
+#define SCFGR1_RXSTALL	BIT(1)
+#define SCFGR1_TXDSTALL	BIT(2)
+#define SCFGR2_FILTSDA_SHIFT	24
+#define SCFGR2_FILTSCL_SHIFT	16
+#define SCFGR2_CLKHOLD(x)	(x)
+#define SCFGR2_FILTSDA(x)	((x) << SCFGR2_FILTSDA_SHIFT)
+#define SCFGR2_FILTSCL(x)	((x) << SCFGR2_FILTSCL_SHIFT)
+#define SSR_TDF		BIT(0)
+#define SSR_RDF		BIT(1)
+#define SSR_AVF		BIT(2)
+#define SSR_TAF		BIT(3)
+#define SSR_RSF		BIT(8)
+#define SSR_SDF		BIT(9)
+#define SSR_BEF		BIT(10)
+#define SSR_FEF		BIT(11)
+#define SSR_SBF		BIT(24)
+#define SSR_BBF		BIT(25)
+#define SSR_CLEAR_BITS	(SSR_RSF | SSR_SDF | SSR_BEF | SSR_FEF)
+#define SIER_TDIE	BIT(0)
+#define SIER_RDIE	BIT(1)
+#define SIER_AVIE	BIT(2)
+#define SIER_TAIE	BIT(3)
+#define SIER_RSIE	BIT(8)
+#define SIER_SDIE	BIT(9)
+#define SIER_BEIE	BIT(10)
+#define SIER_FEIE	BIT(11)
+#define SIER_AM0F	BIT(12)
+#define SASR_READ_REQ	0x1
+#define SLAVE_INT_FLAG	(SIER_TDIE | SIER_RDIE | SIER_AVIE | \
+						SIER_SDIE | SIER_BEIE)
+
 #define I2C_CLK_RATIO	2
 #define CHUNK_DATA	256
 
@@ -133,6 +183,7 @@  struct lpi2c_imx_struct {
 	struct i2c_bus_recovery_info rinfo;
 	bool			can_use_dma;
 	struct lpi2c_imx_dma	*dma;
+	struct i2c_client	*target;
 };
 
 static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
@@ -952,9 +1003,57 @@  static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
 	return (result < 0) ? result : num;
 }
 
-static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
+static irqreturn_t lpi2c_imx_target_isr(struct lpi2c_imx_struct *lpi2c_imx,
+					   u32 ssr, u32 sier_filter)
+{
+	u8 value;
+	u32 sasr;
+
+	/* Arbitration lost */
+	if (sier_filter & SSR_BEF) {
+		writel(0, lpi2c_imx->base + LPI2C_SIER);
+		return IRQ_HANDLED;
+	}
+
+	/* Address detected */
+	if (sier_filter & SSR_AVF) {
+		sasr = readl(lpi2c_imx->base + LPI2C_SASR);
+		if (SASR_READ_REQ & sasr) {
+			/* Read request */
+			i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_READ_REQUESTED, &value);
+			writel(value, lpi2c_imx->base + LPI2C_STDR);
+			goto ret;
+		} else {
+			/* Write request */
+			i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_WRITE_REQUESTED, &value);
+		}
+	}
+
+	if (sier_filter & SSR_SDF) {
+		/* STOP */
+		i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_STOP, &value);
+	}
+
+	if (sier_filter & SSR_TDF) {
+		/* Target send data */
+		i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_READ_PROCESSED, &value);
+		writel(value, lpi2c_imx->base + LPI2C_STDR);
+	}
+
+	if (sier_filter & SSR_RDF) {
+		/* Target receive data */
+		value = readl(lpi2c_imx->base + LPI2C_SRDR);
+		i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+	}
+
+ret:
+	/* Clear SSR */
+	writel(ssr & SSR_CLEAR_BITS, lpi2c_imx->base + LPI2C_SSR);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t lpi2c_imx_master_isr(struct lpi2c_imx_struct *lpi2c_imx)
 {
-	struct lpi2c_imx_struct *lpi2c_imx = dev_id;
 	unsigned int enabled;
 	unsigned int temp;
 
@@ -974,6 +1073,119 @@  static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
+{
+	struct lpi2c_imx_struct *lpi2c_imx = dev_id;
+	u32 ssr, sier_filter;
+	unsigned int scr;
+
+	if (lpi2c_imx->target) {
+		scr = readl(lpi2c_imx->base + LPI2C_SCR);
+		ssr = readl(lpi2c_imx->base + LPI2C_SSR);
+		sier_filter = ssr & readl(lpi2c_imx->base + LPI2C_SIER);
+		if ((scr & SCR_SEN) && sier_filter)
+			return lpi2c_imx_target_isr(lpi2c_imx, ssr, sier_filter);
+		else
+			return lpi2c_imx_master_isr(lpi2c_imx);
+	} else {
+		return lpi2c_imx_master_isr(lpi2c_imx);
+	}
+}
+
+static void lpi2c_imx_target_init(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	int temp;
+
+	/* reset target module */
+	writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR);
+	writel(0, lpi2c_imx->base + LPI2C_SCR);
+
+	/* Set target addr */
+	writel((lpi2c_imx->target->addr << 1), lpi2c_imx->base + LPI2C_SAMR);
+
+	writel(SCFGR1_RXSTALL | SCFGR1_TXDSTALL, lpi2c_imx->base + LPI2C_SCFGR1);
+
+	/*
+	 * set SCFGR2: FILTSDA, FILTSCL and CLKHOLD
+	 *
+	 * FILTSCL/FILTSDA can eliminate signal skew. It should generally be
+	 * set to the same value and should be set >= 50ns.
+	 *
+	 * CLKHOLD is only used when clock stretching is enabled, but it will
+	 * extend the clock stretching to ensure there is an additional delay
+	 * between the target driving SDA and the target releasing the SCL pin.
+	 *
+	 * CLKHOLD setting is crucial for lpi2c target. When master read data
+	 * from target, if there is a delay caused by cpu idle, excessive load,
+	 * or other delays between two bytes in one message transmission. so it
+	 * will cause a short interval time between the driving SDA signal and
+	 * releasing SCL signal. Lpi2c master will mistakenly think it is a stop
+	 * signal resulting in an arbitration failure. This issue can be avoided
+	 * by setting CLKHOLD.
+	 *
+	 * In order to ensure lpi2c function normally when the lpi2c speed is as
+	 * low as 100kHz, CLKHOLD should be set 3 and it is also compatible with
+	 * higher clock frequency like 400kHz and 1MHz.
+	 */
+	temp = SCFGR2_FILTSDA(2) | SCFGR2_FILTSCL(2) | SCFGR2_CLKHOLD(3);
+	writel(temp, lpi2c_imx->base + LPI2C_SCFGR2);
+
+	/*
+	 * Enable module:
+	 * SCR_FILTEN can enable digital filter and output delay counter for LPI2C
+	 * target mode. So SCR_FILTEN need be asserted when enable SDA/SCL FILTER
+	 * and CLKHOLD.
+	 */
+	writel(SCR_SEN | SCR_FILTEN, lpi2c_imx->base + LPI2C_SCR);
+
+	/* Enable interrupt from i2c module */
+	writel(SLAVE_INT_FLAG, lpi2c_imx->base + LPI2C_SIER);
+}
+
+static int lpi2c_imx_reg_target(struct i2c_client *client)
+{
+	struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(client->adapter);
+	int ret;
+
+	if (lpi2c_imx->target)
+		return -EBUSY;
+
+	lpi2c_imx->target = client;
+
+	ret = pm_runtime_resume_and_get(lpi2c_imx->adapter.dev.parent);
+	if (ret < 0) {
+		dev_err(&lpi2c_imx->adapter.dev, "failed to resume i2c controller");
+		return ret;
+	}
+
+	lpi2c_imx_target_init(lpi2c_imx);
+
+	return 0;
+}
+
+static int lpi2c_imx_unreg_target(struct i2c_client *client)
+{
+	struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(client->adapter);
+	int ret;
+
+	if (!lpi2c_imx->target)
+		return -EINVAL;
+
+	/* Reset target address. */
+	writel(0, lpi2c_imx->base + LPI2C_SAMR);
+
+	writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR);
+	writel(0, lpi2c_imx->base + LPI2C_SCR);
+
+	lpi2c_imx->target = NULL;
+
+	ret = pm_runtime_put_sync(lpi2c_imx->adapter.dev.parent);
+	if (ret < 0)
+		dev_err(&lpi2c_imx->adapter.dev, "failed to suspend i2c controller");
+
+	return ret;
+}
+
 static int lpi2c_imx_init_recovery_info(struct lpi2c_imx_struct *lpi2c_imx,
 				  struct platform_device *pdev)
 {
@@ -1049,6 +1261,8 @@  static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
 static const struct i2c_algorithm lpi2c_imx_algo = {
 	.master_xfer	= lpi2c_imx_xfer,
 	.functionality	= lpi2c_imx_func,
+	.reg_slave		= lpi2c_imx_reg_target,
+	.unreg_slave	= lpi2c_imx_unreg_target,
 };
 
 static const struct of_device_id lpi2c_imx_of_match[] = {
@@ -1199,9 +1413,39 @@  static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
 	return 0;
 }
 
+static int lpi2c_suspend_noirq(struct device *dev)
+{
+	int ret;
+
+	ret = pm_runtime_force_suspend(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int lpi2c_resume_noirq(struct device *dev)
+{
+	struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret)
+		return ret;
+
+	/*
+	 * If i2c module powered down in system suspend, register
+	 * value will lose. So reinit target when system resume.
+	 */
+	if (lpi2c_imx->target)
+		lpi2c_imx_target_init(lpi2c_imx);
+
+	return 0;
+}
+
 static const struct dev_pm_ops lpi2c_pm_ops = {
-	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-				      pm_runtime_force_resume)
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpi2c_suspend_noirq,
+				      lpi2c_resume_noirq)
 	SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
 			   lpi2c_runtime_resume, NULL)
 };