public inbox for linux-i2c@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] i2c: designware: Generic polling mode code
@ 2024-02-06 14:51 Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info Jarkko Nikula
                   ` (8 more replies)
  0 siblings, 9 replies; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

Hi

This is mostly the same than the first version implementing generic
polling mode code for the i2c-designware except three more patches added
before them.

Andy had an idea we should have more consistency to platform flags naming
and the first three patches are around that. Michael started the
conversion so I took his patch from an internal set and put first. Since
this version touches Intel PUNIT semaphore code I Cc'ed Hans.

Andy and Andi had comments to "Uniform initialization flow for polling
mode" but I decided to not implement a separate helpter function for
interrupt request as it in my opinnion does not make code any easier to
read.

I also wanted to retain single return point in the
i2c_dw_wait_transfer() implemented by the last patch since I had some
debug code there when doing the first version.

v1:
https://lore.kernel.org/linux-i2c/20240131141653.2689260-1-jarkko.nikula@linux.intel.com/

Jarkko Nikula (8):
  i2c: designware: Convert arbitration semaphore flag as semaphore type
  i2c: designware: Convert shared_with_punit boolean as semaphore type
  i2c: designware: Uniform initialization flow for polling mode
  i2c: designware: Do not enable interrupts shortly in polling mode
  i2c: designware: Use accessors to DW_IC_INTR_MASK register
  i2c: designware: Move interrupt handling functions before
    i2c_dw_xfer()
  i2c: designware: Fix RX FIFO depth define on Wangxun 10Gb NIC
  i2c: designware: Implement generic polling mode code for Wangxun 10Gb
    NIC

Michael J. Ruhl (1):
  i2c: designware: Add some flexiblity to the model info

 drivers/i2c/busses/i2c-designware-amdpsp.c   |   2 +-
 drivers/i2c/busses/i2c-designware-baytrail.c |   2 +-
 drivers/i2c/busses/i2c-designware-common.c   |   2 +-
 drivers/i2c/busses/i2c-designware-core.h     |  38 +-
 drivers/i2c/busses/i2c-designware-master.c   | 417 ++++++++-----------
 drivers/i2c/busses/i2c-designware-pcidrv.c   |   2 +-
 drivers/i2c/busses/i2c-designware-platdrv.c  |  12 +-
 7 files changed, 223 insertions(+), 252 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 15:30   ` Andy Shevchenko
  2024-02-06 14:51 ` [PATCH v2 2/9] i2c: designware: Convert arbitration semaphore flag as semaphore type Jarkko Nikula
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

From: "Michael J. Ruhl" <michael.j.ruhl@intel.com>

Currently the way to identify a model is via a bit field, of which
4 bits are currently defined.

Use a shifted value to that more models can be defined.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Michael J. Ruhl <michael.j.ruhl@intel.com>
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-core.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index a7f6f3eafad7..4e1f0924f493 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -304,10 +304,10 @@ struct dw_i2c_dev {
 #define ACCESS_NO_IRQ_SUSPEND			BIT(1)
 #define ARBITRATION_SEMAPHORE			BIT(2)
 
-#define MODEL_MSCC_OCELOT			BIT(8)
-#define MODEL_BAIKAL_BT1			BIT(9)
-#define MODEL_AMD_NAVI_GPU			BIT(10)
-#define MODEL_WANGXUN_SP			BIT(11)
+#define MODEL_MSCC_OCELOT			(1 << 8)
+#define MODEL_BAIKAL_BT1			(2 << 8)
+#define MODEL_AMD_NAVI_GPU			(3 << 8)
+#define MODEL_WANGXUN_SP			(4 << 8)
 #define MODEL_MASK				GENMASK(11, 8)
 
 /*
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 2/9] i2c: designware: Convert arbitration semaphore flag as semaphore type
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 3/9] i2c: designware: Convert shared_with_punit boolean " Jarkko Nikula
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

Make AMD PSP I2C bus arbitration semaphore flag as a type and add a
related flag bit mask. Only one bus semaphore implementation can be
active at a time so no need to reserve one flag bit for each of them.

Chosen mask size of 4-bits is large considering currently there is only
two semaphore implementations but there is no lack of free flag bits
either.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-amdpsp.c  | 2 +-
 drivers/i2c/busses/i2c-designware-core.h    | 4 +++-
 drivers/i2c/busses/i2c-designware-platdrv.c | 2 +-
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c
index 63454b06e5da..5d788281fe7a 100644
--- a/drivers/i2c/busses/i2c-designware-amdpsp.c
+++ b/drivers/i2c/busses/i2c-designware-amdpsp.c
@@ -284,7 +284,7 @@ int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev)
 	if (!dev)
 		return -ENODEV;
 
-	if (!(dev->flags & ARBITRATION_SEMAPHORE))
+	if ((dev->flags & SEMAPHORE_MASK) != SEMAPHORE_AMD_PSP)
 		return -ENODEV;
 
 	/* Allow to bind only one instance of a driver */
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 4e1f0924f493..bac0aec3cb15 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -302,7 +302,9 @@ struct dw_i2c_dev {
 
 #define ACCESS_INTR_MASK			BIT(0)
 #define ACCESS_NO_IRQ_SUSPEND			BIT(1)
-#define ARBITRATION_SEMAPHORE			BIT(2)
+
+#define SEMAPHORE_AMD_PSP			(1 << 4)
+#define SEMAPHORE_MASK				GENMASK(7, 4)
 
 #define MODEL_MSCC_OCELOT			(1 << 8)
 #define MODEL_BAIKAL_BT1			(2 << 8)
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 855b698e99c0..efe9b8e0b7a2 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -50,7 +50,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
 	{ "808622C1", ACCESS_NO_IRQ_SUSPEND },
 	{ "AMD0010", ACCESS_INTR_MASK },
 	{ "AMDI0010", ACCESS_INTR_MASK },
-	{ "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE },
+	{ "AMDI0019", ACCESS_INTR_MASK | SEMAPHORE_AMD_PSP },
 	{ "AMDI0510", 0 },
 	{ "APMC0D0F", 0 },
 	{ "HISI02A1", 0 },
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 3/9] i2c: designware: Convert shared_with_punit boolean as semaphore type
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 2/9] i2c: designware: Convert arbitration semaphore flag as semaphore type Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 4/9] i2c: designware: Uniform initialization flow for polling mode Jarkko Nikula
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

Remove the shared_with_punit member variable from the struct dw_i2c_dev
and make it one semaphore type. Idea is to make code more uniform when
there is need to differentiate between bus semaphores.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-baytrail.c | 2 +-
 drivers/i2c/busses/i2c-designware-core.h     | 3 +--
 drivers/i2c/busses/i2c-designware-platdrv.c  | 8 ++++----
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
index 45774aa47c28..159db4802cdf 100644
--- a/drivers/i2c/busses/i2c-designware-baytrail.c
+++ b/drivers/i2c/busses/i2c-designware-baytrail.c
@@ -38,7 +38,7 @@ int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev)
 	dev_info(dev->dev, "I2C bus managed by PUNIT\n");
 	dev->acquire_lock = iosf_mbi_block_punit_i2c_access;
 	dev->release_lock = iosf_mbi_unblock_punit_i2c_access;
-	dev->shared_with_punit = true;
+	dev->flags |= SEMAPHORE_INTEL_PUNIT;
 
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index bac0aec3cb15..30b29d6e58ce 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -235,7 +235,6 @@ struct reset_control;
  * @release_lock: function to release a hardware lock on the bus
  * @semaphore_idx: Index of table with semaphore type attached to the bus. It's
  *	-1 if there is no semaphore.
- * @shared_with_punit: true if this bus is shared with the SoCs PUNIT
  * @disable: function to disable the controller
  * @init: function to initialize the I2C hardware
  * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing
@@ -292,7 +291,6 @@ struct dw_i2c_dev {
 	int			(*acquire_lock)(void);
 	void			(*release_lock)(void);
 	int			semaphore_idx;
-	bool			shared_with_punit;
 	void			(*disable)(struct dw_i2c_dev *dev);
 	int			(*init)(struct dw_i2c_dev *dev);
 	int			(*set_sda_hold_time)(struct dw_i2c_dev *dev);
@@ -304,6 +302,7 @@ struct dw_i2c_dev {
 #define ACCESS_NO_IRQ_SUSPEND			BIT(1)
 
 #define SEMAPHORE_AMD_PSP			(1 << 4)
+#define SEMAPHORE_INTEL_PUNIT			(2 << 4)
 #define SEMAPHORE_MASK				GENMASK(7, 4)
 
 #define MODEL_MSCC_OCELOT			(1 << 8)
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index efe9b8e0b7a2..c07385c20cee 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -181,7 +181,7 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
 {
 	pm_runtime_disable(dev->dev);
 
-	if (dev->shared_with_punit)
+	if ((dev->flags & SEMAPHORE_MASK) == SEMAPHORE_INTEL_PUNIT)
 		pm_runtime_put_noidle(dev->dev);
 }
 
@@ -381,7 +381,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_set_active(&pdev->dev);
 
-	if (dev->shared_with_punit)
+	if ((dev->flags & SEMAPHORE_MASK) == SEMAPHORE_INTEL_PUNIT)
 		pm_runtime_get_noresume(&pdev->dev);
 
 	pm_runtime_enable(&pdev->dev);
@@ -433,7 +433,7 @@ static int dw_i2c_plat_runtime_suspend(struct device *dev)
 {
 	struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
 
-	if (i_dev->shared_with_punit)
+	if ((i_dev->flags & SEMAPHORE_MASK) == SEMAPHORE_INTEL_PUNIT)
 		return 0;
 
 	i_dev->disable(i_dev);
@@ -455,7 +455,7 @@ static int dw_i2c_plat_runtime_resume(struct device *dev)
 {
 	struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
 
-	if (!i_dev->shared_with_punit)
+	if ((i_dev->flags & SEMAPHORE_MASK) != SEMAPHORE_INTEL_PUNIT)
 		i2c_dw_prepare_clk(i_dev, true);
 
 	i_dev->init(i_dev);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 4/9] i2c: designware: Uniform initialization flow for polling mode
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
                   ` (2 preceding siblings ...)
  2024-02-06 14:51 ` [PATCH v2 3/9] i2c: designware: Convert shared_with_punit boolean " Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 15:13   ` Andy Shevchenko
  2024-02-06 14:51 ` [PATCH v2 5/9] i2c: designware: Do not enable interrupts shortly in " Jarkko Nikula
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

Currently initialization flow in i2c_dw_probe_master() skips a few steps
and has code duplication for polling mode implementation.

Simplify this by adding a new ACCESS_POLLING flag that is set for those
two platforms that currently use polling mode and use it to skip
interrupt handler setup.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-core.h    |  1 +
 drivers/i2c/busses/i2c-designware-master.c  | 42 ++++-----------------
 drivers/i2c/busses/i2c-designware-pcidrv.c  |  2 +-
 drivers/i2c/busses/i2c-designware-platdrv.c |  2 +-
 4 files changed, 11 insertions(+), 36 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 30b29d6e58ce..ee93c0b4e817 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -300,6 +300,7 @@ struct dw_i2c_dev {
 
 #define ACCESS_INTR_MASK			BIT(0)
 #define ACCESS_NO_IRQ_SUSPEND			BIT(1)
+#define ACCESS_POLLING				BIT(3)
 
 #define SEMAPHORE_AMD_PSP			(1 << 4)
 #define SEMAPHORE_INTEL_PUNIT			(2 << 4)
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 85dbd0eb5392..e879a0f5cc97 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -953,31 +953,6 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
 	return 0;
 }
 
-static int i2c_dw_poll_adap_quirk(struct dw_i2c_dev *dev)
-{
-	struct i2c_adapter *adap = &dev->adapter;
-	int ret;
-
-	pm_runtime_get_noresume(dev->dev);
-	ret = i2c_add_numbered_adapter(adap);
-	if (ret)
-		dev_err(dev->dev, "Failed to add adapter: %d\n", ret);
-	pm_runtime_put_noidle(dev->dev);
-
-	return ret;
-}
-
-static bool i2c_dw_is_model_poll(struct dw_i2c_dev *dev)
-{
-	switch (dev->flags & MODEL_MASK) {
-	case MODEL_AMD_NAVI_GPU:
-	case MODEL_WANGXUN_SP:
-		return true;
-	default:
-		return false;
-	}
-}
-
 int i2c_dw_probe_master(struct dw_i2c_dev *dev)
 {
 	struct i2c_adapter *adap = &dev->adapter;
@@ -1033,9 +1008,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
 	adap->dev.parent = dev->dev;
 	i2c_set_adapdata(adap, dev);
 
-	if (i2c_dw_is_model_poll(dev))
-		return i2c_dw_poll_adap_quirk(dev);
-
 	if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
 		irq_flags = IRQF_NO_SUSPEND;
 	} else {
@@ -1049,12 +1021,14 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
 	regmap_write(dev->map, DW_IC_INTR_MASK, 0);
 	i2c_dw_release_lock(dev);
 
-	ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
-			       dev_name(dev->dev), dev);
-	if (ret) {
-		dev_err(dev->dev, "failure requesting irq %i: %d\n",
-			dev->irq, ret);
-		return ret;
+	if (!(dev->flags & ACCESS_POLLING)) {
+		ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
+				       irq_flags, dev_name(dev->dev), dev);
+		if (ret) {
+			dev_err(dev->dev, "failure requesting irq %i: %d\n",
+				dev->irq, ret);
+			return ret;
+		}
 	}
 
 	ret = i2c_dw_init_recovery_info(dev);
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index 61d7a27aa070..9be9a2658e1f 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -154,7 +154,7 @@ static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
 {
 	struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
 
-	dev->flags |= MODEL_AMD_NAVI_GPU;
+	dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING;
 	dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index c07385c20cee..1c9f8e0c02f8 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -290,7 +290,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
 
 	dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
 	if (device_property_present(&pdev->dev, "wx,i2c-snps-model"))
-		dev->flags = MODEL_WANGXUN_SP;
+		dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING;
 
 	dev->dev = &pdev->dev;
 	dev->irq = irq;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 5/9] i2c: designware: Do not enable interrupts shortly in polling mode
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
                   ` (3 preceding siblings ...)
  2024-02-06 14:51 ` [PATCH v2 4/9] i2c: designware: Uniform initialization flow for polling mode Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 6/9] i2c: designware: Use accessors to DW_IC_INTR_MASK register Jarkko Nikula
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

I was testing the polling mode txgbe_i2c_dw_xfer_quirk() on a HW where
the i2c-designware has interrupt connected and shared with other device.
I noticed there is a bogus interrupt for each transfer.

Reason for this that both polling mode functions call the
i2c_dw_xfer_init() which enable interrupts then followed by immediate
disable by the same polling mode functions. This is enough to trigger
TX_EMPTY interrupt.

Fix this by introducing a __i2c_dw_write_intr_mask() helper that unmasks
interrupts conditionally and use it in i2c_dw_xfer_init().

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-core.h   | 8 ++++++++
 drivers/i2c/busses/i2c-designware-master.c | 4 +---
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index ee93c0b4e817..353d753d9d5d 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -353,6 +353,14 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
 	dev->status &= ~STATUS_ACTIVE;
 }
 
+static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev,
+					    unsigned int intr_mask)
+{
+	unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask;
+
+	regmap_write(dev->map, DW_IC_INTR_MASK, val);
+}
+
 void __i2c_dw_disable(struct dw_i2c_dev *dev);
 
 extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index e879a0f5cc97..835d82e2c5fe 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -250,7 +250,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 
 	/* Clear and enable interrupts */
 	regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
-	regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
+	__i2c_dw_write_intr_mask(dev, DW_IC_INTR_MASTER_MASK);
 }
 
 static int i2c_dw_check_stopbit(struct dw_i2c_dev *dev)
@@ -300,7 +300,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
 	dev->msgs = msgs;
 	dev->msgs_num = num_msgs;
 	i2c_dw_xfer_init(dev);
-	regmap_write(dev->map, DW_IC_INTR_MASK, 0);
 
 	/* Initiate messages read/write transaction */
 	for (msg_wrt_idx = 0; msg_wrt_idx < num_msgs; msg_wrt_idx++) {
@@ -384,7 +383,6 @@ static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msg
 	dev->msgs = msgs;
 	dev->msgs_num = num_msgs;
 	i2c_dw_xfer_init(dev);
-	regmap_write(dev->map, DW_IC_INTR_MASK, 0);
 
 	for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) {
 		buf = msgs[msg_idx].buf;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 6/9] i2c: designware: Use accessors to DW_IC_INTR_MASK register
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
                   ` (4 preceding siblings ...)
  2024-02-06 14:51 ` [PATCH v2 5/9] i2c: designware: Do not enable interrupts shortly in " Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 7/9] i2c: designware: Move interrupt handling functions before i2c_dw_xfer() Jarkko Nikula
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

Convert access to DW_IC_INTR_MASK register using the existing
__i2c_dw_write_intr_mask() and a __i2c_dw_read_intr_mask() introduced
here. Motivation to this is to prepare for generic polling mode code
where polling mode will use a SW mask instead of DW_IC_INTR_MASK.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-common.c |  2 +-
 drivers/i2c/busses/i2c-designware-core.h   |  7 +++++++
 drivers/i2c/busses/i2c-designware-master.c | 22 ++++++++++++----------
 3 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 35f762872b8a..e8a688d04aee 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -648,7 +648,7 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
 	__i2c_dw_disable(dev);
 
 	/* Disable all interrupts */
-	regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+	__i2c_dw_write_intr_mask(dev, 0);
 	regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
 
 	i2c_dw_release_lock(dev);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 353d753d9d5d..ee1dbdb52d3e 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -361,6 +361,13 @@ static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev,
 	regmap_write(dev->map, DW_IC_INTR_MASK, val);
 }
 
+static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev,
+					   unsigned int *intr_mask)
+{
+	if (!(dev->flags & ACCESS_POLLING))
+		regmap_read(dev->map, DW_IC_INTR_MASK, intr_mask);
+}
+
 void __i2c_dw_disable(struct dw_i2c_dev *dev);
 
 extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 835d82e2c5fe..2e8f9733ddd3 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -240,7 +240,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 		     msgs[dev->msg_write_idx].addr | ic_tar);
 
 	/* Enforce disabled interrupts (due to HW issues) */
-	regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+	__i2c_dw_write_intr_mask(dev, 0);
 
 	/* Enable the adapter */
 	__i2c_dw_enable(dev);
@@ -544,7 +544,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 	if (dev->msg_err)
 		intr_mask = 0;
 
-	regmap_write(dev->map,  DW_IC_INTR_MASK, intr_mask);
+	__i2c_dw_write_intr_mask(dev, intr_mask);
 }
 
 static u8
@@ -552,6 +552,7 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
 {
 	struct i2c_msg *msgs = dev->msgs;
 	u32 flags = msgs[dev->msg_read_idx].flags;
+	unsigned int intr_mask;
 
 	/*
 	 * Adjust the buffer length and mask the flag
@@ -566,8 +567,9 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
 	 * Received buffer length, re-enable TX_EMPTY interrupt
 	 * to resume the SMBUS transaction.
 	 */
-	regmap_update_bits(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY,
-			   DW_IC_INTR_TX_EMPTY);
+	__i2c_dw_read_intr_mask(dev, &intr_mask);
+	intr_mask |= DW_IC_INTR_TX_EMPTY;
+	__i2c_dw_write_intr_mask(dev, intr_mask);
 
 	return len;
 }
@@ -827,7 +829,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 		 * interrupt really came from this HW (E.g. firmware has left
 		 * the HW active).
 		 */
-		regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+		__i2c_dw_write_intr_mask(dev, 0);
 		return IRQ_HANDLED;
 	}
 
@@ -840,7 +842,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 		 * Anytime TX_ABRT is set, the contents of the tx/rx
 		 * buffers are flushed. Make sure to skip them.
 		 */
-		regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+		__i2c_dw_write_intr_mask(dev, 0);
 		goto tx_aborted;
 	}
 
@@ -862,9 +864,9 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 		complete(&dev->cmd_complete);
 	else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
 		/* Workaround to trigger pending interrupt */
-		regmap_read(dev->map, DW_IC_INTR_MASK, &stat);
-		regmap_write(dev->map, DW_IC_INTR_MASK, 0);
-		regmap_write(dev->map, DW_IC_INTR_MASK, stat);
+		__i2c_dw_read_intr_mask(dev, &stat);
+		__i2c_dw_write_intr_mask(dev, 0);
+		__i2c_dw_write_intr_mask(dev, stat);
 	}
 
 	return IRQ_HANDLED;
@@ -1016,7 +1018,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
 	if (ret)
 		return ret;
 
-	regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+	__i2c_dw_write_intr_mask(dev, 0);
 	i2c_dw_release_lock(dev);
 
 	if (!(dev->flags & ACCESS_POLLING)) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 7/9] i2c: designware: Move interrupt handling functions before i2c_dw_xfer()
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
                   ` (5 preceding siblings ...)
  2024-02-06 14:51 ` [PATCH v2 6/9] i2c: designware: Use accessors to DW_IC_INTR_MASK register Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 15:18   ` Andy Shevchenko
  2024-02-06 14:51 ` [PATCH v2 8/9] i2c: designware: Fix RX FIFO depth define on Wangxun 10Gb NIC Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 9/9] i2c: designware: Implement generic polling mode code for " Jarkko Nikula
  8 siblings, 1 reply; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

Code is more logically arranged when i2c_dw_read_clear_intrbits() and
i2c_dw_isr() are located before i2c_dw_xfer().

Real reason for this is to prepare for more shared code between
interrupt and polling mode code.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-master.c | 226 ++++++++++-----------
 1 file changed, 113 insertions(+), 113 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 2e8f9733ddd3..856c955c6560 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -633,119 +633,6 @@ i2c_dw_read(struct dw_i2c_dev *dev)
 	}
 }
 
-/*
- * Prepare controller for a transaction and call i2c_dw_xfer_msg.
- */
-static int
-i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
-{
-	struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
-	int ret;
-
-	dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
-
-	pm_runtime_get_sync(dev->dev);
-
-	/*
-	 * Initiate I2C message transfer when polling mode is enabled,
-	 * As it is polling based transfer mechanism, which does not support
-	 * interrupt based functionalities of existing DesignWare driver.
-	 */
-	switch (dev->flags & MODEL_MASK) {
-	case MODEL_AMD_NAVI_GPU:
-		ret = amd_i2c_dw_xfer_quirk(adap, msgs, num);
-		goto done_nolock;
-	case MODEL_WANGXUN_SP:
-		ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num);
-		goto done_nolock;
-	default:
-		break;
-	}
-
-	reinit_completion(&dev->cmd_complete);
-	dev->msgs = msgs;
-	dev->msgs_num = num;
-	dev->cmd_err = 0;
-	dev->msg_write_idx = 0;
-	dev->msg_read_idx = 0;
-	dev->msg_err = 0;
-	dev->status = 0;
-	dev->abort_source = 0;
-	dev->rx_outstanding = 0;
-
-	ret = i2c_dw_acquire_lock(dev);
-	if (ret)
-		goto done_nolock;
-
-	ret = i2c_dw_wait_bus_not_busy(dev);
-	if (ret < 0)
-		goto done;
-
-	/* Start the transfers */
-	i2c_dw_xfer_init(dev);
-
-	/* Wait for tx to complete */
-	if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
-		dev_err(dev->dev, "controller timed out\n");
-		/* i2c_dw_init implicitly disables the adapter */
-		i2c_recover_bus(&dev->adapter);
-		i2c_dw_init_master(dev);
-		ret = -ETIMEDOUT;
-		goto done;
-	}
-
-	/*
-	 * We must disable the adapter before returning and signaling the end
-	 * of the current transfer. Otherwise the hardware might continue
-	 * generating interrupts which in turn causes a race condition with
-	 * the following transfer.  Needs some more investigation if the
-	 * additional interrupts are a hardware bug or this driver doesn't
-	 * handle them correctly yet.
-	 */
-	__i2c_dw_disable_nowait(dev);
-
-	if (dev->msg_err) {
-		ret = dev->msg_err;
-		goto done;
-	}
-
-	/* No error */
-	if (likely(!dev->cmd_err && !dev->status)) {
-		ret = num;
-		goto done;
-	}
-
-	/* We have an error */
-	if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
-		ret = i2c_dw_handle_tx_abort(dev);
-		goto done;
-	}
-
-	if (dev->status)
-		dev_err(dev->dev,
-			"transfer terminated early - interrupt latency too high?\n");
-
-	ret = -EIO;
-
-done:
-	i2c_dw_release_lock(dev);
-
-done_nolock:
-	pm_runtime_mark_last_busy(dev->dev);
-	pm_runtime_put_autosuspend(dev->dev);
-
-	return ret;
-}
-
-static const struct i2c_algorithm i2c_dw_algo = {
-	.master_xfer = i2c_dw_xfer,
-	.functionality = i2c_dw_func,
-};
-
-static const struct i2c_adapter_quirks i2c_dw_quirks = {
-	.flags = I2C_AQ_NO_ZERO_LEN,
-};
-
 static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
 {
 	unsigned int stat, dummy;
@@ -872,6 +759,119 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/*
+ * Prepare controller for a transaction and call i2c_dw_xfer_msg.
+ */
+static int
+i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+	int ret;
+
+	dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+	pm_runtime_get_sync(dev->dev);
+
+	/*
+	 * Initiate I2C message transfer when polling mode is enabled,
+	 * As it is polling based transfer mechanism, which does not support
+	 * interrupt based functionalities of existing DesignWare driver.
+	 */
+	switch (dev->flags & MODEL_MASK) {
+	case MODEL_AMD_NAVI_GPU:
+		ret = amd_i2c_dw_xfer_quirk(adap, msgs, num);
+		goto done_nolock;
+	case MODEL_WANGXUN_SP:
+		ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num);
+		goto done_nolock;
+	default:
+		break;
+	}
+
+	reinit_completion(&dev->cmd_complete);
+	dev->msgs = msgs;
+	dev->msgs_num = num;
+	dev->cmd_err = 0;
+	dev->msg_write_idx = 0;
+	dev->msg_read_idx = 0;
+	dev->msg_err = 0;
+	dev->status = 0;
+	dev->abort_source = 0;
+	dev->rx_outstanding = 0;
+
+	ret = i2c_dw_acquire_lock(dev);
+	if (ret)
+		goto done_nolock;
+
+	ret = i2c_dw_wait_bus_not_busy(dev);
+	if (ret < 0)
+		goto done;
+
+	/* Start the transfers */
+	i2c_dw_xfer_init(dev);
+
+	/* Wait for tx to complete */
+	if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
+		dev_err(dev->dev, "controller timed out\n");
+		/* i2c_dw_init implicitly disables the adapter */
+		i2c_recover_bus(&dev->adapter);
+		i2c_dw_init_master(dev);
+		ret = -ETIMEDOUT;
+		goto done;
+	}
+
+	/*
+	 * We must disable the adapter before returning and signaling the end
+	 * of the current transfer. Otherwise the hardware might continue
+	 * generating interrupts which in turn causes a race condition with
+	 * the following transfer.  Needs some more investigation if the
+	 * additional interrupts are a hardware bug or this driver doesn't
+	 * handle them correctly yet.
+	 */
+	__i2c_dw_disable_nowait(dev);
+
+	if (dev->msg_err) {
+		ret = dev->msg_err;
+		goto done;
+	}
+
+	/* No error */
+	if (likely(!dev->cmd_err && !dev->status)) {
+		ret = num;
+		goto done;
+	}
+
+	/* We have an error */
+	if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
+		ret = i2c_dw_handle_tx_abort(dev);
+		goto done;
+	}
+
+	if (dev->status)
+		dev_err(dev->dev,
+			"transfer terminated early - interrupt latency too high?\n");
+
+	ret = -EIO;
+
+done:
+	i2c_dw_release_lock(dev);
+
+done_nolock:
+	pm_runtime_mark_last_busy(dev->dev);
+	pm_runtime_put_autosuspend(dev->dev);
+
+	return ret;
+}
+
+static const struct i2c_algorithm i2c_dw_algo = {
+	.master_xfer = i2c_dw_xfer,
+	.functionality = i2c_dw_func,
+};
+
+static const struct i2c_adapter_quirks i2c_dw_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN,
+};
+
 void i2c_dw_configure_master(struct dw_i2c_dev *dev)
 {
 	struct i2c_timings *t = &dev->timings;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 8/9] i2c: designware: Fix RX FIFO depth define on Wangxun 10Gb NIC
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
                   ` (6 preceding siblings ...)
  2024-02-06 14:51 ` [PATCH v2 7/9] i2c: designware: Move interrupt handling functions before i2c_dw_xfer() Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 14:51 ` [PATCH v2 9/9] i2c: designware: Implement generic polling mode code for " Jarkko Nikula
  8 siblings, 0 replies; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

I believe RX FIFO depth define 0 is incorrect on Wangxun 10Gb NIC. It
must be at least 1 since code is able to read received data from the
DW_IC_DATA_CMD register.

For now this define is irrelevant since the txgbe_i2c_dw_xfer_quirk()
doesn't use the rx_fifo_depth member variable of struct dw_i2c_dev but
is needed when converting code into generic polling mode implementation.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-core.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index ee1dbdb52d3e..94da70ce1f32 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -320,7 +320,7 @@ struct dw_i2c_dev {
 #define AMD_UCSI_INTR_EN			0xd
 
 #define TXGBE_TX_FIFO_DEPTH			4
-#define TXGBE_RX_FIFO_DEPTH			0
+#define TXGBE_RX_FIFO_DEPTH			1
 
 struct i2c_dw_semaphore_callbacks {
 	int	(*probe)(struct dw_i2c_dev *dev);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 9/9] i2c: designware: Implement generic polling mode code for Wangxun 10Gb NIC
  2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
                   ` (7 preceding siblings ...)
  2024-02-06 14:51 ` [PATCH v2 8/9] i2c: designware: Fix RX FIFO depth define on Wangxun 10Gb NIC Jarkko Nikula
@ 2024-02-06 14:51 ` Jarkko Nikula
  2024-02-06 15:28   ` Andy Shevchenko
  8 siblings, 1 reply; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-06 14:51 UTC (permalink / raw)
  To: linux-i2c
  Cc: Andi Shyti, Andy Shevchenko, Mika Westerberg, Jan Dabros,
	Jiawen Wu, Sanket Goswami, Basavaraj Natikar, michael.j.ruhl,
	Hans de Goede, Jarkko Nikula

I got an idea the i2c-designware should not need duplicated state
machines for the interrupt and polling modes. The IP is practically the
same and state transitions happens in response to the events that can be
observed from the DW_IC_RAW_INTR_STAT register. Either by interrupts or
by polling.

Another reasons are the interrupt mode is the most tested, has handling
for special cases as well as transmit abort handling and those are
missing from two polling mode quirks.

Patch implements a generic polling mode by using existing code for
interrupt mode. This is done by moving event handling from the
i2c_dw_isr() into a new i2c_dw_process_transfer() that will be called
both from the i2c_dw_isr() and a polling loop.

Polling loop is implemented in a new i2c_dw_wait_transfer() that is
shared between both modes. In interrupt mode it waits for the completion
object as before. In polling mode both completion object and
DW_IC_RAW_INTR_STAT are polled to determine completed transfer and state
transitions.

Loop tries to save power by sleeping "stetson guessed" range between
3 and 25 µS which falls between 10 cycles of High-speed mode 3.4 Mb/s
and Fast mode 400 kHz. With it the CPU usage was reduced under heavy
Fast mode I2C transfer without much increase in total transfer time but
otherwise no more effort has been put to optimize this.

I decided to convert the txgbe_i2c_dw_xfer_quirk() straight to generic
polling mode code in this patch. It doesn't have HW dependent quirks
like the amd_i2c_dw_xfer_quirk() does have and without users this patch
is needless.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-core.h   |   5 +
 drivers/i2c/busses/i2c-designware-master.c | 169 +++++++++------------
 2 files changed, 77 insertions(+), 97 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 94da70ce1f32..b62206db4f09 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -212,6 +212,7 @@ struct reset_control;
  * @msg_err: error status of the current transfer
  * @status: i2c master status, one of STATUS_*
  * @abort_source: copy of the TX_ABRT_SOURCE register
+ * @sw_mask: SW mask of DW_IC_INTR_MASK used in polling mode
  * @irq: interrupt number for the i2c master
  * @flags: platform specific flags like type of IO accessors or model
  * @adapter: i2c subsystem adapter node
@@ -269,6 +270,7 @@ struct dw_i2c_dev {
 	int			msg_err;
 	unsigned int		status;
 	unsigned int		abort_source;
+	unsigned int		sw_mask;
 	int			irq;
 	u32			flags;
 	struct i2c_adapter	adapter;
@@ -359,6 +361,7 @@ static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev,
 	unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask;
 
 	regmap_write(dev->map, DW_IC_INTR_MASK, val);
+	dev->sw_mask = intr_mask;
 }
 
 static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev,
@@ -366,6 +369,8 @@ static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev,
 {
 	if (!(dev->flags & ACCESS_POLLING))
 		regmap_read(dev->map, DW_IC_INTR_MASK, intr_mask);
+	else
+		*intr_mask = dev->sw_mask;
 }
 
 void __i2c_dw_disable(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 856c955c6560..5897fad544c0 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -354,67 +354,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
 	return 0;
 }
 
-static int i2c_dw_poll_tx_empty(struct dw_i2c_dev *dev)
-{
-	u32 val;
-
-	return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val,
-					val & DW_IC_INTR_TX_EMPTY,
-					100, 1000);
-}
-
-static int i2c_dw_poll_rx_full(struct dw_i2c_dev *dev)
-{
-	u32 val;
-
-	return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val,
-					val & DW_IC_INTR_RX_FULL,
-					100, 1000);
-}
-
-static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
-				   int num_msgs)
-{
-	struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
-	int msg_idx, buf_len, data_idx, ret;
-	unsigned int val, stop = 0;
-	u8 *buf;
-
-	dev->msgs = msgs;
-	dev->msgs_num = num_msgs;
-	i2c_dw_xfer_init(dev);
-
-	for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) {
-		buf = msgs[msg_idx].buf;
-		buf_len = msgs[msg_idx].len;
-
-		for (data_idx = 0; data_idx < buf_len; data_idx++) {
-			if (msg_idx == num_msgs - 1 && data_idx == buf_len - 1)
-				stop |= BIT(9);
-
-			if (msgs[msg_idx].flags & I2C_M_RD) {
-				regmap_write(dev->map, DW_IC_DATA_CMD, 0x100 | stop);
-
-				ret = i2c_dw_poll_rx_full(dev);
-				if (ret)
-					return ret;
-
-				regmap_read(dev->map, DW_IC_DATA_CMD, &val);
-				buf[data_idx] = val;
-			} else {
-				ret = i2c_dw_poll_tx_empty(dev);
-				if (ret)
-					return ret;
-
-				regmap_write(dev->map, DW_IC_DATA_CMD,
-					     buf[data_idx] | stop);
-			}
-		}
-	}
-
-	return num_msgs;
-}
-
 /*
  * Initiate (and continue) low level master read/write transaction.
  * This function is only called from i2c_dw_isr, and pumping i2c_msg
@@ -649,7 +588,12 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
 	 *
 	 * The raw version might be useful for debugging purposes.
 	 */
-	regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
+	if (!(dev->flags & ACCESS_POLLING)) {
+		regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
+	} else {
+		regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
+		stat &= dev->sw_mask;
+	}
 
 	/*
 	 * Do not use the IC_CLR_INTR register to clear interrupts, or
@@ -689,37 +633,8 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
 	return stat;
 }
 
-/*
- * Interrupt service routine. This gets called whenever an I2C master interrupt
- * occurs.
- */
-static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+static void i2c_dw_process_transfer(struct dw_i2c_dev *dev, unsigned int stat)
 {
-	struct dw_i2c_dev *dev = dev_id;
-	unsigned int stat, enabled;
-
-	regmap_read(dev->map, DW_IC_ENABLE, &enabled);
-	regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
-	if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
-		return IRQ_NONE;
-	if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0))
-		return IRQ_NONE;
-	dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat);
-
-	stat = i2c_dw_read_clear_intrbits(dev);
-
-	if (!(dev->status & STATUS_ACTIVE)) {
-		/*
-		 * Unexpected interrupt in driver point of view. State
-		 * variables are either unset or stale so acknowledge and
-		 * disable interrupts for suppressing further interrupts if
-		 * interrupt really came from this HW (E.g. firmware has left
-		 * the HW active).
-		 */
-		__i2c_dw_write_intr_mask(dev, 0);
-		return IRQ_HANDLED;
-	}
-
 	if (stat & DW_IC_INTR_TX_ABRT) {
 		dev->cmd_err |= DW_IC_ERR_TX_ABRT;
 		dev->status &= ~STATUS_MASK;
@@ -755,10 +670,73 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 		__i2c_dw_write_intr_mask(dev, 0);
 		__i2c_dw_write_intr_mask(dev, stat);
 	}
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C master interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+{
+	struct dw_i2c_dev *dev = dev_id;
+	unsigned int stat, enabled;
+
+	regmap_read(dev->map, DW_IC_ENABLE, &enabled);
+	regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
+	if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+		return IRQ_NONE;
+	if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0))
+		return IRQ_NONE;
+	dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat);
+
+	stat = i2c_dw_read_clear_intrbits(dev);
+
+	if (!(dev->status & STATUS_ACTIVE)) {
+		/*
+		 * Unexpected interrupt in driver point of view. State
+		 * variables are either unset or stale so acknowledge and
+		 * disable interrupts for suppressing further interrupts if
+		 * interrupt really came from this HW (E.g. firmware has left
+		 * the HW active).
+		 */
+		__i2c_dw_write_intr_mask(dev, 0);
+		return IRQ_HANDLED;
+	}
+
+	i2c_dw_process_transfer(dev, stat);
 
 	return IRQ_HANDLED;
 }
 
+static int i2c_dw_wait_transfer(struct dw_i2c_dev *dev)
+{
+	unsigned long timeout = dev->adapter.timeout;
+	unsigned int stat;
+	int ret = 0;
+
+	if (!(dev->flags & ACCESS_POLLING)) {
+		ret = wait_for_completion_timeout(&dev->cmd_complete,
+						  timeout) ? 0 : -ETIMEDOUT;
+	} else {
+		timeout += jiffies;
+		do {
+			if (try_wait_for_completion(&dev->cmd_complete))
+				goto out;
+
+			stat = i2c_dw_read_clear_intrbits(dev);
+			if (stat)
+				i2c_dw_process_transfer(dev, stat);
+			else
+				/* Try save some power */
+				usleep_range(3, 25);
+		} while (time_before(jiffies, timeout));
+		ret = ETIMEDOUT;
+	}
+
+out:
+	return ret;
+}
+
 /*
  * Prepare controller for a transaction and call i2c_dw_xfer_msg.
  */
@@ -781,9 +759,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	case MODEL_AMD_NAVI_GPU:
 		ret = amd_i2c_dw_xfer_quirk(adap, msgs, num);
 		goto done_nolock;
-	case MODEL_WANGXUN_SP:
-		ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num);
-		goto done_nolock;
 	default:
 		break;
 	}
@@ -811,12 +786,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	i2c_dw_xfer_init(dev);
 
 	/* Wait for tx to complete */
-	if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
+	ret = i2c_dw_wait_transfer(dev);
+	if (ret) {
 		dev_err(dev->dev, "controller timed out\n");
 		/* i2c_dw_init implicitly disables the adapter */
 		i2c_recover_bus(&dev->adapter);
 		i2c_dw_init_master(dev);
-		ret = -ETIMEDOUT;
 		goto done;
 	}
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 4/9] i2c: designware: Uniform initialization flow for polling mode
  2024-02-06 14:51 ` [PATCH v2 4/9] i2c: designware: Uniform initialization flow for polling mode Jarkko Nikula
@ 2024-02-06 15:13   ` Andy Shevchenko
  0 siblings, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2024-02-06 15:13 UTC (permalink / raw)
  To: Jarkko Nikula
  Cc: linux-i2c, Andi Shyti, Mika Westerberg, Jan Dabros, Jiawen Wu,
	Sanket Goswami, Basavaraj Natikar, michael.j.ruhl, Hans de Goede

On Tue, Feb 06, 2024 at 04:51:53PM +0200, Jarkko Nikula wrote:
> Currently initialization flow in i2c_dw_probe_master() skips a few steps
> and has code duplication for polling mode implementation.
> 
> Simplify this by adding a new ACCESS_POLLING flag that is set for those
> two platforms that currently use polling mode and use it to skip
> interrupt handler setup.

...

>  #define ACCESS_INTR_MASK			BIT(0)
>  #define ACCESS_NO_IRQ_SUSPEND			BIT(1)
> +#define ACCESS_POLLING				BIT(3)

Bit 2 is free now, no?

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 7/9] i2c: designware: Move interrupt handling functions before i2c_dw_xfer()
  2024-02-06 14:51 ` [PATCH v2 7/9] i2c: designware: Move interrupt handling functions before i2c_dw_xfer() Jarkko Nikula
@ 2024-02-06 15:18   ` Andy Shevchenko
  0 siblings, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2024-02-06 15:18 UTC (permalink / raw)
  To: Jarkko Nikula
  Cc: linux-i2c, Andi Shyti, Mika Westerberg, Jan Dabros, Jiawen Wu,
	Sanket Goswami, Basavaraj Natikar, michael.j.ruhl, Hans de Goede

On Tue, Feb 06, 2024 at 04:51:56PM +0200, Jarkko Nikula wrote:
> Code is more logically arranged when i2c_dw_read_clear_intrbits() and
> i2c_dw_isr() are located before i2c_dw_xfer().
> 
> Real reason for this is to prepare for more shared code between
> interrupt and polling mode code.

...

> +	/*
> +	 * We must disable the adapter before returning and signaling the end
> +	 * of the current transfer. Otherwise the hardware might continue
> +	 * generating interrupts which in turn causes a race condition with
> +	 * the following transfer.  Needs some more investigation if the

While at it, you may make it consistent, i.e. by dropping an extra space.

> +	 * additional interrupts are a hardware bug or this driver doesn't
> +	 * handle them correctly yet.
> +	 */

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 9/9] i2c: designware: Implement generic polling mode code for Wangxun 10Gb NIC
  2024-02-06 14:51 ` [PATCH v2 9/9] i2c: designware: Implement generic polling mode code for " Jarkko Nikula
@ 2024-02-06 15:28   ` Andy Shevchenko
  0 siblings, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2024-02-06 15:28 UTC (permalink / raw)
  To: Jarkko Nikula
  Cc: linux-i2c, Andi Shyti, Mika Westerberg, Jan Dabros, Jiawen Wu,
	Sanket Goswami, Basavaraj Natikar, michael.j.ruhl, Hans de Goede

On Tue, Feb 06, 2024 at 04:51:58PM +0200, Jarkko Nikula wrote:
> I got an idea the i2c-designware should not need duplicated state
> machines for the interrupt and polling modes. The IP is practically the
> same and state transitions happens in response to the events that can be
> observed from the DW_IC_RAW_INTR_STAT register. Either by interrupts or
> by polling.
> 
> Another reasons are the interrupt mode is the most tested, has handling
> for special cases as well as transmit abort handling and those are
> missing from two polling mode quirks.
> 
> Patch implements a generic polling mode by using existing code for
> interrupt mode. This is done by moving event handling from the
> i2c_dw_isr() into a new i2c_dw_process_transfer() that will be called
> both from the i2c_dw_isr() and a polling loop.
> 
> Polling loop is implemented in a new i2c_dw_wait_transfer() that is
> shared between both modes. In interrupt mode it waits for the completion
> object as before. In polling mode both completion object and
> DW_IC_RAW_INTR_STAT are polled to determine completed transfer and state
> transitions.
> 
> Loop tries to save power by sleeping "stetson guessed" range between
> 3 and 25 µS which falls between 10 cycles of High-speed mode 3.4 Mb/s
> and Fast mode 400 kHz. With it the CPU usage was reduced under heavy
> Fast mode I2C transfer without much increase in total transfer time but
> otherwise no more effort has been put to optimize this.
> 
> I decided to convert the txgbe_i2c_dw_xfer_quirk() straight to generic
> polling mode code in this patch. It doesn't have HW dependent quirks
> like the amd_i2c_dw_xfer_quirk() does have and without users this patch
> is needless.

...

I believe even with a single point of out we may do better this one, see below.

> +static int i2c_dw_wait_transfer(struct dw_i2c_dev *dev)
> +{
> +	unsigned long timeout = dev->adapter.timeout;
> +	unsigned int stat;

> +	int ret = 0;

	int ret;

> +	if (!(dev->flags & ACCESS_POLLING)) {
> +		ret = wait_for_completion_timeout(&dev->cmd_complete,
> +						  timeout) ? 0 : -ETIMEDOUT;

		ret = wait_for_completion_timeout(&dev->cmd_complete, timeout);

> +	} else {
> +		timeout += jiffies;
> +		do {
> +			if (try_wait_for_completion(&dev->cmd_complete))
> +				goto out;

				break;

> +			stat = i2c_dw_read_clear_intrbits(dev);
> +			if (stat)
> +				i2c_dw_process_transfer(dev, stat);
> +			else
> +				/* Try save some power */
> +				usleep_range(3, 25);
> +		} while (time_before(jiffies, timeout));

> +		ret = ETIMEDOUT;

		ret = time_before(jiffies, timeout);

> +	}

> +out:

	if (ret)
		return 0;

	return -ETIMEDOUT;

> +	return ret;
> +}

This will make same error code for both branches without need to synchronise,
meaning better maintenance.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info
  2024-02-06 14:51 ` [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info Jarkko Nikula
@ 2024-02-06 15:30   ` Andy Shevchenko
  2024-02-09 14:14     ` Jarkko Nikula
  0 siblings, 1 reply; 16+ messages in thread
From: Andy Shevchenko @ 2024-02-06 15:30 UTC (permalink / raw)
  To: Jarkko Nikula
  Cc: linux-i2c, Andi Shyti, Mika Westerberg, Jan Dabros, Jiawen Wu,
	Sanket Goswami, Basavaraj Natikar, michael.j.ruhl, Hans de Goede

On Tue, Feb 06, 2024 at 04:51:50PM +0200, Jarkko Nikula wrote:
> From: "Michael J. Ruhl" <michael.j.ruhl@intel.com>
> 
> Currently the way to identify a model is via a bit field, of which
> 4 bits are currently defined.
> 
> Use a shifted value to that more models can be defined.

> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

While this is true review, internally we're still discussing
the possibility of moving to plain numbers and shift, so we
may add arrays which are indexed in model-based way.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info
  2024-02-06 15:30   ` Andy Shevchenko
@ 2024-02-09 14:14     ` Jarkko Nikula
  2024-02-09 14:25       ` Andy Shevchenko
  0 siblings, 1 reply; 16+ messages in thread
From: Jarkko Nikula @ 2024-02-09 14:14 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-i2c, Andi Shyti, Mika Westerberg, Jan Dabros, Jiawen Wu,
	Sanket Goswami, Basavaraj Natikar, michael.j.ruhl, Hans de Goede

On 2/6/24 17:30, Andy Shevchenko wrote:
> On Tue, Feb 06, 2024 at 04:51:50PM +0200, Jarkko Nikula wrote:
>> From: "Michael J. Ruhl" <michael.j.ruhl@intel.com>
>>
>> Currently the way to identify a model is via a bit field, of which
>> 4 bits are currently defined.
>>
>> Use a shifted value to that more models can be defined.
> 
>> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>> Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> 
> While this is true review, internally we're still discussing
> the possibility of moving to plain numbers and shift, so we
> may add arrays which are indexed in model-based way.
> 
I was thinking I'll drop these first 3 patches in the next version and 
go back to v1 version. IMHO it's better this patchset to focus 
implementing generic polling only and not mix with cleaning up the 
semaphore or other random stuff.

So planning to go back to v1 version and take your notes for v2 7/9 and 
9/9. What would you think?

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info
  2024-02-09 14:14     ` Jarkko Nikula
@ 2024-02-09 14:25       ` Andy Shevchenko
  0 siblings, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2024-02-09 14:25 UTC (permalink / raw)
  To: Jarkko Nikula
  Cc: linux-i2c, Andi Shyti, Mika Westerberg, Jan Dabros, Jiawen Wu,
	Sanket Goswami, Basavaraj Natikar, michael.j.ruhl, Hans de Goede

On Fri, Feb 09, 2024 at 04:14:37PM +0200, Jarkko Nikula wrote:
> On 2/6/24 17:30, Andy Shevchenko wrote:

...

> I was thinking I'll drop these first 3 patches in the next version and go
> back to v1 version. IMHO it's better this patchset to focus implementing
> generic polling only and not mix with cleaning up the semaphore or other
> random stuff.
> 
> So planning to go back to v1 version and take your notes for v2 7/9 and 9/9.
> What would you think?

I'm fine with that.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2024-02-09 14:25 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-06 14:51 [PATCH v2 0/9] i2c: designware: Generic polling mode code Jarkko Nikula
2024-02-06 14:51 ` [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info Jarkko Nikula
2024-02-06 15:30   ` Andy Shevchenko
2024-02-09 14:14     ` Jarkko Nikula
2024-02-09 14:25       ` Andy Shevchenko
2024-02-06 14:51 ` [PATCH v2 2/9] i2c: designware: Convert arbitration semaphore flag as semaphore type Jarkko Nikula
2024-02-06 14:51 ` [PATCH v2 3/9] i2c: designware: Convert shared_with_punit boolean " Jarkko Nikula
2024-02-06 14:51 ` [PATCH v2 4/9] i2c: designware: Uniform initialization flow for polling mode Jarkko Nikula
2024-02-06 15:13   ` Andy Shevchenko
2024-02-06 14:51 ` [PATCH v2 5/9] i2c: designware: Do not enable interrupts shortly in " Jarkko Nikula
2024-02-06 14:51 ` [PATCH v2 6/9] i2c: designware: Use accessors to DW_IC_INTR_MASK register Jarkko Nikula
2024-02-06 14:51 ` [PATCH v2 7/9] i2c: designware: Move interrupt handling functions before i2c_dw_xfer() Jarkko Nikula
2024-02-06 15:18   ` Andy Shevchenko
2024-02-06 14:51 ` [PATCH v2 8/9] i2c: designware: Fix RX FIFO depth define on Wangxun 10Gb NIC Jarkko Nikula
2024-02-06 14:51 ` [PATCH v2 9/9] i2c: designware: Implement generic polling mode code for " Jarkko Nikula
2024-02-06 15:28   ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox