diff options
author | Yuanyuan Liu <yuanliu@codeaurora.org> | 2016-08-11 15:05:42 -0700 |
---|---|---|
committer | Yuanyuan Liu <yuanliu@codeaurora.org> | 2016-08-15 12:27:12 -0700 |
commit | 1efe85c3ea782037867b276d0763686eba6cf4d2 (patch) | |
tree | 714d47044ae6f903c9d4a0f9b2091d2e2d55a94d /drivers/soc/qcom/icnss.c | |
parent | c2a2da2c9705d410c64db17cee236270b2b6f4c5 (diff) |
icnss: Vote aggre2_noc_clk through bus bandwidth framework
ICNSS uses SMMU which requires aggre2_noc_clk. Hence vote
on aggre2noc clock through bus bandwidth.
CRs-Fixed: 1053538
Change-Id: I5e300cf81bd8b653e9a5611ed60b2b770e94a863
Signed-off-by: Yuanyuan Liu <yuanliu@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom/icnss.c')
-rw-r--r-- | drivers/soc/qcom/icnss.c | 92 |
1 files changed, 52 insertions, 40 deletions
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 16ca3eaee61b..bfe2072ee554 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -33,6 +33,7 @@ #include <linux/dma-mapping.h> #include <linux/qmi_encdec.h> #include <linux/ipc_logging.h> +#include <linux/msm-bus.h> #include <soc/qcom/memory_dump.h> #include <soc/qcom/icnss.h> #include <soc/qcom/msm_qmi_interface.h> @@ -43,7 +44,6 @@ #define ICNSS_PANIC 1 #define WLFW_TIMEOUT_MS 3000 #define WLFW_SERVICE_INS_ID_V01 0 -#define SMMU_CLOCK_NAME "smmu_aggre2_noc_clk" #define MAX_PROP_SIZE 32 #define MAX_VOLTAGE_LEVEL 2 #define VREG_ON 1 @@ -203,7 +203,8 @@ static struct icnss_data { size_t smmu_iova_len; dma_addr_t smmu_iova_ipa_start; size_t smmu_iova_ipa_len; - struct clk *smmu_clk; + struct msm_bus_scale_pdata *bus_scale_table; + uint32_t bus_client; struct qmi_handle *wlfw_clnt; struct list_head event_list; spinlock_t event_lock; @@ -1789,44 +1790,60 @@ int icnss_smmu_map(struct device *dev, } EXPORT_SYMBOL(icnss_smmu_map); -static struct clk *icnss_clock_init(struct device *dev, const char *cname) +static int icnss_bw_vote(struct icnss_data *priv, int index) { - struct clk *c; - long rate; - - if (of_property_match_string(dev->of_node, "clock-names", cname) < 0) { - icnss_pr_err("Clock %s not found!", cname); - return NULL; - } - - c = devm_clk_get(dev, cname); - if (IS_ERR(c)) { - icnss_pr_err("Couldn't get clock %s!", cname); - return NULL; - } + int ret = 0; - if (clk_get_rate(c) == 0) { - rate = clk_round_rate(c, 1000); - clk_set_rate(c, rate); - } + icnss_pr_dbg("Vote %d for msm_bus, state 0x%lx\n", + index, priv->state); + ret = msm_bus_scale_client_update_request(priv->bus_client, index); + if (ret) + icnss_pr_err("Fail to vote %d: ret %d, state 0x%lx!\n", + index, ret, priv->state); - return c; + return ret; } -static int icnss_clock_enable(struct clk *c) +static int icnss_bw_init(struct icnss_data *priv) { int ret = 0; - ret = clk_prepare_enable(c); + priv->bus_scale_table = msm_bus_cl_get_pdata(priv->pdev); + if (!priv->bus_scale_table) { + icnss_pr_err("Missing entry for msm_bus scale table\n"); + return -EINVAL; + } - if (ret < 0) - icnss_pr_err("Couldn't enable clock: %d!\n", ret); + priv->bus_client = msm_bus_scale_register_client(priv->bus_scale_table); + if (!priv->bus_client) { + icnss_pr_err("Fail to register with bus_scale client\n"); + ret = -EINVAL; + goto out; + } + + ret = icnss_bw_vote(priv, 1); + if (ret) + goto out; + + return 0; + +out: + msm_bus_cl_clear_pdata(priv->bus_scale_table); return ret; } -static void icnss_clock_disable(struct clk *c) +static void icnss_bw_deinit(struct icnss_data *priv) { - clk_disable_unprepare(c); + if (!priv) + return; + + if (priv->bus_client) { + icnss_bw_vote(priv, 0); + msm_bus_scale_unregister_client(priv->bus_client); + } + + if (priv->bus_scale_table) + msm_bus_cl_clear_pdata(priv->bus_scale_table); } static int icnss_smmu_init(struct device *dev) @@ -2460,12 +2477,9 @@ static int icnss_probe(struct platform_device *pdev) goto err_smmu_init; } - penv->smmu_clk = icnss_clock_init(&pdev->dev, SMMU_CLOCK_NAME); - if (penv->smmu_clk) { - ret = icnss_clock_enable(penv->smmu_clk); - if (ret < 0) - goto err_smmu_clock_enable; - } + ret = icnss_bw_init(penv); + if (ret) + goto err_bw_init; } penv->skip_qmi = of_property_read_bool(dev->of_node, @@ -2478,7 +2492,7 @@ static int icnss_probe(struct platform_device *pdev) if (!penv->event_wq) { icnss_pr_err("Workqueue creation failed\n"); ret = -EFAULT; - goto err_smmu_clock_enable; + goto err_alloc_workqueue; } INIT_WORK(&penv->event_work, icnss_driver_event_work); @@ -2503,7 +2517,9 @@ static int icnss_probe(struct platform_device *pdev) err_qmi: if (penv->event_wq) destroy_workqueue(penv->event_wq); -err_smmu_clock_enable: +err_alloc_workqueue: + icnss_bw_deinit(penv); +err_bw_init: if (penv->smmu_mapping) icnss_smmu_remove(&pdev->dev); err_smmu_init: @@ -2538,11 +2554,7 @@ static int icnss_remove(struct platform_device *pdev) if (penv->event_wq) destroy_workqueue(penv->event_wq); - if (penv->smmu_mapping) { - if (penv->smmu_clk) - icnss_clock_disable(penv->smmu_clk); - icnss_smmu_remove(&pdev->dev); - } + icnss_bw_deinit(penv); if (penv->msa_va) dma_free_coherent(&pdev->dev, penv->msa_mem_size, |