blob: c0cc00f86c7b1f8505fb48e0e3a0ddeb9e180e7e [file] [log] [blame]
Amit Nischal86a69552017-06-23 17:10:16 +05301/*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/cpu.h>
15#include <linux/clk.h>
16#include <linux/clk-provider.h>
17#include <linux/module.h>
18#include <linux/pm_opp.h>
19#include <linux/platform_device.h>
20#include <linux/regmap.h>
21#include <dt-bindings/clock/qcom,cpu-a7.h>
22
23#include "clk-alpha-pll.h"
24#include "clk-debug.h"
25#include "clk-rcg.h"
26#include "clk-regmap-mux-div.h"
27#include "common.h"
28#include "vdd-level-sdm845.h"
29
30#define SYS_APC0_AUX_CLK_SRC 1
31
32#define PLL_MODE_REG 0x0
33#define PLL_OPMODE_RUN 0x1
34#define PLL_OPMODE_REG 0x38
35#define PLL_MODE_OUTCTRL BIT(0)
36
37#define to_clk_regmap_mux_div(_hw) \
38 container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr)
39
40static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner);
41static DEFINE_VDD_REGS_INIT(vdd_cpu, 1);
42
43enum apcs_clk_parent_index {
44 XO_AO_INDEX,
45 SYS_APC0_AUX_CLK_INDEX,
46 APCS_CPU_PLL_INDEX,
47};
48
49enum {
50 P_SYS_APC0_AUX_CLK,
51 P_APCS_CPU_PLL,
52 P_BI_TCXO_AO,
53};
54
55static const struct parent_map apcs_clk_parent_map[] = {
56 [XO_AO_INDEX] = { P_BI_TCXO_AO, 0 },
57 [SYS_APC0_AUX_CLK_INDEX] = { P_SYS_APC0_AUX_CLK, 1 },
58 [APCS_CPU_PLL_INDEX] = { P_APCS_CPU_PLL, 5 },
59};
60
61static const char *const apcs_clk_parent_name[] = {
62 [XO_AO_INDEX] = "bi_tcxo_ao",
63 [SYS_APC0_AUX_CLK_INDEX] = "sys_apc0_aux_clk",
64 [APCS_CPU_PLL_INDEX] = "apcs_cpu_pll",
65};
66
67static int a7cc_clk_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
68 unsigned long prate, u8 index)
69{
70 struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw);
71
72 return __mux_div_set_src_div(cpuclk, cpuclk->parent_map[index].cfg,
73 cpuclk->div);
74}
75
76static int a7cc_clk_set_parent(struct clk_hw *hw, u8 index)
77{
78 /*
79 * Since a7cc_clk_set_rate_and_parent() is defined and set_parent()
80 * will never gets called from clk_change_rate() so return 0.
81 */
82 return 0;
83}
84
85static int a7cc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
86 unsigned long prate)
87{
88 struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw);
89
90 /*
91 * Parent is same as the last rate.
92 * Here just configure new div.
93 */
94 return __mux_div_set_src_div(cpuclk, cpuclk->src, cpuclk->div);
95}
96
97static int a7cc_clk_determine_rate(struct clk_hw *hw,
98 struct clk_rate_request *req)
99{
100 int ret;
101 u32 div = 1;
102 struct clk_hw *xo, *apc0_auxclk_hw, *apcs_cpu_pll_hw;
103 unsigned long apc0_auxclk_rate, rate = req->rate;
104 struct clk_rate_request parent_req = { };
105 struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw);
106 unsigned long mask = BIT(cpuclk->hid_width) - 1;
107
108 xo = clk_hw_get_parent_by_index(hw, XO_AO_INDEX);
109 if (rate == clk_hw_get_rate(xo)) {
110 req->best_parent_hw = xo;
111 req->best_parent_rate = rate;
112 cpuclk->div = div;
113 cpuclk->src = cpuclk->parent_map[XO_AO_INDEX].cfg;
114 return 0;
115 }
116
117 apc0_auxclk_hw = clk_hw_get_parent_by_index(hw, SYS_APC0_AUX_CLK_INDEX);
118 apcs_cpu_pll_hw = clk_hw_get_parent_by_index(hw, APCS_CPU_PLL_INDEX);
119
120 apc0_auxclk_rate = clk_hw_get_rate(apc0_auxclk_hw);
121 if (rate <= apc0_auxclk_rate) {
122 req->best_parent_hw = apc0_auxclk_hw;
123 req->best_parent_rate = apc0_auxclk_rate;
124
125 div = DIV_ROUND_UP((2 * req->best_parent_rate), rate) - 1;
126 div = min_t(unsigned long, div, mask);
127
128 req->rate = clk_rcg2_calc_rate(req->best_parent_rate, 0,
129 0, 0, div);
130 cpuclk->src = cpuclk->parent_map[SYS_APC0_AUX_CLK_INDEX].cfg;
131 } else {
132 parent_req.rate = rate;
133 parent_req.best_parent_hw = apcs_cpu_pll_hw;
134
135 req->best_parent_hw = apcs_cpu_pll_hw;
136 ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
137 if (ret)
138 return ret;
139
140 req->best_parent_rate = parent_req.rate;
141 cpuclk->src = cpuclk->parent_map[APCS_CPU_PLL_INDEX].cfg;
142 }
143 cpuclk->div = div;
144
145 return 0;
146}
147
148static void a7cc_clk_list_registers(struct seq_file *f, struct clk_hw *hw)
149{
150 struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw);
151 int i = 0, size = 0, val;
152
153 static struct clk_register_data data[] = {
154 {"CMD_RCGR", 0x0},
155 {"CFG_RCGR", 0x4},
156 };
157
158 size = ARRAY_SIZE(data);
159 for (i = 0; i < size; i++) {
160 regmap_read(cpuclk->clkr.regmap,
161 cpuclk->reg_offset + data[i].offset, &val);
162 seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
163 }
164}
165
166static unsigned long a7cc_clk_recalc_rate(struct clk_hw *hw,
167 unsigned long prate)
168{
169 struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw);
170 const char *name = clk_hw_get_name(hw);
171 struct clk_hw *parent;
172 int ret = 0;
173 unsigned long parent_rate;
174 u32 i, div, src = 0;
175 u32 num_parents = clk_hw_get_num_parents(hw);
176
177 ret = mux_div_get_src_div(cpuclk, &src, &div);
178 if (ret)
179 return ret;
180
181 for (i = 0; i < num_parents; i++) {
182 if (src == cpuclk->parent_map[i].cfg) {
183 parent = clk_hw_get_parent_by_index(hw, i);
184 parent_rate = clk_hw_get_rate(parent);
185 return clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div);
186 }
187 }
188 pr_err("%s: Can't find parent %d\n", name, src);
189 return ret;
190}
191
192static int a7cc_clk_enable(struct clk_hw *hw)
193{
194 return clk_regmap_mux_div_ops.enable(hw);
195}
196
197static void a7cc_clk_disable(struct clk_hw *hw)
198{
199 clk_regmap_mux_div_ops.disable(hw);
200}
201
202static u8 a7cc_clk_get_parent(struct clk_hw *hw)
203{
204 return clk_regmap_mux_div_ops.get_parent(hw);
205}
206
207/*
208 * We use the notifier function for switching to a temporary safe configuration
209 * (mux and divider), while the APSS pll is reconfigured.
210 */
211static int a7cc_notifier_cb(struct notifier_block *nb, unsigned long event,
212 void *data)
213{
214 int ret = 0;
215 struct clk_regmap_mux_div *cpuclk = container_of(nb,
216 struct clk_regmap_mux_div, clk_nb);
217
218 if (event == PRE_RATE_CHANGE)
219 /* set the mux to safe source(sys_apc0_aux_clk) & div */
220 ret = __mux_div_set_src_div(cpuclk, SYS_APC0_AUX_CLK_SRC, 1);
221
222 if (event == ABORT_RATE_CHANGE)
223 pr_err("Error in configuring PLL - stay at safe src only\n");
224
225 return notifier_from_errno(ret);
226}
227
228static const struct clk_ops a7cc_clk_ops = {
229 .enable = a7cc_clk_enable,
230 .disable = a7cc_clk_disable,
231 .get_parent = a7cc_clk_get_parent,
232 .set_rate = a7cc_clk_set_rate,
233 .set_parent = a7cc_clk_set_parent,
234 .set_rate_and_parent = a7cc_clk_set_rate_and_parent,
235 .determine_rate = a7cc_clk_determine_rate,
236 .recalc_rate = a7cc_clk_recalc_rate,
237 .debug_init = clk_debug_measure_add,
238 .list_registers = a7cc_clk_list_registers,
239};
240
241/*
242 * As per HW, sys_apc0_aux_clk runs at 300MHz and configured by BOOT
243 * So adding it as dummy clock.
244 */
245
246static struct clk_dummy sys_apc0_aux_clk = {
247 .rrate = 300000000,
248 .hw.init = &(struct clk_init_data){
249 .name = "sys_apc0_aux_clk",
250 .ops = &clk_dummy_ops,
251 },
252};
253
254/* Initial configuration for 1497.6MHz(Turbo) */
255static const struct pll_config apcs_cpu_pll_config = {
256 .l = 0x4E,
257};
258
259static struct pll_vco trion_vco[] = {
260 { 249600000, 2000000000, 0 },
261};
262
263static struct clk_alpha_pll apcs_cpu_pll = {
264 .type = TRION_PLL,
265 .vco_table = trion_vco,
266 .num_vco = ARRAY_SIZE(trion_vco),
267 .clkr.hw.init = &(struct clk_init_data){
268 .name = "apcs_cpu_pll",
269 .parent_names = (const char *[]){ "bi_tcxo_ao" },
270 .num_parents = 1,
271 .ops = &clk_trion_pll_ops,
272 VDD_CX_FMAX_MAP4(LOWER, 345600000,
273 LOW, 576000000,
274 NOMINAL, 1094400000,
275 HIGH, 1497600000),
276 },
277};
278
279static struct clk_regmap_mux_div apcs_clk = {
280 .hid_width = 5,
281 .hid_shift = 0,
282 .src_width = 3,
283 .src_shift = 8,
284 .safe_src = 1,
285 .safe_div = 1,
286 .parent_map = apcs_clk_parent_map,
287 .clk_nb.notifier_call = a7cc_notifier_cb,
288 .clkr.hw.init = &(struct clk_init_data) {
289 .name = "apcs_clk",
290 .parent_names = apcs_clk_parent_name,
291 .num_parents = 3,
292 .vdd_class = &vdd_cpu,
293 .flags = CLK_SET_RATE_PARENT,
294 .ops = &a7cc_clk_ops,
295 },
296};
297
298static const struct of_device_id match_table[] = {
299 { .compatible = "qcom,cpu-sdxpoorwills" },
300 {}
301};
302
303static const struct regmap_config cpu_regmap_config = {
304 .reg_bits = 32,
305 .reg_stride = 4,
306 .val_bits = 32,
307 .max_register = 0x7F10,
308 .fast_io = true,
309};
310
311static struct clk_hw *cpu_clks_hws[] = {
312 [SYS_APC0_AUX_CLK] = &sys_apc0_aux_clk.hw,
313 [APCS_CPU_PLL] = &apcs_cpu_pll.clkr.hw,
314 [APCS_CLK] = &apcs_clk.clkr.hw,
315};
316
317static void a7cc_clk_get_speed_bin(struct platform_device *pdev, int *bin,
318 int *version)
319{
320 struct resource *res;
321 void __iomem *base;
322 u32 pte_efuse, valid;
323
324 *bin = 0;
325 *version = 0;
326
327 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
328 if (!res) {
329 dev_info(&pdev->dev,
330 "No speed/PVS binning available. Defaulting to 0!\n");
331 return;
332 }
333
334 base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
335 if (!base) {
336 dev_info(&pdev->dev,
337 "Unable to read efuse data. Defaulting to 0!\n");
338 return;
339 }
340
341 pte_efuse = readl_relaxed(base);
342 devm_iounmap(&pdev->dev, base);
343
344 *bin = pte_efuse & 0x7;
345 valid = (pte_efuse >> 3) & 0x1;
346 *version = (pte_efuse >> 4) & 0x3;
347
348 if (!valid) {
349 dev_info(&pdev->dev, "Speed bin not set. Defaulting to 0!\n");
350 *bin = 0;
351 } else {
352 dev_info(&pdev->dev, "Speed bin: %d\n", *bin);
353 }
354
355 dev_info(&pdev->dev, "PVS version: %d\n", *version);
356}
357
358static int a7cc_clk_get_fmax_vdd_class(struct platform_device *pdev,
359 struct clk_init_data *clk_intd, char *prop_name)
360{
361 struct device_node *of = pdev->dev.of_node;
362 int prop_len, i, j;
363 struct clk_vdd_class *vdd = clk_intd->vdd_class;
364 int num = vdd->num_regulators + 1;
365 u32 *array;
366
367 if (!of_find_property(of, prop_name, &prop_len)) {
368 dev_err(&pdev->dev, "missing %s\n", prop_name);
369 return -EINVAL;
370 }
371
372 prop_len /= sizeof(u32);
373 if (prop_len % num) {
374 dev_err(&pdev->dev, "bad length %d\n", prop_len);
375 return -EINVAL;
376 }
377
378 prop_len /= num;
379 vdd->level_votes = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
380 GFP_KERNEL);
381 if (!vdd->level_votes)
382 return -ENOMEM;
383
384 vdd->vdd_uv = devm_kzalloc(&pdev->dev,
385 prop_len * sizeof(int) * (num - 1), GFP_KERNEL);
386 if (!vdd->vdd_uv)
387 return -ENOMEM;
388
389 clk_intd->rate_max = devm_kzalloc(&pdev->dev,
390 prop_len * sizeof(unsigned long), GFP_KERNEL);
391 if (!clk_intd->rate_max)
392 return -ENOMEM;
393
394 array = devm_kzalloc(&pdev->dev,
395 prop_len * sizeof(u32) * num, GFP_KERNEL);
396 if (!array)
397 return -ENOMEM;
398
399 of_property_read_u32_array(of, prop_name, array, prop_len * num);
400 for (i = 0; i < prop_len; i++) {
401 clk_intd->rate_max[i] = array[num * i];
402 for (j = 1; j < num; j++) {
403 vdd->vdd_uv[(num - 1) * i + (j - 1)] =
404 array[num * i + j];
405 }
406 }
407
408 devm_kfree(&pdev->dev, array);
409 vdd->num_levels = prop_len;
410 vdd->cur_level = prop_len;
411 clk_intd->num_rate_max = prop_len;
412
413 return 0;
414}
415
416/*
417 * Find the voltage level required for a given clock rate.
418 */
419static int find_vdd_level(struct clk_init_data *clk_intd, unsigned long rate)
420{
421 int level;
422
423 for (level = 0; level < clk_intd->num_rate_max; level++)
424 if (rate <= clk_intd->rate_max[level])
425 break;
426
427 if (level == clk_intd->num_rate_max) {
428 pr_err("Rate %lu for %s is greater than highest Fmax\n", rate,
429 clk_intd->name);
430 return -EINVAL;
431 }
432
433 return level;
434}
435
436static int
437a7cc_clk_add_opp(struct clk_hw *hw, struct device *dev, unsigned long max_rate)
438{
439 unsigned long rate = 0;
440 int level, uv, j = 1;
441 long ret;
442 struct clk_init_data *clk_intd = (struct clk_init_data *)hw->init;
443 struct clk_vdd_class *vdd = clk_intd->vdd_class;
444
445 if (IS_ERR_OR_NULL(dev)) {
446 pr_err("%s: Invalid parameters\n", __func__);
447 return -EINVAL;
448 }
449
450 while (1) {
451 rate = clk_intd->rate_max[j++];
452 level = find_vdd_level(clk_intd, rate);
453 if (level <= 0) {
454 pr_warn("clock-cpu: no corner for %lu.\n", rate);
455 return -EINVAL;
456 }
457
458 uv = vdd->vdd_uv[level];
459 if (uv < 0) {
460 pr_warn("clock-cpu: no uv for %lu.\n", rate);
461 return -EINVAL;
462 }
463
464 ret = dev_pm_opp_add(dev, rate, uv);
465 if (ret) {
466 pr_warn("clock-cpu: failed to add OPP for %lu\n", rate);
467 return rate;
468 }
469
470 if (rate >= max_rate)
471 break;
472 }
473
474 return 0;
475}
476
477static void a7cc_clk_print_opp_table(int a7_cpu)
478{
479 struct dev_pm_opp *oppfmax, *oppfmin;
480 unsigned long apc_fmax, apc_fmin;
481 u32 max_a7ss_index = apcs_clk.clkr.hw.init->num_rate_max;
482
483 apc_fmax = apcs_clk.clkr.hw.init->rate_max[max_a7ss_index - 1];
484 apc_fmin = apcs_clk.clkr.hw.init->rate_max[1];
485
486 rcu_read_lock();
487
488 oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a7_cpu),
489 apc_fmax, true);
490 oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a7_cpu),
491 apc_fmin, true);
492 pr_info("Clock_cpu: OPP voltage for %lu: %ld\n", apc_fmin,
493 dev_pm_opp_get_voltage(oppfmin));
494 pr_info("Clock_cpu: OPP voltage for %lu: %ld\n", apc_fmax,
495 dev_pm_opp_get_voltage(oppfmax));
496
497 rcu_read_unlock();
498}
499
500static void a7cc_clk_populate_opp_table(struct platform_device *pdev)
501{
502 unsigned long apc_fmax;
503 int cpu, a7_cpu = 0;
504 u32 max_a7ss_index = apcs_clk.clkr.hw.init->num_rate_max;
505
506 apc_fmax = apcs_clk.clkr.hw.init->rate_max[max_a7ss_index - 1];
507
508 for_each_possible_cpu(cpu) {
509 a7_cpu = cpu;
510 WARN(a7cc_clk_add_opp(&apcs_clk.clkr.hw, get_cpu_device(cpu),
511 apc_fmax),
512 "Failed to add OPP levels for apcs_clk\n");
513 }
514 /* One time print during bootup */
515 dev_info(&pdev->dev, "OPP tables populated (cpu %d)\n", a7_cpu);
516
517 a7cc_clk_print_opp_table(a7_cpu);
518}
519
520static int a7cc_driver_probe(struct platform_device *pdev)
521{
522 struct clk *clk;
523 void __iomem *base;
524 u32 opmode_regval, mode_regval;
525 struct resource *res;
526 struct clk_onecell_data *data;
527 struct device *dev = &pdev->dev;
528 struct device_node *of = pdev->dev.of_node;
529 int i, ret, speed_bin, version, cpu;
530 int num_clks = ARRAY_SIZE(cpu_clks_hws);
531 u32 a7cc_clk_init_rate = 0;
532 char prop_name[] = "qcom,speedX-bin-vX";
533 struct clk *ext_xo_clk;
534
535 /* Require the RPMH-XO clock to be registered before */
536 ext_xo_clk = devm_clk_get(dev, "xo_ao");
537 if (IS_ERR(ext_xo_clk)) {
538 if (PTR_ERR(ext_xo_clk) != -EPROBE_DEFER)
539 dev_err(dev, "Unable to get xo clock\n");
540 return PTR_ERR(ext_xo_clk);
541 }
542
543 /* Get speed bin information */
544 a7cc_clk_get_speed_bin(pdev, &speed_bin, &version);
545
546 /* Rail Regulator for apcs_pll */
547 vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig_ao");
548 if (IS_ERR(vdd_cx.regulator[0])) {
549 if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER))
550 dev_err(&pdev->dev,
551 "Unable to get vdd_dig_ao regulator\n");
552 return PTR_ERR(vdd_cx.regulator[0]);
553 }
554
555 /* Rail Regulator for APSS a7ss mux */
556 vdd_cpu.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd");
557 if (IS_ERR(vdd_cpu.regulator[0])) {
558 if (!(PTR_ERR(vdd_cpu.regulator[0]) == -EPROBE_DEFER))
559 dev_err(&pdev->dev,
560 "Unable to get cpu-vdd regulator\n");
561 return PTR_ERR(vdd_cpu.regulator[0]);
562 }
563
564 snprintf(prop_name, ARRAY_SIZE(prop_name),
565 "qcom,speed%d-bin-v%d", speed_bin, version);
566
567 ret = a7cc_clk_get_fmax_vdd_class(pdev,
568 (struct clk_init_data *)apcs_clk.clkr.hw.init, prop_name);
569 if (ret) {
570 dev_err(&pdev->dev,
571 "Can't get speed bin for apcs_clk. Falling back to zero\n");
572 ret = a7cc_clk_get_fmax_vdd_class(pdev,
573 (struct clk_init_data *)apcs_clk.clkr.hw.init,
574 "qcom,speed0-bin-v0");
575 if (ret) {
576 dev_err(&pdev->dev,
577 "Unable to get speed bin for apcs_clk freq-corner mapping info\n");
578 return ret;
579 }
580 }
581
582 ret = of_property_read_u32(of, "qcom,a7cc-init-rate",
583 &a7cc_clk_init_rate);
584 if (ret) {
585 dev_err(&pdev->dev,
586 "unable to find qcom,a7cc_clk_init_rate property,ret=%d\n",
587 ret);
588 return -EINVAL;
589 }
590
591 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_pll");
592 base = devm_ioremap_resource(dev, res);
593 if (IS_ERR(base)) {
594 dev_err(&pdev->dev, "Failed to map apcs_cpu_pll register base\n");
595 return PTR_ERR(base);
596 }
597
598 apcs_cpu_pll.clkr.regmap = devm_regmap_init_mmio(dev, base,
599 &cpu_regmap_config);
600 if (IS_ERR(apcs_cpu_pll.clkr.regmap)) {
601 dev_err(&pdev->dev, "Couldn't get regmap for apcs_cpu_pll\n");
602 return PTR_ERR(apcs_cpu_pll.clkr.regmap);
603 }
604
605 ret = of_property_read_u32(of, "qcom,rcg-reg-offset",
606 &apcs_clk.reg_offset);
607 if (ret) {
608 dev_err(&pdev->dev,
609 "unable to find qcom,rcg-reg-offset property,ret=%d\n",
610 ret);
611 return -EINVAL;
612 }
613
614 apcs_clk.clkr.regmap = apcs_cpu_pll.clkr.regmap;
615
616 /* Read PLLs OPMODE and mode register */
617 ret = regmap_read(apcs_cpu_pll.clkr.regmap, PLL_OPMODE_REG,
618 &opmode_regval);
619 if (ret)
620 return ret;
621
622 ret = regmap_read(apcs_cpu_pll.clkr.regmap, PLL_MODE_REG,
623 &mode_regval);
624 if (ret)
625 return ret;
626
627 /* Configure APSS PLL only if it is not enabled and running */
628 if (!(opmode_regval & PLL_OPMODE_RUN) &&
629 !(mode_regval & PLL_MODE_OUTCTRL))
630 clk_trion_pll_configure(&apcs_cpu_pll,
631 apcs_cpu_pll.clkr.regmap, &apcs_cpu_pll_config);
632
633 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
634 if (!data)
635 return -ENOMEM;
636
637 data->clk_num = num_clks;
638
639 data->clks = devm_kzalloc(dev, num_clks * sizeof(struct clk *),
640 GFP_KERNEL);
641 if (!data->clks)
642 return -ENOMEM;
643
644 /* Register clocks with clock framework */
645 for (i = 0; i < num_clks; i++) {
646 clk = devm_clk_register(dev, cpu_clks_hws[i]);
647 if (IS_ERR(clk))
648 return PTR_ERR(clk);
649 data->clks[i] = clk;
650 }
651
652 ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
653 if (ret) {
654 dev_err(&pdev->dev, "CPU clock driver registeration failed\n");
655 return ret;
656 }
657
658 ret = clk_notifier_register(apcs_cpu_pll.clkr.hw.clk, &apcs_clk.clk_nb);
659 if (ret) {
660 dev_err(dev, "failed to register clock notifier: %d\n", ret);
661 return ret;
662 }
663
664 /* Put proxy vote for APSS PLL */
665 clk_prepare_enable(apcs_cpu_pll.clkr.hw.clk);
666
667 /* Set to TURBO boot frequency */
668 ret = clk_set_rate(apcs_clk.clkr.hw.clk, a7cc_clk_init_rate);
669 if (ret)
670 dev_err(&pdev->dev, "Unable to set init rate on apcs_clk\n");
671
672 /*
673 * We don't want the CPU clocks to be turned off at late init
674 * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
675 * refcount of these clocks. Any cpufreq/hotplug manager can assume
676 * that the clocks have already been prepared and enabled by the time
677 * they take over.
678 */
679
680 get_online_cpus();
681 for_each_online_cpu(cpu)
682 WARN(clk_prepare_enable(apcs_clk.clkr.hw.clk),
683 "Unable to turn on CPU clock\n");
684 put_online_cpus();
685
686 /* Remove proxy vote for APSS PLL */
687 clk_disable_unprepare(apcs_cpu_pll.clkr.hw.clk);
688
689 a7cc_clk_populate_opp_table(pdev);
690
691 dev_info(dev, "CPU clock Driver probed successfully\n");
692
693 return ret;
694}
695
696static struct platform_driver a7_clk_driver = {
697 .probe = a7cc_driver_probe,
698 .driver = {
699 .name = "qcom-cpu-sdxpoorwills",
700 .of_match_table = match_table,
701 },
702};
703
704static int __init a7_clk_init(void)
705{
706 return platform_driver_register(&a7_clk_driver);
707}
708subsys_initcall(a7_clk_init);
709
710static void __exit a7_clk_exit(void)
711{
712 platform_driver_unregister(&a7_clk_driver);
713}
714module_exit(a7_clk_exit);
715
716MODULE_ALIAS("platform:cpu");
717MODULE_DESCRIPTION("A7 CPU clock Driver");
718MODULE_LICENSE("GPL v2");