diff options
Diffstat (limited to 'drivers/clk/qcom/common.c')
| -rw-r--r-- | drivers/clk/qcom/common.c | 101 |
1 files changed, 90 insertions, 11 deletions
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 33cc1f73c69d..121591886774 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -9,10 +9,13 @@ #include <linux/platform_device.h> #include <linux/clk-provider.h> #include <linux/interconnect-clk.h> +#include <linux/pm_runtime.h> #include <linux/reset-controller.h> #include <linux/of.h> #include "common.h" +#include "clk-alpha-pll.h" +#include "clk-branch.h" #include "clk-rcg.h" #include "clk-regmap.h" #include "reset.h" @@ -22,6 +25,7 @@ struct qcom_cc { struct qcom_reset_controller reset; struct clk_regmap **rclks; size_t num_rclks; + struct dev_pm_domain_list *pd_list; }; const @@ -273,8 +277,8 @@ static int qcom_cc_icc_register(struct device *dev, icd[i].slave_id = desc->icc_hws[i].slave_id; hws = &desc->clks[desc->icc_hws[i].clk_id]->hw; icd[i].clk = devm_clk_hw_get_clk(dev, hws, "icc"); - if (!icd[i].clk) - return dev_err_probe(dev, -ENOENT, + if (IS_ERR(icd[i].clk)) + return dev_err_probe(dev, PTR_ERR(icd[i].clk), "(%d) clock entry is null\n", i); icd[i].name = clk_hw_get_name(hws); } @@ -283,6 +287,40 @@ static int qcom_cc_icc_register(struct device *dev, desc->num_icc_hws, icd); } +static int qcom_cc_clk_pll_configure(const struct qcom_cc_driver_data *data, + struct regmap *regmap) +{ + const struct clk_init_data *init; + struct clk_alpha_pll *pll; + int i; + + for (i = 0; i < data->num_alpha_plls; i++) { + pll = data->alpha_plls[i]; + init = pll->clkr.hw.init; + + if (!pll->config || !pll->regs) { + pr_err("%s: missing pll config or regs\n", init->name); + return -EINVAL; + } + + qcom_clk_alpha_pll_configure(pll, regmap); + } + + return 0; +} + +static void qcom_cc_clk_regs_configure(struct device *dev, const struct qcom_cc_driver_data *data, + struct regmap *regmap) +{ + int i; + + for (i = 0; i < data->num_clk_cbcrs; i++) + qcom_branch_set_clk_en(regmap, data->clk_cbcrs[i]); + + if (data->clk_regs_configure) + data->clk_regs_configure(dev, regmap); +} + int qcom_cc_really_probe(struct device *dev, const struct qcom_cc_desc *desc, struct regmap *regmap) { @@ -299,6 +337,28 @@ int qcom_cc_really_probe(struct device *dev, if (!cc) return -ENOMEM; + ret = devm_pm_domain_attach_list(dev, NULL, &cc->pd_list); + if (ret < 0 && ret != -EEXIST) + return ret; + + if (desc->use_rpm) { + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + } + + if (desc->driver_data) { + ret = qcom_cc_clk_pll_configure(desc->driver_data, regmap); + if (ret) + goto put_rpm; + + qcom_cc_clk_regs_configure(dev, desc->driver_data, regmap); + } + reset = &cc->reset; reset->rcdev.of_node = dev->of_node; reset->rcdev.ops = &qcom_reset_ops; @@ -309,22 +369,35 @@ int qcom_cc_really_probe(struct device *dev, ret = devm_reset_controller_register(dev, &reset->rcdev); if (ret) - return ret; + goto put_rpm; if (desc->gdscs && desc->num_gdscs) { scd = devm_kzalloc(dev, sizeof(*scd), GFP_KERNEL); - if (!scd) - return -ENOMEM; + if (!scd) { + ret = -ENOMEM; + goto put_rpm; + } scd->dev = dev; scd->scs = desc->gdscs; scd->num = desc->num_gdscs; + scd->pd_list = cc->pd_list; ret = gdsc_register(scd, &reset->rcdev, regmap); if (ret) - return ret; + goto put_rpm; ret = devm_add_action_or_reset(dev, qcom_cc_gdsc_unregister, scd); if (ret) - return ret; + goto put_rpm; + } + + if (desc->driver_data && + desc->driver_data->dfs_rcgs && + desc->driver_data->num_dfs_rcgs) { + ret = qcom_cc_register_rcg_dfs(regmap, + desc->driver_data->dfs_rcgs, + desc->driver_data->num_dfs_rcgs); + if (ret) + goto put_rpm; } cc->rclks = rclks; @@ -335,7 +408,7 @@ int qcom_cc_really_probe(struct device *dev, for (i = 0; i < num_clk_hws; i++) { ret = devm_clk_hw_register(dev, clk_hws[i]); if (ret) - return ret; + goto put_rpm; } for (i = 0; i < num_clks; i++) { @@ -344,14 +417,20 @@ int qcom_cc_really_probe(struct device *dev, ret = devm_clk_register_regmap(dev, rclks[i]); if (ret) - return ret; + goto put_rpm; } ret = devm_of_clk_add_hw_provider(dev, qcom_cc_clk_hw_get, cc); if (ret) - return ret; + goto put_rpm; + + ret = qcom_cc_icc_register(dev, desc); + +put_rpm: + if (desc->use_rpm) + pm_runtime_put(dev); - return qcom_cc_icc_register(dev, desc); + return ret; } EXPORT_SYMBOL_GPL(qcom_cc_really_probe); |
