i2c: imx: Make sure to unregister adapter on remove()
commitd98bdd3a5b
upstream. 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:588eb93ea4
("i2c: imx: add runtime pm support to improve the performance") Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Acked-by: Oleksij Rempel <o.rempel@pengutronix.de> Signed-off-by: Wolfram Sang <wsa@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
b4ac11967e
Коммит
09e512a659
|
@ -1487,9 +1487,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
|
|||
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
|
||||
int irq, ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(&pdev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
/* remove adapter */
|
||||
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
|
||||
|
@ -1498,17 +1496,21 @@ static int i2c_imx_remove(struct platform_device *pdev)
|
|||
if (i2c_imx->dma)
|
||||
i2c_imx_dma_free(i2c_imx);
|
||||
|
||||
/* setup chip registers to defaults */
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
|
||||
if (ret == 0) {
|
||||
/* setup chip registers to defaults */
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
|
||||
clk_disable(i2c_imx->clk);
|
||||
}
|
||||
|
||||
clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq >= 0)
|
||||
free_irq(irq, i2c_imx);
|
||||
clk_disable_unprepare(i2c_imx->clk);
|
||||
|
||||
clk_unprepare(i2c_imx->clk);
|
||||
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
|
Загрузка…
Ссылка в новой задаче