Loading drivers/i2c/busses/i2c-msm-geni.c +51 −4 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/clk.h> Loading Loading @@ -136,10 +137,12 @@ struct geni_i2c_dev { bool disable_dma_mode; bool prev_cancel_pending; //Halt cancel till IOS in good state bool is_i2c_rtl_based; /* doing pending cancel only for rtl based SE's */ atomic_t is_xfer_in_progress; /* Used to maintain xfer inprogress status */ }; static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; static int arr_idx; static int geni_i2c_runtime_suspend(struct device *dev); struct geni_i2c_err_log { int err; Loading Loading @@ -1052,11 +1055,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; atomic_set(&gi2c->is_xfer_in_progress, 1); /* Client to respect system suspend */ if (!pm_runtime_enabled(gi2c->dev)) { GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "%s: System suspended\n", __func__); atomic_set(&gi2c->is_xfer_in_progress, 0); return -EACCES; } Loading @@ -1068,6 +1073,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_put_noidle(gi2c->dev); /* Set device in suspended since resume failed */ pm_runtime_set_suspended(gi2c->dev); atomic_set(&gi2c->is_xfer_in_progress, 0); return ret; } } Loading @@ -1078,6 +1084,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, if (ret) { pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); atomic_set(&gi2c->is_xfer_in_progress, 0); return ret; //Don't perform xfer is cancel failed } } Loading Loading @@ -1268,7 +1275,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); } atomic_set(&gi2c->is_xfer_in_progress, 0); gi2c->cur = NULL; GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c txn ret:%d, num:%d, err:%d\n", ret, num, gi2c->err); Loading Loading @@ -1476,10 +1483,10 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } atomic_set(&gi2c->is_xfer_in_progress, 0); snprintf(boot_marker, sizeof(boot_marker), "M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr); place_marker(boot_marker); dev_info(gi2c->dev, "I2C probed\n"); return 0; } Loading @@ -1489,6 +1496,33 @@ static int geni_i2c_remove(struct platform_device *pdev) struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); int i; if (atomic_read(&gi2c->is_xfer_in_progress)) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s: Xfer is in progress\n", __func__); return -EBUSY; } if (!pm_runtime_status_suspended(gi2c->dev)) { if (geni_i2c_runtime_suspend(gi2c->dev)) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s: runtime suspend failed\n", __func__); } if (gi2c->se_mode == GSI_ONLY) { if (gi2c->tx_c) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s: clearing tx dma resource\n", __func__); dma_release_channel(gi2c->tx_c); } if (gi2c->rx_c) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s: clearing rx dma resource\n", __func__); dma_release_channel(gi2c->rx_c); } } pm_runtime_put_noidle(gi2c->dev); pm_runtime_set_suspended(gi2c->dev); pm_runtime_disable(gi2c->dev); i2c_del_adapter(&gi2c->adap); Loading Loading @@ -1594,6 +1628,19 @@ static int geni_i2c_suspend_late(struct device *device) int ret; GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); if (atomic_read(&gi2c->is_xfer_in_progress)) { if (!pm_runtime_status_suspended(gi2c->dev)) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, ":%s: runtime PM is active\n", __func__); return -EBUSY; } GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s System suspend not allowed while xfer in progress\n", __func__); return -EBUSY; } /* Make sure no transactions are pending */ ret = i2c_trylock_bus(&gi2c->adap, I2C_LOCK_SEGMENT); if (!ret) { Loading Loading
drivers/i2c/busses/i2c-msm-geni.c +51 −4 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/clk.h> Loading Loading @@ -136,10 +137,12 @@ struct geni_i2c_dev { bool disable_dma_mode; bool prev_cancel_pending; //Halt cancel till IOS in good state bool is_i2c_rtl_based; /* doing pending cancel only for rtl based SE's */ atomic_t is_xfer_in_progress; /* Used to maintain xfer inprogress status */ }; static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; static int arr_idx; static int geni_i2c_runtime_suspend(struct device *dev); struct geni_i2c_err_log { int err; Loading Loading @@ -1052,11 +1055,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; atomic_set(&gi2c->is_xfer_in_progress, 1); /* Client to respect system suspend */ if (!pm_runtime_enabled(gi2c->dev)) { GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "%s: System suspended\n", __func__); atomic_set(&gi2c->is_xfer_in_progress, 0); return -EACCES; } Loading @@ -1068,6 +1073,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_put_noidle(gi2c->dev); /* Set device in suspended since resume failed */ pm_runtime_set_suspended(gi2c->dev); atomic_set(&gi2c->is_xfer_in_progress, 0); return ret; } } Loading @@ -1078,6 +1084,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, if (ret) { pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); atomic_set(&gi2c->is_xfer_in_progress, 0); return ret; //Don't perform xfer is cancel failed } } Loading Loading @@ -1268,7 +1275,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); } atomic_set(&gi2c->is_xfer_in_progress, 0); gi2c->cur = NULL; GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c txn ret:%d, num:%d, err:%d\n", ret, num, gi2c->err); Loading Loading @@ -1476,10 +1483,10 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } atomic_set(&gi2c->is_xfer_in_progress, 0); snprintf(boot_marker, sizeof(boot_marker), "M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr); place_marker(boot_marker); dev_info(gi2c->dev, "I2C probed\n"); return 0; } Loading @@ -1489,6 +1496,33 @@ static int geni_i2c_remove(struct platform_device *pdev) struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); int i; if (atomic_read(&gi2c->is_xfer_in_progress)) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s: Xfer is in progress\n", __func__); return -EBUSY; } if (!pm_runtime_status_suspended(gi2c->dev)) { if (geni_i2c_runtime_suspend(gi2c->dev)) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s: runtime suspend failed\n", __func__); } if (gi2c->se_mode == GSI_ONLY) { if (gi2c->tx_c) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s: clearing tx dma resource\n", __func__); dma_release_channel(gi2c->tx_c); } if (gi2c->rx_c) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s: clearing rx dma resource\n", __func__); dma_release_channel(gi2c->rx_c); } } pm_runtime_put_noidle(gi2c->dev); pm_runtime_set_suspended(gi2c->dev); pm_runtime_disable(gi2c->dev); i2c_del_adapter(&gi2c->adap); Loading Loading @@ -1594,6 +1628,19 @@ static int geni_i2c_suspend_late(struct device *device) int ret; GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); if (atomic_read(&gi2c->is_xfer_in_progress)) { if (!pm_runtime_status_suspended(gi2c->dev)) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, ":%s: runtime PM is active\n", __func__); return -EBUSY; } GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s System suspend not allowed while xfer in progress\n", __func__); return -EBUSY; } /* Make sure no transactions are pending */ ret = i2c_trylock_bus(&gi2c->adap, I2C_LOCK_SEGMENT); if (!ret) { Loading