diff options
Diffstat (limited to 'drivers/clk/qcom/common.c')
-rw-r--r-- | drivers/clk/qcom/common.c | 91 |
1 files changed, 82 insertions, 9 deletions
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 9e3380fd7181..37c3008e6c1b 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" @@ -284,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) { @@ -304,6 +341,24 @@ int qcom_cc_really_probe(struct device *dev, 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; @@ -314,23 +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; @@ -341,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++) { @@ -350,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); |