* [PATCH] i2c: iop3xx: fix adapter and IRQ teardown
@ 2026-07-28 17:15 Myeonghun Pak
0 siblings, 0 replies; only message in thread
From: Myeonghun Pak @ 2026-07-28 17:15 UTC (permalink / raw)
To: Andi Shyti; +Cc: linux-i2c, linux-kernel, stable, Myeonghun Pak, Ijae Kim
The probe path enables the controller and requests its IRQ before
registering the I2C adapter, but ignores an adapter registration
failure. The remove path also frees the IRQ data and unmaps its
registers without first unregistering the adapter or IRQ handler.
Check the adapter registration result and unwind the IRQ on failure.
On removal, unregister the adapter first, then quiesce the controller
and synchronize and release the IRQ before freeing its backing
resources.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
---
drivers/i2c/busses/i2c-iop3xx.c | 31 ++++++++++++++++++++++---------
drivers/i2c/busses/i2c-iop3xx.h | 1 +
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 4c67c5d18f..c375509c93 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -89,6 +89,16 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
}
+static void
+iop3xx_i2c_disable(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+
+ cr &= ~(IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
+ IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE);
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
static void
iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
@@ -392,14 +402,10 @@ iop3xx_i2c_remove(struct platform_device *pdev)
struct i2c_algo_iop3xx_data *adapter_data =
(struct i2c_algo_iop3xx_data *)padapter->algo_data;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET);
- /*
- * Disable the actual HW unit
- */
- cr &= ~(IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
- IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE);
- __raw_writel(cr, adapter_data->ioaddr + CR_OFFSET);
+ i2c_del_adapter(padapter);
+ iop3xx_i2c_disable(adapter_data);
+ free_irq(adapter_data->irq, adapter_data);
iounmap(adapter_data->ioaddr);
release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
@@ -467,6 +473,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
ret = irq;
goto unmap;
}
+ adapter_data->irq = irq;
ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
pdev->name, adapter_data);
@@ -492,13 +499,19 @@ iop3xx_i2c_probe(struct platform_device *pdev)
iop3xx_i2c_reset(adapter_data);
iop3xx_i2c_enable(adapter_data);
- platform_set_drvdata(pdev, new_adapter);
new_adapter->algo_data = adapter_data;
- i2c_add_numbered_adapter(new_adapter);
+ ret = i2c_add_numbered_adapter(new_adapter);
+ if (ret)
+ goto disable;
+ platform_set_drvdata(pdev, new_adapter);
return 0;
+disable:
+ iop3xx_i2c_disable(adapter_data);
+ free_irq(adapter_data->irq, adapter_data);
+
unmap:
iounmap(adapter_data->ioaddr);
diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h
index 1435483355..6c07ea16bf 100644
--- a/drivers/i2c/busses/i2c-iop3xx.h
+++ b/drivers/i2c/busses/i2c-iop3xx.h
@@ -92,6 +92,7 @@ struct i2c_algo_iop3xx_data {
spinlock_t lock;
u32 SR_enabled, SR_received;
int id;
+ int irq;
struct gpio_desc *gpio_scl;
struct gpio_desc *gpio_sda;
};
--
2.47.1
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-28 17:15 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-28 17:15 [PATCH] i2c: iop3xx: fix adapter and IRQ teardown Myeonghun Pak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox