diff options
| author | Dilip Kota <dkota@codeaurora.org> | 2016-05-09 13:06:23 +0530 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-02-27 21:03:23 -0800 |
| commit | 7f4bbffddd57edbde5db9df465de4d47b3ab654c (patch) | |
| tree | de0902986fb98f7d71c7a53cd3efa98fc5fd9fe0 /drivers/i2c | |
| parent | 3bf75ddd22dc6e7303e962a262c8d64e5ab87b15 (diff) | |
i2c-msm-v2: Enable/Disable clocks and gpios per transfer
With QUP in shared mode, enabling and disabling the
resources in runtime pm will cause failure of
transactions over the QUP that are running on other
execution environment. To avoid the failure
enable/disable gpios and clocks of QUP per transfer.
Also move the clock prepare and unprepare calls
to runtime pm APIs from the transfer API to
reduce the latencies in the transactions.
Change-Id: Ic697cdc544405d86ec7c675922c18c00fec451a6
Signed-off-by: Dilip Kota <dkota@codeaurora.org>
Signed-off-by: Shrey Vijay <shreyv@codeaurora.org>
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/busses/i2c-msm-v2.c | 70 |
1 files changed, 53 insertions, 17 deletions
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index 04b1b62f85c3..bf2a1dd7cf15 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -50,6 +50,8 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl, static int i2c_msm_pm_resume(struct device *dev); static void i2c_msm_pm_suspend(struct device *dev); static void i2c_msm_clk_path_init(struct i2c_msm_ctrl *ctrl); +static void i2c_msm_pm_pinctrl_state(struct i2c_msm_ctrl *ctrl, + bool runtime_active); /* string table for enum i2c_msm_xfer_mode_id */ const char * const i2c_msm_mode_str_tbl[] = { @@ -2157,27 +2159,54 @@ static bool i2c_msm_xfer_next_buf(struct i2c_msm_ctrl *ctrl) return true; } -static void i2c_msm_pm_clk_disable_unprepare(struct i2c_msm_ctrl *ctrl) +static void i2c_msm_pm_clk_unprepare(struct i2c_msm_ctrl *ctrl) { - clk_disable_unprepare(ctrl->rsrcs.core_clk); - clk_disable_unprepare(ctrl->rsrcs.iface_clk); + clk_unprepare(ctrl->rsrcs.core_clk); + clk_unprepare(ctrl->rsrcs.iface_clk); } -static int i2c_msm_pm_clk_prepare_enable(struct i2c_msm_ctrl *ctrl) +static int i2c_msm_pm_clk_prepare(struct i2c_msm_ctrl *ctrl) { int ret; - ret = clk_prepare_enable(ctrl->rsrcs.iface_clk); + ret = clk_prepare(ctrl->rsrcs.iface_clk); if (ret) { dev_err(ctrl->dev, - "error on clk_prepare_enable(iface_clk):%d\n", ret); + "error on clk_prepare(iface_clk):%d\n", ret); return ret; } - ret = clk_prepare_enable(ctrl->rsrcs.core_clk); + ret = clk_prepare(ctrl->rsrcs.core_clk); + if (ret) { + clk_unprepare(ctrl->rsrcs.iface_clk); + dev_err(ctrl->dev, + "error clk_prepare(core_clk):%d\n", ret); + } + return ret; +} + +static void i2c_msm_pm_clk_disable(struct i2c_msm_ctrl *ctrl) +{ + clk_disable(ctrl->rsrcs.core_clk); + clk_disable(ctrl->rsrcs.iface_clk); +} + +static int i2c_msm_pm_clk_enable(struct i2c_msm_ctrl *ctrl) +{ + int ret; + + ret = clk_enable(ctrl->rsrcs.iface_clk); + if (ret) { + dev_err(ctrl->dev, + "error on clk_enable(iface_clk):%d\n", ret); + i2c_msm_pm_clk_unprepare(ctrl); + return ret; + } + ret = clk_enable(ctrl->rsrcs.core_clk); if (ret) { - clk_disable_unprepare(ctrl->rsrcs.iface_clk); + clk_disable(ctrl->rsrcs.iface_clk); + i2c_msm_pm_clk_unprepare(ctrl); dev_err(ctrl->dev, - "error clk_prepare_enable(core_clk):%d\n", ret); + "error clk_enable(core_clk):%d\n", ret); } return ret; } @@ -2198,6 +2227,7 @@ static int i2c_msm_pm_xfer_start(struct i2c_msm_ctrl *ctrl) return -EIO; } + i2c_msm_pm_pinctrl_state(ctrl, true); pm_runtime_get_sync(ctrl->dev); /* * if runtime PM callback was not invoked (when both runtime-pm @@ -2208,7 +2238,7 @@ static int i2c_msm_pm_xfer_start(struct i2c_msm_ctrl *ctrl) i2c_msm_pm_resume(ctrl->dev); } - ret = i2c_msm_pm_clk_prepare_enable(ctrl); + ret = i2c_msm_pm_clk_enable(ctrl); if (ret) { mutex_unlock(&ctrl->xfer.mtx); return ret; @@ -2235,13 +2265,14 @@ static void i2c_msm_pm_xfer_end(struct i2c_msm_ctrl *ctrl) if (ctrl->xfer.mode_id == I2C_MSM_XFER_MODE_DMA) i2c_msm_dma_free_channels(ctrl); - i2c_msm_pm_clk_disable_unprepare(ctrl); + i2c_msm_pm_clk_disable(ctrl); if (!pm_runtime_enabled(ctrl->dev)) i2c_msm_pm_suspend(ctrl->dev); pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev); + i2c_msm_pm_pinctrl_state(ctrl, false); mutex_unlock(&ctrl->xfer.mtx); } @@ -2663,7 +2694,7 @@ static void i2c_msm_pm_suspend(struct device *dev) return; } i2c_msm_dbg(ctrl, MSM_DBG, "suspending..."); - i2c_msm_pm_pinctrl_state(ctrl, false); + i2c_msm_pm_clk_unprepare(ctrl); i2c_msm_clk_path_unvote(ctrl); /* @@ -2690,7 +2721,7 @@ static int i2c_msm_pm_resume(struct device *dev) i2c_msm_dbg(ctrl, MSM_DBG, "resuming..."); i2c_msm_clk_path_vote(ctrl); - i2c_msm_pm_pinctrl_state(ctrl, true); + i2c_msm_pm_clk_prepare(ctrl); ctrl->pwr_state = I2C_MSM_PM_RT_ACTIVE; return 0; } @@ -2870,9 +2901,13 @@ static int i2c_msm_probe(struct platform_device *pdev) /* vote for clock to enable reading the version number off the HW */ i2c_msm_clk_path_vote(ctrl); - ret = i2c_msm_pm_clk_prepare_enable(ctrl); + ret = i2c_msm_pm_clk_prepare(ctrl); + if (ret) + goto clk_err; + + ret = i2c_msm_pm_clk_enable(ctrl); if (ret) { - dev_err(ctrl->dev, "error in enabling clocks:%d\n", ret); + i2c_msm_pm_clk_unprepare(ctrl); goto clk_err; } @@ -2884,7 +2919,8 @@ static int i2c_msm_probe(struct platform_device *pdev) if (ret) dev_err(ctrl->dev, "error error on qup software reset\n"); - i2c_msm_pm_clk_disable_unprepare(ctrl); + i2c_msm_pm_clk_disable(ctrl); + i2c_msm_pm_clk_unprepare(ctrl); i2c_msm_clk_path_unvote(ctrl); ret = i2c_msm_rsrcs_gpio_pinctrl_init(ctrl); |
