提交 4b32e61d 编写于 作者: U Uwe Kleine-König 提交者: Zheng Zengkai

i2c: imx: Make sure to unregister adapter on remove()

stable inclusion
from stable-v5.10.138
commit b5ba5c36694d25e8267b767228a08df4e81760bd
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I60QFD

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=b5ba5c36694d25e8267b767228a08df4e81760bd

--------------------------------

commit d98bdd3a 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: 588eb93e ("i2c: imx: add runtime pm support to improve the performance")
Signed-off-by: NUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: NOleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: NWolfram Sang <wsa@kernel.org>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
Reviewed-by: NWei Li <liwei391@huawei.com>
上级 36102f8e
...@@ -1280,9 +1280,7 @@ static int i2c_imx_remove(struct platform_device *pdev) ...@@ -1280,9 +1280,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev); struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
int irq, ret; int irq, ret;
ret = pm_runtime_resume_and_get(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
return ret;
/* remove adapter */ /* remove adapter */
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
...@@ -1291,17 +1289,21 @@ static int i2c_imx_remove(struct platform_device *pdev) ...@@ -1291,17 +1289,21 @@ static int i2c_imx_remove(struct platform_device *pdev)
if (i2c_imx->dma) if (i2c_imx->dma)
i2c_imx_dma_free(i2c_imx); i2c_imx_dma_free(i2c_imx);
/* setup chip registers to defaults */ if (ret == 0) {
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR); /* setup chip registers to defaults */
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); 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); clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq >= 0) if (irq >= 0)
free_irq(irq, i2c_imx); free_irq(irq, i2c_imx);
clk_disable_unprepare(i2c_imx->clk);
clk_unprepare(i2c_imx->clk);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册