Skip to content

Commit d98bdd3

Browse files
Uwe Kleine-Königwsakernel
authored andcommitted
i2c: imx: Make sure to unregister adapter on remove()
If for whatever reasons pm_runtime_resume_and_get() fails and .remove() is exited early, the i2c adapter stays around and the irq still calls its handler, while the driver data and the register mapping go away. So if later the i2c adapter is accessed or the irq triggers this results in havoc accessing freed memory and unmapped registers. So unregister the software resources even if resume failed, and only skip the hardware access in that case. Fixes: 588eb93 ("i2c: imx: add runtime pm support to improve the performance") Signed-off-by: Uwe Kleine-König <[email protected]> Acked-by: Oleksij Rempel <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 3df71d7 commit d98bdd3

File tree

1 file changed

+11
-9
lines changed

1 file changed

+11
-9
lines changed

drivers/i2c/busses/i2c-imx.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,9 +1572,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
15721572
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
15731573
int irq, ret;
15741574

1575-
ret = pm_runtime_resume_and_get(&pdev->dev);
1576-
if (ret < 0)
1577-
return ret;
1575+
ret = pm_runtime_get_sync(&pdev->dev);
15781576

15791577
hrtimer_cancel(&i2c_imx->slave_timer);
15801578

@@ -1585,17 +1583,21 @@ static int i2c_imx_remove(struct platform_device *pdev)
15851583
if (i2c_imx->dma)
15861584
i2c_imx_dma_free(i2c_imx);
15871585

1588-
/* setup chip registers to defaults */
1589-
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
1590-
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
1591-
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
1592-
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
1586+
if (ret == 0) {
1587+
/* setup chip registers to defaults */
1588+
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
1589+
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
1590+
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
1591+
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
1592+
clk_disable(i2c_imx->clk);
1593+
}
15931594

15941595
clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
15951596
irq = platform_get_irq(pdev, 0);
15961597
if (irq >= 0)
15971598
free_irq(irq, i2c_imx);
1598-
clk_disable_unprepare(i2c_imx->clk);
1599+
1600+
clk_unprepare(i2c_imx->clk);
15991601

16001602
pm_runtime_put_noidle(&pdev->dev);
16011603
pm_runtime_disable(&pdev->dev);

0 commit comments

Comments
 (0)