1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
4 */
5
6/*
7 * Each of the CPU clusters (Power and Perf) on msm8996 are
8 * clocked via 2 PLLs, a primary and alternate. There are also
9 * 2 Mux'es, a primary and secondary all connected together
10 * as shown below
11 *
12 *                              +-------+
13 *               XO             |       |
14 *           +------------------>0      |
15 *               SYS_APCS_AUX   |       |
16 *           +------------------>3      |
17 *                              |       |
18 *                    PLL/2     | SMUX  +----+
19 *                      +------->1      |    |
20 *                      |       |       |    |
21 *                      |       +-------+    |    +-------+
22 *                      |                    +---->0      |
23 *                      |                         |       |
24 * +---------------+    |             +----------->1      | CPU clk
25 * |Primary PLL    +----+ PLL_EARLY   |           |       +------>
26 * |               +------+-----------+    +------>2 PMUX |
27 * +---------------+      |                |      |       |
28 *                        |   +------+     |   +-->3      |
29 *                        +--^+  ACD +-----+   |  +-------+
30 * +---------------+          +------+         |
31 * |Alt PLL        |                           |
32 * |               +---------------------------+
33 * +---------------+         PLL_EARLY
34 *
35 * The primary PLL is what drives the CPU clk, except for times
36 * when we are reprogramming the PLL itself (for rate changes) when
37 * we temporarily switch to an alternate PLL.
38 *
39 * The primary PLL operates on a single VCO range, between 600MHz
40 * and 3GHz. However the CPUs do support OPPs with frequencies
41 * between 300MHz and 600MHz. In order to support running the CPUs
42 * at those frequencies we end up having to lock the PLL at twice
43 * the rate and drive the CPU clk via the PLL/2 output and SMUX.
44 *
45 * So for frequencies above 600MHz we follow the following path
46 *  Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
47 * and for frequencies between 300MHz and 600MHz we follow
48 *  Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
49 *
50 * ACD stands for Adaptive Clock Distribution and is used to
51 * detect voltage droops.
52 */
53
54#include <linux/bitfield.h>
55#include <linux/clk.h>
56#include <linux/clk-provider.h>
57#include <linux/io.h>
58#include <linux/module.h>
59#include <linux/platform_device.h>
60#include <linux/regmap.h>
61#include <soc/qcom/kryo-l2-accessors.h>
62
63#include <asm/cputype.h>
64
65#include "clk-alpha-pll.h"
66#include "clk-regmap.h"
67#include "clk-regmap-mux.h"
68
69enum _pmux_input {
70	SMUX_INDEX = 0,
71	PLL_INDEX,
72	ACD_INDEX,
73	ALT_INDEX,
74	NUM_OF_PMUX_INPUTS
75};
76
77#define DIV_2_THRESHOLD		600000000
78#define PWRCL_REG_OFFSET 0x0
79#define PERFCL_REG_OFFSET 0x80000
80#define MUX_OFFSET	0x40
81#define CLK_CTL_OFFSET 0x44
82#define CLK_CTL_AUTO_CLK_SEL BIT(8)
83#define ALT_PLL_OFFSET	0x100
84#define SSSCTL_OFFSET 0x160
85#define PSCTL_OFFSET 0x164
86
87#define PMUX_MASK	0x3
88#define MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK GENMASK(5, 4)
89#define MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL \
90	FIELD_PREP(MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK, 0x03)
91
92static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
93	[PLL_OFF_L_VAL] = 0x04,
94	[PLL_OFF_ALPHA_VAL] = 0x08,
95	[PLL_OFF_USER_CTL] = 0x10,
96	[PLL_OFF_CONFIG_CTL] = 0x18,
97	[PLL_OFF_CONFIG_CTL_U] = 0x1c,
98	[PLL_OFF_TEST_CTL] = 0x20,
99	[PLL_OFF_TEST_CTL_U] = 0x24,
100	[PLL_OFF_STATUS] = 0x28,
101};
102
103static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
104	[PLL_OFF_L_VAL] = 0x04,
105	[PLL_OFF_ALPHA_VAL] = 0x08,
106	[PLL_OFF_USER_CTL] = 0x10,
107	[PLL_OFF_CONFIG_CTL] = 0x18,
108	[PLL_OFF_TEST_CTL] = 0x20,
109	[PLL_OFF_STATUS] = 0x28,
110};
111
112/* PLLs */
113
114static const struct alpha_pll_config hfpll_config = {
115	.l = 54,
116	.config_ctl_val = 0x200d4828,
117	.config_ctl_hi_val = 0x006,
118	.test_ctl_val = 0x1c000000,
119	.test_ctl_hi_val = 0x00004000,
120	.pre_div_mask = BIT(12),
121	.post_div_mask = 0x3 << 8,
122	.post_div_val = 0x1 << 8,
123	.main_output_mask = BIT(0),
124	.early_output_mask = BIT(3),
125};
126
127static const struct clk_parent_data pll_parent[] = {
128	{ .fw_name = "xo" },
129};
130
131static struct clk_alpha_pll pwrcl_pll = {
132	.offset = PWRCL_REG_OFFSET,
133	.regs = prim_pll_regs,
134	.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
135	.clkr.hw.init = &(struct clk_init_data){
136		.name = "pwrcl_pll",
137		.parent_data = pll_parent,
138		.num_parents = ARRAY_SIZE(pll_parent),
139		.ops = &clk_alpha_pll_hwfsm_ops,
140	},
141};
142
143static struct clk_alpha_pll perfcl_pll = {
144	.offset = PERFCL_REG_OFFSET,
145	.regs = prim_pll_regs,
146	.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
147	.clkr.hw.init = &(struct clk_init_data){
148		.name = "perfcl_pll",
149		.parent_data = pll_parent,
150		.num_parents = ARRAY_SIZE(pll_parent),
151		.ops = &clk_alpha_pll_hwfsm_ops,
152	},
153};
154
155static struct clk_fixed_factor pwrcl_pll_postdiv = {
156	.mult = 1,
157	.div = 2,
158	.hw.init = &(struct clk_init_data){
159		.name = "pwrcl_pll_postdiv",
160		.parent_data = &(const struct clk_parent_data){
161			.hw = &pwrcl_pll.clkr.hw
162		},
163		.num_parents = 1,
164		.ops = &clk_fixed_factor_ops,
165		.flags = CLK_SET_RATE_PARENT,
166	},
167};
168
169static struct clk_fixed_factor perfcl_pll_postdiv = {
170	.mult = 1,
171	.div = 2,
172	.hw.init = &(struct clk_init_data){
173		.name = "perfcl_pll_postdiv",
174		.parent_data = &(const struct clk_parent_data){
175			.hw = &perfcl_pll.clkr.hw
176		},
177		.num_parents = 1,
178		.ops = &clk_fixed_factor_ops,
179		.flags = CLK_SET_RATE_PARENT,
180	},
181};
182
183static struct clk_fixed_factor perfcl_pll_acd = {
184	.mult = 1,
185	.div = 1,
186	.hw.init = &(struct clk_init_data){
187		.name = "perfcl_pll_acd",
188		.parent_data = &(const struct clk_parent_data){
189			.hw = &perfcl_pll.clkr.hw
190		},
191		.num_parents = 1,
192		.ops = &clk_fixed_factor_ops,
193		.flags = CLK_SET_RATE_PARENT,
194	},
195};
196
197static struct clk_fixed_factor pwrcl_pll_acd = {
198	.mult = 1,
199	.div = 1,
200	.hw.init = &(struct clk_init_data){
201		.name = "pwrcl_pll_acd",
202		.parent_data = &(const struct clk_parent_data){
203			.hw = &pwrcl_pll.clkr.hw
204		},
205		.num_parents = 1,
206		.ops = &clk_fixed_factor_ops,
207		.flags = CLK_SET_RATE_PARENT,
208	},
209};
210
211static const struct pll_vco alt_pll_vco_modes[] = {
212	VCO(3,  250000000,  500000000),
213	VCO(2,  500000000,  750000000),
214	VCO(1,  750000000, 1000000000),
215	VCO(0, 1000000000, 2150400000),
216};
217
218static const struct alpha_pll_config altpll_config = {
219	.l = 16,
220	.vco_val = 0x3 << 20,
221	.vco_mask = 0x3 << 20,
222	.config_ctl_val = 0x4001051b,
223	.post_div_mask = 0x3 << 8,
224	.post_div_val = 0x1 << 8,
225	.main_output_mask = BIT(0),
226	.early_output_mask = BIT(3),
227};
228
229static struct clk_alpha_pll pwrcl_alt_pll = {
230	.offset = PWRCL_REG_OFFSET + ALT_PLL_OFFSET,
231	.regs = alt_pll_regs,
232	.vco_table = alt_pll_vco_modes,
233	.num_vco = ARRAY_SIZE(alt_pll_vco_modes),
234	.flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
235	.clkr.hw.init = &(struct clk_init_data) {
236		.name = "pwrcl_alt_pll",
237		.parent_data = pll_parent,
238		.num_parents = ARRAY_SIZE(pll_parent),
239		.ops = &clk_alpha_pll_hwfsm_ops,
240	},
241};
242
243static struct clk_alpha_pll perfcl_alt_pll = {
244	.offset = PERFCL_REG_OFFSET + ALT_PLL_OFFSET,
245	.regs = alt_pll_regs,
246	.vco_table = alt_pll_vco_modes,
247	.num_vco = ARRAY_SIZE(alt_pll_vco_modes),
248	.flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
249	.clkr.hw.init = &(struct clk_init_data) {
250		.name = "perfcl_alt_pll",
251		.parent_data = pll_parent,
252		.num_parents = ARRAY_SIZE(pll_parent),
253		.ops = &clk_alpha_pll_hwfsm_ops,
254	},
255};
256
257struct clk_cpu_8996_pmux {
258	u32	reg;
259	struct notifier_block nb;
260	struct clk_regmap clkr;
261};
262
263static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
264			       void *data);
265
266#define to_clk_cpu_8996_pmux_nb(_nb) \
267	container_of(_nb, struct clk_cpu_8996_pmux, nb)
268
269static inline struct clk_cpu_8996_pmux *to_clk_cpu_8996_pmux_hw(struct clk_hw *hw)
270{
271	return container_of(to_clk_regmap(hw), struct clk_cpu_8996_pmux, clkr);
272}
273
274static u8 clk_cpu_8996_pmux_get_parent(struct clk_hw *hw)
275{
276	struct clk_regmap *clkr = to_clk_regmap(hw);
277	struct clk_cpu_8996_pmux *cpuclk = to_clk_cpu_8996_pmux_hw(hw);
278	u32 val;
279
280	regmap_read(clkr->regmap, cpuclk->reg, &val);
281
282	return FIELD_GET(PMUX_MASK, val);
283}
284
285static int clk_cpu_8996_pmux_set_parent(struct clk_hw *hw, u8 index)
286{
287	struct clk_regmap *clkr = to_clk_regmap(hw);
288	struct clk_cpu_8996_pmux *cpuclk = to_clk_cpu_8996_pmux_hw(hw);
289	u32 val;
290
291	val = FIELD_PREP(PMUX_MASK, index);
292
293	return regmap_update_bits(clkr->regmap, cpuclk->reg, PMUX_MASK, val);
294}
295
296static int clk_cpu_8996_pmux_determine_rate(struct clk_hw *hw,
297					   struct clk_rate_request *req)
298{
299	struct clk_hw *parent;
300
301	if (req->rate < (DIV_2_THRESHOLD / 2))
302		return -EINVAL;
303
304	if (req->rate < DIV_2_THRESHOLD)
305		parent = clk_hw_get_parent_by_index(hw, SMUX_INDEX);
306	else
307		parent = clk_hw_get_parent_by_index(hw, ACD_INDEX);
308	if (!parent)
309		return -EINVAL;
310
311	req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
312	req->best_parent_hw = parent;
313
314	return 0;
315}
316
317static const struct clk_ops clk_cpu_8996_pmux_ops = {
318	.set_parent = clk_cpu_8996_pmux_set_parent,
319	.get_parent = clk_cpu_8996_pmux_get_parent,
320	.determine_rate = clk_cpu_8996_pmux_determine_rate,
321};
322
323static const struct parent_map smux_parent_map[] = {
324	{ .cfg = 0, }, /* xo */
325	{ .cfg = 1, }, /* pll */
326	{ .cfg = 3, }, /* sys_apcs_aux */
327};
328
329static const struct clk_parent_data pwrcl_smux_parents[] = {
330	{ .fw_name = "xo" },
331	{ .hw = &pwrcl_pll_postdiv.hw },
332	{ .fw_name = "sys_apcs_aux" },
333};
334
335static const struct clk_parent_data perfcl_smux_parents[] = {
336	{ .fw_name = "xo" },
337	{ .hw = &perfcl_pll_postdiv.hw },
338	{ .fw_name = "sys_apcs_aux" },
339};
340
341static struct clk_regmap_mux pwrcl_smux = {
342	.reg = PWRCL_REG_OFFSET + MUX_OFFSET,
343	.shift = 2,
344	.width = 2,
345	.parent_map = smux_parent_map,
346	.clkr.hw.init = &(struct clk_init_data) {
347		.name = "pwrcl_smux",
348		.parent_data = pwrcl_smux_parents,
349		.num_parents = ARRAY_SIZE(pwrcl_smux_parents),
350		.ops = &clk_regmap_mux_closest_ops,
351		.flags = CLK_SET_RATE_PARENT,
352	},
353};
354
355static struct clk_regmap_mux perfcl_smux = {
356	.reg = PERFCL_REG_OFFSET + MUX_OFFSET,
357	.shift = 2,
358	.width = 2,
359	.parent_map = smux_parent_map,
360	.clkr.hw.init = &(struct clk_init_data) {
361		.name = "perfcl_smux",
362		.parent_data = perfcl_smux_parents,
363		.num_parents = ARRAY_SIZE(perfcl_smux_parents),
364		.ops = &clk_regmap_mux_closest_ops,
365		.flags = CLK_SET_RATE_PARENT,
366	},
367};
368
369static const struct clk_hw *pwrcl_pmux_parents[] = {
370	[SMUX_INDEX] = &pwrcl_smux.clkr.hw,
371	[PLL_INDEX] = &pwrcl_pll.clkr.hw,
372	[ACD_INDEX] = &pwrcl_pll_acd.hw,
373	[ALT_INDEX] = &pwrcl_alt_pll.clkr.hw,
374};
375
376static const struct clk_hw *perfcl_pmux_parents[] = {
377	[SMUX_INDEX] = &perfcl_smux.clkr.hw,
378	[PLL_INDEX] = &perfcl_pll.clkr.hw,
379	[ACD_INDEX] = &perfcl_pll_acd.hw,
380	[ALT_INDEX] = &perfcl_alt_pll.clkr.hw,
381};
382
383static struct clk_cpu_8996_pmux pwrcl_pmux = {
384	.reg = PWRCL_REG_OFFSET + MUX_OFFSET,
385	.nb.notifier_call = cpu_clk_notifier_cb,
386	.clkr.hw.init = &(struct clk_init_data) {
387		.name = "pwrcl_pmux",
388		.parent_hws = pwrcl_pmux_parents,
389		.num_parents = ARRAY_SIZE(pwrcl_pmux_parents),
390		.ops = &clk_cpu_8996_pmux_ops,
391		/* CPU clock is critical and should never be gated */
392		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
393	},
394};
395
396static struct clk_cpu_8996_pmux perfcl_pmux = {
397	.reg = PERFCL_REG_OFFSET + MUX_OFFSET,
398	.nb.notifier_call = cpu_clk_notifier_cb,
399	.clkr.hw.init = &(struct clk_init_data) {
400		.name = "perfcl_pmux",
401		.parent_hws = perfcl_pmux_parents,
402		.num_parents = ARRAY_SIZE(perfcl_pmux_parents),
403		.ops = &clk_cpu_8996_pmux_ops,
404		/* CPU clock is critical and should never be gated */
405		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
406	},
407};
408
409static const struct regmap_config cpu_msm8996_regmap_config = {
410	.reg_bits		= 32,
411	.reg_stride		= 4,
412	.val_bits		= 32,
413	.max_register		= 0x80210,
414	.fast_io		= true,
415	.val_format_endian	= REGMAP_ENDIAN_LITTLE,
416};
417
418static struct clk_hw *cpu_msm8996_hw_clks[] = {
419	&pwrcl_pll_postdiv.hw,
420	&perfcl_pll_postdiv.hw,
421	&pwrcl_pll_acd.hw,
422	&perfcl_pll_acd.hw,
423};
424
425static struct clk_regmap *cpu_msm8996_clks[] = {
426	&pwrcl_pll.clkr,
427	&perfcl_pll.clkr,
428	&pwrcl_alt_pll.clkr,
429	&perfcl_alt_pll.clkr,
430	&pwrcl_smux.clkr,
431	&perfcl_smux.clkr,
432	&pwrcl_pmux.clkr,
433	&perfcl_pmux.clkr,
434};
435
436static void qcom_cpu_clk_msm8996_acd_init(struct regmap *regmap);
437
438static int qcom_cpu_clk_msm8996_register_clks(struct device *dev,
439					      struct regmap *regmap)
440{
441	int i, ret;
442
443	/* Select GPLL0 for 300MHz for both clusters */
444	regmap_write(regmap, PERFCL_REG_OFFSET + MUX_OFFSET, 0xc);
445	regmap_write(regmap, PWRCL_REG_OFFSET + MUX_OFFSET, 0xc);
446
447	/* Ensure write goes through before PLLs are reconfigured */
448	udelay(5);
449
450	/* Set the auto clock sel always-on source to GPLL0/2 (300MHz) */
451	regmap_update_bits(regmap, PWRCL_REG_OFFSET + MUX_OFFSET,
452			   MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK,
453			   MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL);
454	regmap_update_bits(regmap, PERFCL_REG_OFFSET + MUX_OFFSET,
455			   MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK,
456			   MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL);
457
458	clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
459	clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
460	clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
461	clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
462
463	/* Wait for PLL(s) to lock */
464	udelay(50);
465
466	/* Enable auto clock selection for both clusters */
467	regmap_update_bits(regmap, PWRCL_REG_OFFSET + CLK_CTL_OFFSET,
468			   CLK_CTL_AUTO_CLK_SEL, CLK_CTL_AUTO_CLK_SEL);
469	regmap_update_bits(regmap, PERFCL_REG_OFFSET + CLK_CTL_OFFSET,
470			   CLK_CTL_AUTO_CLK_SEL, CLK_CTL_AUTO_CLK_SEL);
471
472	/* Ensure write goes through before muxes are switched */
473	udelay(5);
474
475	qcom_cpu_clk_msm8996_acd_init(regmap);
476
477	/* Pulse swallower and soft-start settings */
478	regmap_write(regmap, PWRCL_REG_OFFSET + PSCTL_OFFSET, 0x00030005);
479	regmap_write(regmap, PERFCL_REG_OFFSET + PSCTL_OFFSET, 0x00030005);
480
481	/* Switch clusters to use the ACD leg */
482	regmap_write(regmap, PWRCL_REG_OFFSET + MUX_OFFSET, 0x32);
483	regmap_write(regmap, PERFCL_REG_OFFSET + MUX_OFFSET, 0x32);
484
485	for (i = 0; i < ARRAY_SIZE(cpu_msm8996_hw_clks); i++) {
486		ret = devm_clk_hw_register(dev, cpu_msm8996_hw_clks[i]);
487		if (ret)
488			return ret;
489	}
490
491	for (i = 0; i < ARRAY_SIZE(cpu_msm8996_clks); i++) {
492		ret = devm_clk_register_regmap(dev, cpu_msm8996_clks[i]);
493		if (ret)
494			return ret;
495	}
496
497	/* Enable alt PLLs */
498	clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
499	clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
500
501	devm_clk_notifier_register(dev, pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
502	devm_clk_notifier_register(dev, perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb);
503
504	return ret;
505}
506
507#define CPU_CLUSTER_AFFINITY_MASK 0xf00
508#define PWRCL_AFFINITY_MASK 0x000
509#define PERFCL_AFFINITY_MASK 0x100
510
511#define L2ACDCR_REG 0x580ULL
512#define L2ACDTD_REG 0x581ULL
513#define L2ACDDVMRC_REG 0x584ULL
514#define L2ACDSSCR_REG 0x589ULL
515
516static DEFINE_SPINLOCK(qcom_clk_acd_lock);
517
518static void qcom_cpu_clk_msm8996_acd_init(struct regmap *regmap)
519{
520	u64 hwid;
521	u32 val;
522	unsigned long flags;
523
524	spin_lock_irqsave(&qcom_clk_acd_lock, flags);
525
526	val = kryo_l2_get_indirect_reg(L2ACDTD_REG);
527	if (val == 0x00006a11)
528		goto out;
529
530	kryo_l2_set_indirect_reg(L2ACDTD_REG, 0x00006a11);
531	kryo_l2_set_indirect_reg(L2ACDDVMRC_REG, 0x000e0f0f);
532	kryo_l2_set_indirect_reg(L2ACDSSCR_REG, 0x00000601);
533
534	kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002c5ffd);
535
536	hwid = read_cpuid_mpidr();
537	if ((hwid & CPU_CLUSTER_AFFINITY_MASK) == PWRCL_AFFINITY_MASK)
538		regmap_write(regmap, PWRCL_REG_OFFSET + SSSCTL_OFFSET, 0xf);
539	else
540		regmap_write(regmap, PERFCL_REG_OFFSET + SSSCTL_OFFSET, 0xf);
541
542out:
543	spin_unlock_irqrestore(&qcom_clk_acd_lock, flags);
544}
545
546static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
547			       void *data)
548{
549	struct clk_cpu_8996_pmux *cpuclk = to_clk_cpu_8996_pmux_nb(nb);
550	struct clk_notifier_data *cnd = data;
551
552	switch (event) {
553	case PRE_RATE_CHANGE:
554		qcom_cpu_clk_msm8996_acd_init(cpuclk->clkr.regmap);
555
556		/*
557		 * Avoid overvolting. clk_core_set_rate_nolock() walks from top
558		 * to bottom, so it will change the rate of the PLL before
559		 * chaging the parent of PMUX. This can result in pmux getting
560		 * clocked twice the expected rate.
561		 *
562		 * Manually switch to PLL/2 here.
563		 */
564		if (cnd->new_rate < DIV_2_THRESHOLD &&
565		    cnd->old_rate > DIV_2_THRESHOLD)
566			clk_cpu_8996_pmux_set_parent(&cpuclk->clkr.hw, SMUX_INDEX);
567
568		break;
569	case ABORT_RATE_CHANGE:
570		/* Revert manual change */
571		if (cnd->new_rate < DIV_2_THRESHOLD &&
572		    cnd->old_rate > DIV_2_THRESHOLD)
573			clk_cpu_8996_pmux_set_parent(&cpuclk->clkr.hw, ACD_INDEX);
574		break;
575	default:
576		break;
577	}
578
579	return NOTIFY_OK;
580};
581
582static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
583{
584	static void __iomem *base;
585	struct regmap *regmap;
586	struct clk_hw_onecell_data *data;
587	struct device *dev = &pdev->dev;
588	int ret;
589
590	data = devm_kzalloc(dev, struct_size(data, hws, 2), GFP_KERNEL);
591	if (!data)
592		return -ENOMEM;
593	data->num = 2;
594
595	base = devm_platform_ioremap_resource(pdev, 0);
596	if (IS_ERR(base))
597		return PTR_ERR(base);
598
599	regmap = devm_regmap_init_mmio(dev, base, &cpu_msm8996_regmap_config);
600	if (IS_ERR(regmap))
601		return PTR_ERR(regmap);
602
603	ret = qcom_cpu_clk_msm8996_register_clks(dev, regmap);
604	if (ret)
605		return ret;
606
607	data->hws[0] = &pwrcl_pmux.clkr.hw;
608	data->hws[1] = &perfcl_pmux.clkr.hw;
609
610	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
611}
612
613static const struct of_device_id qcom_cpu_clk_msm8996_match_table[] = {
614	{ .compatible = "qcom,msm8996-apcc" },
615	{}
616};
617MODULE_DEVICE_TABLE(of, qcom_cpu_clk_msm8996_match_table);
618
619static struct platform_driver qcom_cpu_clk_msm8996_driver = {
620	.probe = qcom_cpu_clk_msm8996_driver_probe,
621	.driver = {
622		.name = "qcom-msm8996-apcc",
623		.of_match_table = qcom_cpu_clk_msm8996_match_table,
624	},
625};
626module_platform_driver(qcom_cpu_clk_msm8996_driver);
627
628MODULE_DESCRIPTION("QCOM MSM8996 CPU Clock Driver");
629MODULE_LICENSE("GPL v2");
630