public inbox for linux-i2c@vger.kernel.org
 help / color / mirror / Atom feed
From: Artem Shimko <a.shimko.dev@gmail.com>
To: Mika Westerberg <mika.westerberg@linux.intel.com>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	Jan Dabros <jsd@semihalf.com>, Andi Shyti <andi.shyti@kernel.org>,
	Philipp Zabel <p.zabel@pengutronix.de>
Cc: Artem Shimko <a.shimko.dev@gmail.com>,
	linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] i2c: designware: add reset control support in suspend/resume
Date: Tue, 10 Mar 2026 21:40:45 +0300	[thread overview]
Message-ID: <20260310184046.2010403-1-a.shimko.dev@gmail.com> (raw)

The driver currently acquires reset control during probe but does not
manage it during system suspend/resume. This can leave the I2C controller
in an undefined state after resume.

Add reset control assertion during system suspend and deassertion during
resume to ensure proper hardware initialization across power management
transitions. Skip runtime suspend if the device is already suspended to
avoid redundant operations.

Signed-off-by: Artem Shimko <a.shimko.dev@gmail.com>
---
Hello maintainers and reviewers,

This patch adds proper reset control handling to the suspend/resume
callbacks. The reset line is asserted during system suspend to ensure
the controller is properly quiesced, and deasserted during resume to
reinitialize the hardware. Additionally, the suspend path now checks
the runtime PM status to avoid redundant operations when the device is
already suspended.

Thank you!
--
Regards,
Artem

 drivers/i2c/busses/i2c-designware-common.c | 40 ++++++++++++++++++----
 1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 4dc57fd56170..fbe817df9b2e 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -29,6 +29,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 #include <linux/swab.h>
 #include <linux/types.h>
 #include <linux/units.h>
@@ -967,6 +968,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
 }
 EXPORT_SYMBOL_GPL(i2c_dw_probe);
 
+#ifdef CONFIG_ACPI
 static int i2c_dw_prepare(struct device *device)
 {
 	/*
@@ -977,18 +979,23 @@ static int i2c_dw_prepare(struct device *device)
 	 */
 	return !has_acpi_companion(device);
 }
+#endif
 
 static int i2c_dw_runtime_suspend(struct device *device)
 {
 	struct dw_i2c_dev *dev = dev_get_drvdata(device);
+	int ret;
 
 	if (dev->shared_with_punit)
 		return 0;
 
 	i2c_dw_disable(dev);
-	i2c_dw_prepare_clk(dev, false);
 
-	return 0;
+	ret = reset_control_assert(dev->rst);
+	if (ret)
+		return ret;
+
+	return i2c_dw_prepare_clk(dev, false);
 }
 
 static int i2c_dw_suspend(struct device *device)
@@ -997,15 +1004,28 @@ static int i2c_dw_suspend(struct device *device)
 
 	i2c_mark_adapter_suspended(&dev->adapter);
 
-	return i2c_dw_runtime_suspend(device);
+	if (!pm_runtime_status_suspended(device))
+		return i2c_dw_runtime_suspend(device);
+
+	return 0;
 }
 
 static int i2c_dw_runtime_resume(struct device *device)
 {
 	struct dw_i2c_dev *dev = dev_get_drvdata(device);
+	int ret;
+
+	if (!dev->shared_with_punit) {
+		ret = i2c_dw_prepare_clk(dev, true);
+		if (ret)
+			return ret;
 
-	if (!dev->shared_with_punit)
-		i2c_dw_prepare_clk(dev, true);
+		ret = reset_control_deassert(dev->rst);
+		if (ret) {
+			i2c_dw_prepare_clk(dev, false);
+			return ret;
+		}
+	}
 
 	i2c_dw_init(dev);
 
@@ -1015,16 +1035,24 @@ static int i2c_dw_runtime_resume(struct device *device)
 static int i2c_dw_resume(struct device *device)
 {
 	struct dw_i2c_dev *dev = dev_get_drvdata(device);
+	int ret;
+
+	ret = i2c_dw_runtime_resume(device);
+	if (ret)
+		return ret;
 
-	i2c_dw_runtime_resume(device);
 	i2c_mark_adapter_resumed(&dev->adapter);
 
 	return 0;
 }
 
 EXPORT_GPL_DEV_PM_OPS(i2c_dw_dev_pm_ops) = {
+#ifdef CONFIG_ACPI
 	.prepare = pm_sleep_ptr(i2c_dw_prepare),
 	LATE_SYSTEM_SLEEP_PM_OPS(i2c_dw_suspend, i2c_dw_resume)
+#else
+	SYSTEM_SLEEP_PM_OPS(i2c_dw_suspend, i2c_dw_resume)
+#endif
 	RUNTIME_PM_OPS(i2c_dw_runtime_suspend, i2c_dw_runtime_resume, NULL)
 };
 
-- 
2.43.0


             reply	other threads:[~2026-03-10 18:40 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-10 18:40 Artem Shimko [this message]
2026-03-10 19:22 ` [PATCH] i2c: designware: add reset control support in suspend/resume Andy Shevchenko
2026-03-11  6:20   ` Artem Shimko
2026-03-11 12:10     ` Andy Shevchenko
2026-03-23  7:42       ` Artem Shimko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260310184046.2010403-1-a.shimko.dev@gmail.com \
    --to=a.shimko.dev@gmail.com \
    --cc=andi.shyti@kernel.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=jsd@semihalf.com \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mika.westerberg@linux.intel.com \
    --cc=p.zabel@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox