diff options
-rw-r--r-- | drivers/clk/qcom/krait-cc.c | 202 |
1 files changed, 112 insertions, 90 deletions
diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c index f95489d174a8..2f9287c263ec 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c @@ -15,6 +15,16 @@ #include "clk-krait.h" +enum { + cpu0_mux = 0, + cpu1_mux, + cpu2_mux, + cpu3_mux, + l2_mux, + + clks_max, +}; + static unsigned int sec_mux_map[] = { 2, 0, @@ -69,21 +79,23 @@ static int krait_notifier_register(struct device *dev, struct clk *clk, return ret; } -static int +static struct clk_hw * krait_add_div(struct device *dev, int id, const char *s, unsigned int offset) { struct krait_div2_clk *div; + static struct clk_parent_data p_data[1]; struct clk_init_data init = { - .num_parents = 1, + .num_parents = ARRAY_SIZE(p_data), .ops = &krait_div2_clk_ops, .flags = CLK_SET_RATE_PARENT, }; - const char *p_names[1]; + struct clk_hw *clk; + char *parent_name; int cpu, ret; div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); if (!div) - return -ENOMEM; + return ERR_PTR(-ENOMEM); div->width = 2; div->shift = 6; @@ -93,18 +105,25 @@ krait_add_div(struct device *dev, int id, const char *s, unsigned int offset) init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s); if (!init.name) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - init.parent_names = p_names; - p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s); - if (!p_names[0]) { - kfree(init.name); - return -ENOMEM; + init.parent_data = p_data; + parent_name = kasprintf(GFP_KERNEL, "hfpll%s", s); + if (!parent_name) { + clk = ERR_PTR(-ENOMEM); + goto err_parent_name; } + p_data[0].fw_name = parent_name; + p_data[0].name = parent_name; + ret = devm_clk_hw_register(dev, &div->hw); - if (ret) - goto err; + if (ret) { + clk = ERR_PTR(ret); + goto err_clk; + } + + clk = &div->hw; /* clk-krait ignore any rate change if mux is not flagged as enabled */ if (id < 0) @@ -113,33 +132,36 @@ krait_add_div(struct device *dev, int id, const char *s, unsigned int offset) else clk_prepare_enable(div->hw.clk); -err: - kfree(p_names[0]); +err_clk: + kfree(parent_name); +err_parent_name: kfree(init.name); - return ret; + return clk; } -static int +static struct clk_hw * krait_add_sec_mux(struct device *dev, int id, const char *s, unsigned int offset, bool unique_aux) { int cpu, ret; struct krait_mux_clk *mux; - static const char *sec_mux_list[] = { - "qsb", - "acpu_aux", + static struct clk_parent_data sec_mux_list[2] = { + { .name = "qsb", .fw_name = "qsb" }, + {}, }; struct clk_init_data init = { - .parent_names = sec_mux_list, + .parent_data = sec_mux_list, .num_parents = ARRAY_SIZE(sec_mux_list), .ops = &krait_mux_clk_ops, .flags = CLK_SET_RATE_PARENT, }; + struct clk_hw *clk; + char *parent_name; mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); if (!mux) - return -ENOMEM; + return ERR_PTR(-ENOMEM); mux->offset = offset; mux->lpl = id >= 0; @@ -159,23 +181,33 @@ krait_add_sec_mux(struct device *dev, int id, const char *s, init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); if (!init.name) - return -ENOMEM; + return ERR_PTR(-ENOMEM); if (unique_aux) { - sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s); - if (!sec_mux_list[0]) { - ret = -ENOMEM; + parent_name = kasprintf(GFP_KERNEL, "acpu%s_aux", s); + if (!parent_name) { + clk = ERR_PTR(-ENOMEM); goto err_aux; } + sec_mux_list[1].fw_name = parent_name; + sec_mux_list[1].name = parent_name; + } else { + sec_mux_list[1].name = "apu_aux"; } ret = devm_clk_hw_register(dev, &mux->hw); - if (ret) - goto unique_aux; + if (ret) { + clk = ERR_PTR(ret); + goto err_clk; + } + + clk = &mux->hw; ret = krait_notifier_register(dev, mux->hw.clk, mux); - if (ret) - goto unique_aux; + if (ret) { + clk = ERR_PTR(ret); + goto err_clk; + } /* clk-krait ignore any rate change if mux is not flagged as enabled */ if (id < 0) @@ -184,28 +216,29 @@ krait_add_sec_mux(struct device *dev, int id, const char *s, else clk_prepare_enable(mux->hw.clk); -unique_aux: +err_clk: if (unique_aux) - kfree(sec_mux_list[0]); + kfree(parent_name); err_aux: kfree(init.name); - return ret; + return clk; } -static struct clk * -krait_add_pri_mux(struct device *dev, int id, const char *s, - unsigned int offset) +static struct clk_hw * +krait_add_pri_mux(struct device *dev, struct clk_hw *hfpll_div, struct clk_hw *sec_mux, + int id, const char *s, unsigned int offset) { int ret; struct krait_mux_clk *mux; - const char *p_names[3]; + static struct clk_parent_data p_data[3]; struct clk_init_data init = { - .parent_names = p_names, - .num_parents = ARRAY_SIZE(p_names), + .parent_data = p_data, + .num_parents = ARRAY_SIZE(p_data), .ops = &krait_mux_clk_ops, .flags = CLK_SET_RATE_PARENT, }; - struct clk *clk; + struct clk_hw *clk; + char *hfpll_name; mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); if (!mux) @@ -223,55 +256,44 @@ krait_add_pri_mux(struct device *dev, int id, const char *s, if (!init.name) return ERR_PTR(-ENOMEM); - p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s); - if (!p_names[0]) { + hfpll_name = kasprintf(GFP_KERNEL, "hfpll%s", s); + if (!hfpll_name) { clk = ERR_PTR(-ENOMEM); - goto err_p0; + goto err_hfpll; } - p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s); - if (!p_names[1]) { - clk = ERR_PTR(-ENOMEM); - goto err_p1; - } + p_data[0].fw_name = hfpll_name; + p_data[0].name = hfpll_name; - p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); - if (!p_names[2]) { - clk = ERR_PTR(-ENOMEM); - goto err_p2; - } + p_data[1].hw = hfpll_div; + p_data[2].hw = sec_mux; ret = devm_clk_hw_register(dev, &mux->hw); if (ret) { clk = ERR_PTR(ret); - goto err_p3; + goto err_clk; } - clk = mux->hw.clk; + clk = &mux->hw; - ret = krait_notifier_register(dev, clk, mux); + ret = krait_notifier_register(dev, mux->hw.clk, mux); if (ret) clk = ERR_PTR(ret); -err_p3: - kfree(p_names[2]); -err_p2: - kfree(p_names[1]); -err_p1: - kfree(p_names[0]); -err_p0: +err_clk: + kfree(hfpll_name); +err_hfpll: kfree(init.name); return clk; } /* id < 0 for L2, otherwise id == physical CPU number */ -static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux) +static struct clk_hw *krait_add_clks(struct device *dev, int id, bool unique_aux) { - int ret; + struct clk_hw *hfpll_div, *sec_mux, *pri_mux; unsigned int offset; void *p = NULL; const char *s; - struct clk *clk; if (id >= 0) { offset = 0x4501 + (0x1000 * id); @@ -283,22 +305,23 @@ static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux) s = "_l2"; } - ret = krait_add_div(dev, id, s, offset); - if (ret) { - clk = ERR_PTR(ret); + hfpll_div = krait_add_div(dev, id, s, offset); + if (IS_ERR(hfpll_div)) { + pri_mux = hfpll_div; goto err; } - ret = krait_add_sec_mux(dev, id, s, offset, unique_aux); - if (ret) { - clk = ERR_PTR(ret); + sec_mux = krait_add_sec_mux(dev, id, s, offset, unique_aux); + if (IS_ERR(sec_mux)) { + pri_mux = sec_mux; goto err; } - clk = krait_add_pri_mux(dev, id, s, offset); + pri_mux = krait_add_pri_mux(dev, hfpll_div, sec_mux, id, s, offset); + err: kfree(p); - return clk; + return pri_mux; } static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data) @@ -306,7 +329,7 @@ static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data) unsigned int idx = clkspec->args[0]; struct clk **clks = data; - if (idx >= 5) { + if (idx >= clks_max) { pr_err("%s: invalid clock index %d\n", __func__, idx); return ERR_PTR(-EINVAL); } @@ -327,9 +350,8 @@ static int krait_cc_probe(struct platform_device *pdev) const struct of_device_id *id; unsigned long cur_rate, aux_rate; int cpu; - struct clk *clk; - struct clk **clks; - struct clk *l2_pri_mux_clk; + struct clk_hw *mux, *l2_pri_mux; + struct clk *clk, **clks; id = of_match_device(krait_cc_match_table, dev); if (!id) @@ -348,21 +370,21 @@ static int krait_cc_probe(struct platform_device *pdev) } /* Krait configurations have at most 4 CPUs and one L2 */ - clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL); + clks = devm_kcalloc(dev, clks_max, sizeof(*clks), GFP_KERNEL); if (!clks) return -ENOMEM; for_each_possible_cpu(cpu) { - clk = krait_add_clks(dev, cpu, id->data); + mux = krait_add_clks(dev, cpu, id->data); if (IS_ERR(clk)) return PTR_ERR(clk); - clks[cpu] = clk; + clks[cpu] = mux->clk; } - l2_pri_mux_clk = krait_add_clks(dev, -1, id->data); - if (IS_ERR(l2_pri_mux_clk)) - return PTR_ERR(l2_pri_mux_clk); - clks[4] = l2_pri_mux_clk; + l2_pri_mux = krait_add_clks(dev, -1, id->data); + if (IS_ERR(l2_pri_mux)) + return PTR_ERR(l2_pri_mux); + clks[l2_mux] = l2_pri_mux->clk; /* * We don't want the CPU or L2 clocks to be turned off at late init @@ -372,7 +394,7 @@ static int krait_cc_probe(struct platform_device *pdev) * they take over. */ for_each_online_cpu(cpu) { - clk_prepare_enable(l2_pri_mux_clk); + clk_prepare_enable(clks[l2_mux]); WARN(clk_prepare_enable(clks[cpu]), "Unable to turn on CPU%d clock", cpu); } @@ -388,16 +410,16 @@ static int krait_cc_probe(struct platform_device *pdev) * two different rates to force a HFPLL reinit under all * circumstances. */ - cur_rate = clk_get_rate(l2_pri_mux_clk); + cur_rate = clk_get_rate(clks[l2_mux]); aux_rate = 384000000; if (cur_rate < aux_rate) { pr_info("L2 @ Undefined rate. Forcing new rate.\n"); cur_rate = aux_rate; } - clk_set_rate(l2_pri_mux_clk, aux_rate); - clk_set_rate(l2_pri_mux_clk, 2); - clk_set_rate(l2_pri_mux_clk, cur_rate); - pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000); + clk_set_rate(clks[l2_mux], aux_rate); + clk_set_rate(clks[l2_mux], 2); + clk_set_rate(clks[l2_mux], cur_rate); + pr_info("L2 @ %lu KHz\n", clk_get_rate(clks[l2_mux]) / 1000); for_each_possible_cpu(cpu) { clk = clks[cpu]; cur_rate = clk_get_rate(clk); |