Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
  4 */
  5
  6#include <linux/clk-provider.h>
  7#include <linux/err.h>
  8#include <linux/kernel.h>
  9#include <linux/module.h>
 10#include <linux/of_device.h>
 11#include <linux/pm_clock.h>
 12#include <linux/pm_runtime.h>
 13#include <linux/regmap.h>
 14
 15#include <dt-bindings/clock/qcom,lpass-sc7280.h>
 16#include <dt-bindings/clock/qcom,lpassaudiocc-sc7280.h>
 17
 18#include "clk-alpha-pll.h"
 19#include "clk-branch.h"
 20#include "clk-rcg.h"
 21#include "clk-regmap.h"
 22#include "clk-regmap-divider.h"
 23#include "clk-regmap-mux.h"
 24#include "common.h"
 25#include "gdsc.h"
 26#include "reset.h"
 27
 28enum {
 29	P_BI_TCXO,
 30	P_LPASS_AON_CC_PLL_OUT_EVEN,
 31	P_LPASS_AON_CC_PLL_OUT_MAIN,
 32	P_LPASS_AON_CC_PLL_OUT_MAIN_CDIV_DIV_CLK_SRC,
 33	P_LPASS_AON_CC_PLL_OUT_ODD,
 34	P_LPASS_AUDIO_CC_PLL_OUT_AUX,
 35	P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC,
 36	P_LPASS_AUDIO_CC_PLL_MAIN_DIV_CLK,
 37};
 38
 39static const struct pll_vco zonda_vco[] = {
 40	{ 595200000UL, 3600000000UL, 0 },
 41};
 42
 43static struct clk_branch lpass_q6ss_ahbm_clk = {
 44	.halt_reg = 0x901c,
 45	.halt_check = BRANCH_HALT,
 46	.clkr = {
 47		.enable_reg = 0x901c,
 48		.enable_mask = BIT(0),
 49		.hw.init = &(struct clk_init_data){
 50				.name = "lpass_q6ss_ahbm_clk",
 51				.ops = &clk_branch2_ops,
 52		},
 53	},
 54};
 55
 56static struct clk_branch lpass_q6ss_ahbs_clk = {
 57	.halt_reg = 0x9020,
 58	.halt_check = BRANCH_HALT_VOTED,
 59	.clkr = {
 60		.enable_reg = 0x9020,
 61		.enable_mask = BIT(0),
 62		.hw.init = &(struct clk_init_data){
 63			.name = "lpass_q6ss_ahbs_clk",
 64			.ops = &clk_branch2_ops,
 65		},
 66	},
 67};
 68
 69/* 1128.96MHz configuration */
 70static const struct alpha_pll_config lpass_audio_cc_pll_config = {
 71	.l = 0x3a,
 72	.alpha = 0xcccc,
 73	.config_ctl_val = 0x08200920,
 74	.config_ctl_hi_val = 0x05002001,
 75	.config_ctl_hi1_val = 0x00000000,
 76	.user_ctl_val = 0x03000101,
 77};
 78
 79static struct clk_alpha_pll lpass_audio_cc_pll = {
 80	.offset = 0x0,
 81	.vco_table = zonda_vco,
 82	.num_vco = ARRAY_SIZE(zonda_vco),
 83	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
 84	.clkr = {
 85		.hw.init = &(const struct clk_init_data){
 86			.name = "lpass_audio_cc_pll",
 87			.parent_data = &(const struct clk_parent_data){
 88				.index = 0,
 89			},
 90			.num_parents = 1,
 91			.ops = &clk_alpha_pll_zonda_ops,
 92		},
 93	},
 94};
 95
 96static const struct clk_div_table post_div_table_lpass_audio_cc_pll_out_aux2[] = {
 97	{ 0x1, 2 },
 98	{ }
 99};
100
101static struct clk_alpha_pll_postdiv lpass_audio_cc_pll_out_aux2 = {
102	.offset = 0x0,
103	.post_div_shift = 8,
104	.post_div_table = post_div_table_lpass_audio_cc_pll_out_aux2,
105	.num_post_div = ARRAY_SIZE(post_div_table_lpass_audio_cc_pll_out_aux2),
106	.width = 2,
107	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
108	.clkr.hw.init = &(const struct clk_init_data){
109		.name = "lpass_audio_cc_pll_out_aux2",
110		.parent_hws = (const struct clk_hw*[]){
111			&lpass_audio_cc_pll.clkr.hw,
112		},
113		.num_parents = 1,
114		.ops = &clk_alpha_pll_postdiv_zonda_ops,
115	},
116};
117
118static const struct pll_vco lucid_vco[] = {
119	{ 249600000, 2000000000, 0 },
120};
121
122/* 614.4 MHz configuration */
123static const struct alpha_pll_config lpass_aon_cc_pll_config = {
124	.l = 0x20,
125	.alpha = 0x0,
126	.config_ctl_val = 0x20485699,
127	.config_ctl_hi_val = 0x00002261,
128	.config_ctl_hi1_val = 0x329A299C,
129	.user_ctl_val = 0x00005100,
130	.user_ctl_hi_val = 0x00000805,
131	.user_ctl_hi1_val = 0x00000000,
132};
133
134static struct clk_alpha_pll lpass_aon_cc_pll = {
135	.offset = 0x0,
136	.vco_table = lucid_vco,
137	.num_vco = ARRAY_SIZE(lucid_vco),
138	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
139	.clkr = {
140		.hw.init = &(const struct clk_init_data){
141			.name = "lpass_aon_cc_pll",
142			.parent_data = &(const struct clk_parent_data){
143				.index = 0,
144			},
145			.num_parents = 1,
146			.ops = &clk_alpha_pll_lucid_ops,
147		},
148	},
149};
150
151static const struct clk_div_table post_div_table_lpass_aon_cc_pll_out_even[] = {
152	{ 0x1, 2 },
153	{ }
154};
155
156static struct clk_alpha_pll_postdiv lpass_aon_cc_pll_out_even = {
157	.offset = 0x0,
158	.post_div_shift = 8,
159	.post_div_table = post_div_table_lpass_aon_cc_pll_out_even,
160	.num_post_div = ARRAY_SIZE(post_div_table_lpass_aon_cc_pll_out_even),
161	.width = 4,
162	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
163	.clkr.hw.init = &(const struct clk_init_data){
164		.name = "lpass_aon_cc_pll_out_even",
165		.parent_hws = (const struct clk_hw*[]){
166			&lpass_aon_cc_pll.clkr.hw,
167		},
168		.num_parents = 1,
169		.ops = &clk_alpha_pll_postdiv_lucid_ops,
170	},
171};
172
173static const struct clk_div_table post_div_table_lpass_aon_cc_pll_out_odd[] = {
174	{ 0x5, 5 },
175	{ }
176};
177
178static struct clk_alpha_pll_postdiv lpass_aon_cc_pll_out_odd = {
179	.offset = 0x0,
180	.post_div_shift = 12,
181	.post_div_table = post_div_table_lpass_aon_cc_pll_out_odd,
182	.num_post_div = ARRAY_SIZE(post_div_table_lpass_aon_cc_pll_out_odd),
183	.width = 4,
184	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
185	.clkr.hw.init = &(const struct clk_init_data){
186		.name = "lpass_aon_cc_pll_out_odd",
187		.parent_hws = (const struct clk_hw*[]){
188			&lpass_aon_cc_pll.clkr.hw,
189		},
190		.num_parents = 1,
191		.ops = &clk_alpha_pll_postdiv_lucid_ops,
192	},
193};
194
195static const struct parent_map lpass_audio_cc_parent_map_0[] = {
196	{ P_BI_TCXO, 0 },
197	{ P_LPASS_AUDIO_CC_PLL_OUT_AUX, 3 },
198	{ P_LPASS_AON_CC_PLL_OUT_ODD, 5 },
199	{ P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 6 },
200};
201
202static struct clk_regmap_div lpass_audio_cc_pll_out_aux2_div_clk_src;
203static struct clk_regmap_div lpass_audio_cc_pll_out_main_div_clk_src;
204
205static const struct clk_parent_data lpass_audio_cc_parent_data_0[] = {
206	{ .index = 0 },
207	{ .hw = &lpass_audio_cc_pll.clkr.hw },
208	{ .hw = &lpass_aon_cc_pll_out_odd.clkr.hw },
209	{ .hw = &lpass_audio_cc_pll_out_aux2_div_clk_src.clkr.hw },
210};
211
212static const struct parent_map lpass_aon_cc_parent_map_0[] = {
213	{ P_BI_TCXO, 0 },
214	{ P_LPASS_AON_CC_PLL_OUT_EVEN, 4 },
215};
216
217static const struct clk_parent_data lpass_aon_cc_parent_data_0[] = {
218	{ .index = 0 },
219	{ .hw = &lpass_aon_cc_pll_out_even.clkr.hw },
220};
221
222static const struct parent_map lpass_aon_cc_parent_map_1[] = {
223	{ P_BI_TCXO, 0 },
224	{ P_LPASS_AON_CC_PLL_OUT_ODD, 1 },
225	{ P_LPASS_AUDIO_CC_PLL_MAIN_DIV_CLK, 6 },
226};
227
228static const struct clk_parent_data lpass_aon_cc_parent_data_1[] = {
229	{ .index = 0 },
230	{ .hw = &lpass_aon_cc_pll_out_odd.clkr.hw },
231	{ .hw = &lpass_audio_cc_pll_out_main_div_clk_src.clkr.hw },
232};
233
234static const struct freq_tbl ftbl_lpass_aon_cc_main_rcg_clk_src[] = {
235	F(38400000, P_LPASS_AON_CC_PLL_OUT_EVEN, 8, 0, 0),
236	F(76800000, P_LPASS_AON_CC_PLL_OUT_EVEN, 4, 0, 0),
237	F(153600000, P_LPASS_AON_CC_PLL_OUT_EVEN, 2, 0, 0),
238	{ }
239};
240
241static struct clk_rcg2 lpass_aon_cc_main_rcg_clk_src = {
242	.cmd_rcgr = 0x1000,
243	.mnd_width = 0,
244	.hid_width = 5,
245	.parent_map = lpass_aon_cc_parent_map_0,
246	.freq_tbl = ftbl_lpass_aon_cc_main_rcg_clk_src,
247	.clkr.hw.init = &(const struct clk_init_data){
248		.name = "lpass_aon_cc_main_rcg_clk_src",
249		.parent_data = lpass_aon_cc_parent_data_0,
250		.num_parents = ARRAY_SIZE(lpass_aon_cc_parent_data_0),
251		.flags = CLK_OPS_PARENT_ENABLE,
252		.ops = &clk_rcg2_shared_ops,
253	},
254};
255
256static const struct freq_tbl ftbl_lpass_aon_cc_tx_mclk_rcg_clk_src[] = {
257	F(19200000, P_BI_TCXO, 1, 0, 0),
258	F(24576000, P_LPASS_AON_CC_PLL_OUT_ODD, 5, 0, 0),
259	{ }
260};
261
262static struct clk_rcg2 lpass_aon_cc_tx_mclk_rcg_clk_src = {
263	.cmd_rcgr = 0x13004,
264	.mnd_width = 0,
265	.hid_width = 5,
266	.parent_map = lpass_aon_cc_parent_map_1,
267	.freq_tbl = ftbl_lpass_aon_cc_tx_mclk_rcg_clk_src,
268	.clkr.hw.init = &(const struct clk_init_data){
269		.name = "lpass_aon_cc_tx_mclk_rcg_clk_src",
270		.parent_data = lpass_aon_cc_parent_data_1,
271		.num_parents = ARRAY_SIZE(lpass_aon_cc_parent_data_1),
272		.ops = &clk_rcg2_ops,
273	},
274};
275
276static struct clk_regmap_div lpass_audio_cc_pll_out_aux2_div_clk_src = {
277	.reg = 0x48,
278	.shift = 0,
279	.width = 4,
280	.clkr.hw.init = &(const struct clk_init_data) {
281		.name = "lpass_audio_cc_pll_out_aux2_div_clk_src",
282		.parent_hws = (const struct clk_hw*[]){
283			&lpass_audio_cc_pll_out_aux2.clkr.hw,
284		},
285		.num_parents = 1,
286		.flags = CLK_SET_RATE_PARENT,
287		.ops = &clk_regmap_div_ro_ops,
288	},
289};
290
291static struct clk_regmap_div lpass_audio_cc_pll_out_main_div_clk_src = {
292	.reg = 0x3c,
293	.shift = 0,
294	.width = 4,
295	.clkr.hw.init = &(const struct clk_init_data) {
296		.name = "lpass_audio_cc_pll_out_main_div_clk_src",
297		.parent_hws = (const struct clk_hw*[]){
298			&lpass_audio_cc_pll.clkr.hw,
299		},
300		.num_parents = 1,
301		.flags = CLK_SET_RATE_PARENT,
302		.ops = &clk_regmap_div_ro_ops,
303	},
304};
305
306static struct clk_regmap_div lpass_aon_cc_cdiv_tx_mclk_div_clk_src = {
307	.reg = 0x13010,
308	.shift = 0,
309	.width = 4,
310	.clkr.hw.init = &(const struct clk_init_data) {
311		.name = "lpass_aon_cc_cdiv_tx_mclk_div_clk_src",
312		.parent_hws = (const struct clk_hw*[]){
313			&lpass_aon_cc_tx_mclk_rcg_clk_src.clkr.hw,
314		},
315		.num_parents = 1,
316		.flags = CLK_SET_RATE_PARENT,
317		.ops = &clk_regmap_div_ro_ops,
318	},
319};
320
321static struct clk_regmap_div lpass_aon_cc_pll_out_main_cdiv_div_clk_src = {
322	.reg = 0x80,
323	.shift = 0,
324	.width = 4,
325	.clkr.hw.init = &(const struct clk_init_data) {
326		.name = "lpass_aon_cc_pll_out_main_cdiv_div_clk_src",
327		.parent_hws = (const struct clk_hw*[]){
328			&lpass_aon_cc_pll.clkr.hw,
329		},
330		.num_parents = 1,
331		.flags = CLK_SET_RATE_PARENT,
332		.ops = &clk_regmap_div_ro_ops,
333	},
334};
335
336static const struct freq_tbl ftbl_lpass_audio_cc_ext_mclk0_clk_src[] = {
337	F(256000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 32),
338	F(352800, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 32),
339	F(512000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 16),
340	F(705600, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 16),
341	F(768000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 1, 16),
342	F(1024000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 8),
343	F(1411200, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 8),
344	F(1536000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 1, 8),
345	F(2048000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 4),
346	F(2822400, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 4),
347	F(3072000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 1, 4),
348	F(4096000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 2),
349	F(5644800, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 2),
350	F(6144000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 1, 2),
351	F(8192000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 0, 0),
352	F(9600000, P_BI_TCXO, 2, 0, 0),
353	F(11289600, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 0, 0),
354	F(12288000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 0, 0),
355	F(19200000, P_BI_TCXO, 1, 0, 0),
356	F(22579200, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 5, 0, 0),
357	F(24576000, P_LPASS_AON_CC_PLL_OUT_ODD, 5, 0, 0),
358	{ }
359};
360
361static struct clk_rcg2 lpass_audio_cc_ext_mclk0_clk_src = {
362	.cmd_rcgr = 0x20004,
363	.mnd_width = 8,
364	.hid_width = 5,
365	.parent_map = lpass_audio_cc_parent_map_0,
366	.freq_tbl = ftbl_lpass_audio_cc_ext_mclk0_clk_src,
367	.clkr.hw.init = &(const struct clk_init_data){
368		.name = "lpass_audio_cc_ext_mclk0_clk_src",
369		.parent_data = lpass_audio_cc_parent_data_0,
370		.num_parents = ARRAY_SIZE(lpass_audio_cc_parent_data_0),
371		.ops = &clk_rcg2_ops,
372	},
373};
374
375static struct clk_rcg2 lpass_audio_cc_ext_mclk1_clk_src = {
376	.cmd_rcgr = 0x21004,
377	.mnd_width = 8,
378	.hid_width = 5,
379	.parent_map = lpass_audio_cc_parent_map_0,
380	.freq_tbl = ftbl_lpass_audio_cc_ext_mclk0_clk_src,
381	.clkr.hw.init = &(const struct clk_init_data){
382		.name = "lpass_audio_cc_ext_mclk1_clk_src",
383		.parent_data = lpass_audio_cc_parent_data_0,
384		.num_parents = ARRAY_SIZE(lpass_audio_cc_parent_data_0),
385		.ops = &clk_rcg2_ops,
386	},
387};
388
389static struct clk_rcg2 lpass_audio_cc_rx_mclk_clk_src = {
390	.cmd_rcgr = 0x24004,
391	.mnd_width = 8,
392	.hid_width = 5,
393	.parent_map = lpass_audio_cc_parent_map_0,
394	.freq_tbl = ftbl_lpass_audio_cc_ext_mclk0_clk_src,
395	.clkr.hw.init = &(const struct clk_init_data){
396		.name = "lpass_audio_cc_rx_mclk_clk_src",
397		.parent_data = lpass_audio_cc_parent_data_0,
398		.num_parents = ARRAY_SIZE(lpass_audio_cc_parent_data_0),
399		.ops = &clk_rcg2_ops,
400	},
401};
402
403static struct clk_regmap_div lpass_audio_cc_cdiv_rx_mclk_div_clk_src = {
404	.reg = 0x240d0,
405	.shift = 0,
406	.width = 4,
407	.clkr.hw.init = &(const struct clk_init_data) {
408		.name = "lpass_audio_cc_cdiv_rx_mclk_div_clk_src",
409		.parent_hws = (const struct clk_hw*[]){
410			&lpass_audio_cc_rx_mclk_clk_src.clkr.hw,
411		},
412		.num_parents = 1,
413		.flags = CLK_SET_RATE_PARENT,
414		.ops = &clk_regmap_div_ro_ops,
415	},
416};
417
418static struct clk_branch lpass_aon_cc_audio_hm_h_clk;
419
420static struct clk_branch lpass_audio_cc_codec_mem0_clk = {
421	.halt_reg = 0x1e004,
422	.halt_check = BRANCH_HALT,
423	.clkr = {
424		.enable_reg = 0x1e004,
425		.enable_mask = BIT(0),
426		.hw.init = &(const struct clk_init_data){
427			.name = "lpass_audio_cc_codec_mem0_clk",
428			.parent_hws = (const struct clk_hw*[]){
429				&lpass_aon_cc_audio_hm_h_clk.clkr.hw,
430			},
431			.num_parents = 1,
432			.flags = CLK_SET_RATE_PARENT,
433			.ops = &clk_branch2_ops,
434		},
435	},
436};
437
438static struct clk_branch lpass_audio_cc_codec_mem1_clk = {
439	.halt_reg = 0x1e008,
440	.halt_check = BRANCH_HALT,
441	.clkr = {
442		.enable_reg = 0x1e008,
443		.enable_mask = BIT(0),
444		.hw.init = &(const struct clk_init_data){
445			.name = "lpass_audio_cc_codec_mem1_clk",
446			.parent_hws = (const struct clk_hw*[]){
447				&lpass_aon_cc_audio_hm_h_clk.clkr.hw,
448			},
449			.num_parents = 1,
450			.flags = CLK_SET_RATE_PARENT,
451			.ops = &clk_branch2_ops,
452		},
453	},
454};
455
456static struct clk_branch lpass_audio_cc_codec_mem2_clk = {
457	.halt_reg = 0x1e00c,
458	.halt_check = BRANCH_HALT,
459	.clkr = {
460		.enable_reg = 0x1e00c,
461		.enable_mask = BIT(0),
462		.hw.init = &(const struct clk_init_data){
463			.name = "lpass_audio_cc_codec_mem2_clk",
464			.parent_hws = (const struct clk_hw*[]){
465				&lpass_aon_cc_audio_hm_h_clk.clkr.hw,
466			},
467			.num_parents = 1,
468			.flags = CLK_SET_RATE_PARENT,
469			.ops = &clk_branch2_ops,
470		},
471	},
472};
473
474static struct clk_branch lpass_audio_cc_codec_mem_clk = {
475	.halt_reg = 0x1e000,
476	.halt_check = BRANCH_HALT,
477	.clkr = {
478		.enable_reg = 0x1e000,
479		.enable_mask = BIT(0),
480		.hw.init = &(const struct clk_init_data){
481			.name = "lpass_audio_cc_codec_mem_clk",
482			.parent_hws = (const struct clk_hw*[]){
483				&lpass_aon_cc_audio_hm_h_clk.clkr.hw,
484			},
485			.num_parents = 1,
486			.flags = CLK_SET_RATE_PARENT,
487			.ops = &clk_branch2_ops,
488		},
489	},
490};
491
492static struct clk_branch lpass_audio_cc_ext_mclk0_clk = {
493	.halt_reg = 0x20018,
494	.halt_check = BRANCH_HALT,
495	.clkr = {
496		.enable_reg = 0x20018,
497		.enable_mask = BIT(0),
498		.hw.init = &(const struct clk_init_data){
499			.name = "lpass_audio_cc_ext_mclk0_clk",
500			.parent_hws = (const struct clk_hw*[]){
501				&lpass_audio_cc_ext_mclk0_clk_src.clkr.hw,
502			},
503			.num_parents = 1,
504			.flags = CLK_SET_RATE_PARENT,
505			.ops = &clk_branch2_ops,
506		},
507	},
508};
509
510static struct clk_branch lpass_audio_cc_ext_mclk1_clk = {
511	.halt_reg = 0x21018,
512	.halt_check = BRANCH_HALT,
513	.clkr = {
514		.enable_reg = 0x21018,
515		.enable_mask = BIT(0),
516		.hw.init = &(const struct clk_init_data){
517			.name = "lpass_audio_cc_ext_mclk1_clk",
518			.parent_hws = (const struct clk_hw*[]){
519				&lpass_audio_cc_ext_mclk1_clk_src.clkr.hw,
520			},
521			.num_parents = 1,
522			.flags = CLK_SET_RATE_PARENT,
523			.ops = &clk_branch2_ops,
524		},
525	},
526};
527
528static struct clk_branch lpass_audio_cc_rx_mclk_2x_clk = {
529	.halt_reg = 0x240cc,
530	.halt_check = BRANCH_HALT,
531	.clkr = {
532		.enable_reg = 0x240cc,
533		.enable_mask = BIT(0),
534		.hw.init = &(const struct clk_init_data){
535			.name = "lpass_audio_cc_rx_mclk_2x_clk",
536			.parent_hws = (const struct clk_hw*[]){
537				&lpass_audio_cc_rx_mclk_clk_src.clkr.hw,
538			},
539			.num_parents = 1,
540			.flags = CLK_SET_RATE_PARENT,
541			.ops = &clk_branch2_ops,
542		},
543	},
544};
545
546static struct clk_branch lpass_audio_cc_rx_mclk_clk = {
547	.halt_reg = 0x240d4,
548	.halt_check = BRANCH_HALT,
549	.clkr = {
550		.enable_reg = 0x240d4,
551		.enable_mask = BIT(0),
552		.hw.init = &(const struct clk_init_data){
553			.name = "lpass_audio_cc_rx_mclk_clk",
554			.parent_hws = (const struct clk_hw*[]){
555				&lpass_audio_cc_cdiv_rx_mclk_div_clk_src.clkr.hw,
556			},
557			.num_parents = 1,
558			.flags = CLK_SET_RATE_PARENT,
559			.ops = &clk_branch2_ops,
560		},
561	},
562};
563
564static struct clk_branch lpass_aon_cc_audio_hm_h_clk = {
565	.halt_reg = 0x9014,
566	.halt_check = BRANCH_HALT,
567	.clkr = {
568		.enable_reg = 0x9014,
569		.enable_mask = BIT(0),
570		.hw.init = &(const struct clk_init_data){
571			.name = "lpass_aon_cc_audio_hm_h_clk",
572			.parent_hws = (const struct clk_hw*[]){
573				&lpass_aon_cc_main_rcg_clk_src.clkr.hw,
574			},
575			.num_parents = 1,
576			.flags = CLK_SET_RATE_PARENT,
577			.ops = &clk_branch2_aon_ops,
578		},
579	},
580};
581
582static struct clk_branch lpass_aon_cc_va_mem0_clk = {
583	.halt_reg = 0x9028,
584	.halt_check = BRANCH_HALT,
585	.clkr = {
586		.enable_reg = 0x9028,
587		.enable_mask = BIT(0),
588		.hw.init = &(const struct clk_init_data){
589			.name = "lpass_aon_cc_va_mem0_clk",
590			.parent_hws = (const struct clk_hw*[]){
591				&lpass_aon_cc_main_rcg_clk_src.clkr.hw,
592			},
593			.num_parents = 1,
594			.flags = CLK_SET_RATE_PARENT,
595			.ops = &clk_branch2_ops,
596		},
597	},
598};
599
600static struct clk_branch lpass_aon_cc_tx_mclk_2x_clk = {
601	.halt_reg = 0x1300c,
602	.halt_check = BRANCH_HALT,
603	.clkr = {
604		.enable_reg = 0x1300c,
605		.enable_mask = BIT(0),
606		.hw.init = &(const struct clk_init_data){
607			.name = "lpass_aon_cc_tx_mclk_2x_clk",
608			.parent_hws = (const struct clk_hw*[]){
609				&lpass_aon_cc_tx_mclk_rcg_clk_src.clkr.hw,
610			},
611			.num_parents = 1,
612			.flags = CLK_SET_RATE_PARENT,
613			.ops = &clk_branch2_ops,
614		},
615	},
616};
617
618static struct clk_branch lpass_aon_cc_tx_mclk_clk = {
619	.halt_reg = 0x13014,
620	.halt_check = BRANCH_HALT,
621	.clkr = {
622		.enable_reg = 0x13014,
623		.enable_mask = BIT(0),
624		.hw.init = &(const struct clk_init_data){
625			.name = "lpass_aon_cc_tx_mclk_clk",
626			.parent_hws = (const struct clk_hw*[]){
627				&lpass_aon_cc_cdiv_tx_mclk_div_clk_src.clkr.hw,
628			},
629			.num_parents = 1,
630			.flags = CLK_SET_RATE_PARENT,
631			.ops = &clk_branch2_ops,
632		},
633	},
634};
635
636static struct gdsc lpass_aon_cc_lpass_audio_hm_gdsc = {
637	.gdscr = 0x9090,
638	.pd = {
639		.name = "lpass_aon_cc_lpass_audio_hm_gdsc",
640	},
641	.pwrsts = PWRSTS_OFF_ON,
642	.flags = RETAIN_FF_ENABLE,
643};
644
645static struct clk_regmap *lpass_cc_sc7280_clocks[] = {
646	[LPASS_Q6SS_AHBM_CLK] = &lpass_q6ss_ahbm_clk.clkr,
647	[LPASS_Q6SS_AHBS_CLK] = &lpass_q6ss_ahbs_clk.clkr,
648};
649
650static struct clk_regmap *lpass_aon_cc_sc7280_clocks[] = {
651	[LPASS_AON_CC_AUDIO_HM_H_CLK] = &lpass_aon_cc_audio_hm_h_clk.clkr,
652	[LPASS_AON_CC_VA_MEM0_CLK] = &lpass_aon_cc_va_mem0_clk.clkr,
653	[LPASS_AON_CC_CDIV_TX_MCLK_DIV_CLK_SRC] = &lpass_aon_cc_cdiv_tx_mclk_div_clk_src.clkr,
654	[LPASS_AON_CC_MAIN_RCG_CLK_SRC] = &lpass_aon_cc_main_rcg_clk_src.clkr,
655	[LPASS_AON_CC_PLL] = &lpass_aon_cc_pll.clkr,
656	[LPASS_AON_CC_PLL_OUT_EVEN] = &lpass_aon_cc_pll_out_even.clkr,
657	[LPASS_AON_CC_PLL_OUT_MAIN_CDIV_DIV_CLK_SRC] =
658		&lpass_aon_cc_pll_out_main_cdiv_div_clk_src.clkr,
659	[LPASS_AON_CC_PLL_OUT_ODD] = &lpass_aon_cc_pll_out_odd.clkr,
660	[LPASS_AON_CC_TX_MCLK_2X_CLK] = &lpass_aon_cc_tx_mclk_2x_clk.clkr,
661	[LPASS_AON_CC_TX_MCLK_CLK] = &lpass_aon_cc_tx_mclk_clk.clkr,
662	[LPASS_AON_CC_TX_MCLK_RCG_CLK_SRC] = &lpass_aon_cc_tx_mclk_rcg_clk_src.clkr,
663};
664
665static struct gdsc *lpass_aon_cc_sc7280_gdscs[] = {
666	[LPASS_AON_CC_LPASS_AUDIO_HM_GDSC] = &lpass_aon_cc_lpass_audio_hm_gdsc,
667};
668
669static struct clk_regmap *lpass_audio_cc_sc7280_clocks[] = {
670	[LPASS_AUDIO_CC_CDIV_RX_MCLK_DIV_CLK_SRC] = &lpass_audio_cc_cdiv_rx_mclk_div_clk_src.clkr,
671	[LPASS_AUDIO_CC_CODEC_MEM0_CLK] = &lpass_audio_cc_codec_mem0_clk.clkr,
672	[LPASS_AUDIO_CC_CODEC_MEM1_CLK] = &lpass_audio_cc_codec_mem1_clk.clkr,
673	[LPASS_AUDIO_CC_CODEC_MEM2_CLK] = &lpass_audio_cc_codec_mem2_clk.clkr,
674	[LPASS_AUDIO_CC_CODEC_MEM_CLK] = &lpass_audio_cc_codec_mem_clk.clkr,
675	[LPASS_AUDIO_CC_EXT_MCLK0_CLK] = &lpass_audio_cc_ext_mclk0_clk.clkr,
676	[LPASS_AUDIO_CC_EXT_MCLK0_CLK_SRC] = &lpass_audio_cc_ext_mclk0_clk_src.clkr,
677	[LPASS_AUDIO_CC_EXT_MCLK1_CLK] = &lpass_audio_cc_ext_mclk1_clk.clkr,
678	[LPASS_AUDIO_CC_EXT_MCLK1_CLK_SRC] = &lpass_audio_cc_ext_mclk1_clk_src.clkr,
679	[LPASS_AUDIO_CC_PLL] = &lpass_audio_cc_pll.clkr,
680	[LPASS_AUDIO_CC_PLL_OUT_AUX2] = &lpass_audio_cc_pll_out_aux2.clkr,
681	[LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC] = &lpass_audio_cc_pll_out_aux2_div_clk_src.clkr,
682	[LPASS_AUDIO_CC_PLL_OUT_MAIN_DIV_CLK_SRC] = &lpass_audio_cc_pll_out_main_div_clk_src.clkr,
683	[LPASS_AUDIO_CC_RX_MCLK_2X_CLK] = &lpass_audio_cc_rx_mclk_2x_clk.clkr,
684	[LPASS_AUDIO_CC_RX_MCLK_CLK] = &lpass_audio_cc_rx_mclk_clk.clkr,
685	[LPASS_AUDIO_CC_RX_MCLK_CLK_SRC] = &lpass_audio_cc_rx_mclk_clk_src.clkr,
686};
687
688static struct regmap_config lpass_audio_cc_sc7280_regmap_config = {
689	.reg_bits = 32,
690	.reg_stride = 4,
691	.val_bits = 32,
692	.fast_io = true,
693};
694
695static const struct qcom_cc_desc lpass_cc_sc7280_desc = {
696	.config = &lpass_audio_cc_sc7280_regmap_config,
697	.clks = lpass_cc_sc7280_clocks,
698	.num_clks = ARRAY_SIZE(lpass_cc_sc7280_clocks),
699};
700
701static const struct qcom_cc_desc lpass_audio_cc_sc7280_desc = {
702	.config = &lpass_audio_cc_sc7280_regmap_config,
703	.clks = lpass_audio_cc_sc7280_clocks,
704	.num_clks = ARRAY_SIZE(lpass_audio_cc_sc7280_clocks),
705};
706
707static const struct qcom_reset_map lpass_audio_cc_sc7280_resets[] = {
708	[LPASS_AUDIO_SWR_RX_CGCR] =  { 0xa0, 1 },
709	[LPASS_AUDIO_SWR_TX_CGCR] =  { 0xa8, 1 },
710	[LPASS_AUDIO_SWR_WSA_CGCR] = { 0xb0, 1 },
711};
712
713static const struct qcom_cc_desc lpass_audio_cc_reset_sc7280_desc = {
714	.config = &lpass_audio_cc_sc7280_regmap_config,
715	.resets = lpass_audio_cc_sc7280_resets,
716	.num_resets = ARRAY_SIZE(lpass_audio_cc_sc7280_resets),
717};
718
719static const struct of_device_id lpass_audio_cc_sc7280_match_table[] = {
720	{ .compatible = "qcom,sc7280-lpassaudiocc" },
721	{ }
722};
723MODULE_DEVICE_TABLE(of, lpass_audio_cc_sc7280_match_table);
724
725static int lpass_audio_setup_runtime_pm(struct platform_device *pdev)
726{
727	int ret;
728
729	pm_runtime_use_autosuspend(&pdev->dev);
730	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
731	ret = devm_pm_runtime_enable(&pdev->dev);
732	if (ret)
733		return ret;
734
735	ret = devm_pm_clk_create(&pdev->dev);
736	if (ret)
737		return ret;
738
739	ret = pm_clk_add(&pdev->dev, "iface");
740	if (ret < 0)
741		dev_err(&pdev->dev, "failed to acquire iface clock\n");
742
743	return pm_runtime_resume_and_get(&pdev->dev);
744}
745
746static int lpass_audio_cc_sc7280_probe(struct platform_device *pdev)
747{
748	const struct qcom_cc_desc *desc;
749	struct regmap *regmap;
750	int ret;
751
752	ret = lpass_audio_setup_runtime_pm(pdev);
753	if (ret)
754		return ret;
755
756	lpass_audio_cc_sc7280_regmap_config.name = "lpassaudio_cc";
757	lpass_audio_cc_sc7280_regmap_config.max_register = 0x2f000;
758	desc = &lpass_audio_cc_sc7280_desc;
759
760	regmap = qcom_cc_map(pdev, desc);
761	if (IS_ERR(regmap)) {
762		ret = PTR_ERR(regmap);
763		goto exit;
764	}
765
766	clk_zonda_pll_configure(&lpass_audio_cc_pll, regmap, &lpass_audio_cc_pll_config);
767
768	/* PLL settings */
769	regmap_write(regmap, 0x4, 0x3b);
770	regmap_write(regmap, 0x8, 0xff05);
771
772	ret = qcom_cc_really_probe(pdev, &lpass_audio_cc_sc7280_desc, regmap);
773	if (ret) {
774		dev_err(&pdev->dev, "Failed to register LPASS AUDIO CC clocks\n");
775		goto exit;
776	}
777
778	ret = qcom_cc_probe_by_index(pdev, 1, &lpass_audio_cc_reset_sc7280_desc);
779	if (ret) {
780		dev_err(&pdev->dev, "Failed to register LPASS AUDIO CC Resets\n");
781		goto exit;
782	}
783
784	pm_runtime_mark_last_busy(&pdev->dev);
785exit:
786	pm_runtime_put_autosuspend(&pdev->dev);
787
788	return ret;
789}
790
791static const struct dev_pm_ops lpass_audio_cc_pm_ops = {
792	SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
793};
794
795static struct platform_driver lpass_audio_cc_sc7280_driver = {
796	.probe = lpass_audio_cc_sc7280_probe,
797	.driver = {
798		.name = "lpass_audio_cc-sc7280",
799		.of_match_table = lpass_audio_cc_sc7280_match_table,
800		.pm = &lpass_audio_cc_pm_ops,
801	},
802};
803
804static const struct qcom_cc_desc lpass_aon_cc_sc7280_desc = {
805	.config = &lpass_audio_cc_sc7280_regmap_config,
806	.clks = lpass_aon_cc_sc7280_clocks,
807	.num_clks = ARRAY_SIZE(lpass_aon_cc_sc7280_clocks),
808	.gdscs = lpass_aon_cc_sc7280_gdscs,
809	.num_gdscs = ARRAY_SIZE(lpass_aon_cc_sc7280_gdscs),
810};
811
812static const struct of_device_id lpass_aon_cc_sc7280_match_table[] = {
813	{ .compatible = "qcom,sc7280-lpassaoncc" },
814	{ }
815};
816MODULE_DEVICE_TABLE(of, lpass_aon_cc_sc7280_match_table);
817
818static int lpass_aon_cc_sc7280_probe(struct platform_device *pdev)
819{
820	const struct qcom_cc_desc *desc;
821	struct regmap *regmap;
822	int ret;
823
824	ret = lpass_audio_setup_runtime_pm(pdev);
825	if (ret)
826		return ret;
827
828	if (of_property_read_bool(pdev->dev.of_node, "qcom,adsp-pil-mode")) {
829		lpass_audio_cc_sc7280_regmap_config.name = "cc";
830		desc = &lpass_cc_sc7280_desc;
831		ret = qcom_cc_probe(pdev, desc);
832		goto exit;
833	}
834
835	lpass_audio_cc_sc7280_regmap_config.name = "lpasscc_aon";
836	lpass_audio_cc_sc7280_regmap_config.max_register = 0xa0008;
837	desc = &lpass_aon_cc_sc7280_desc;
838
839	regmap = qcom_cc_map(pdev, desc);
840	if (IS_ERR(regmap)) {
841		ret = PTR_ERR(regmap);
842		goto exit;
843	}
844
845	clk_lucid_pll_configure(&lpass_aon_cc_pll, regmap, &lpass_aon_cc_pll_config);
846
847	ret = qcom_cc_really_probe(pdev, &lpass_aon_cc_sc7280_desc, regmap);
848	if (ret) {
849		dev_err(&pdev->dev, "Failed to register LPASS AON CC clocks\n");
850		goto exit;
851	}
852
853	pm_runtime_mark_last_busy(&pdev->dev);
854exit:
855	pm_runtime_put_autosuspend(&pdev->dev);
856
857	return ret;
858}
859
860static struct platform_driver lpass_aon_cc_sc7280_driver = {
861	.probe = lpass_aon_cc_sc7280_probe,
862	.driver = {
863		.name = "lpass_aon_cc-sc7280",
864		.of_match_table = lpass_aon_cc_sc7280_match_table,
865		.pm = &lpass_audio_cc_pm_ops,
866	},
867};
868
869static int __init lpass_audio_cc_sc7280_init(void)
870{
871	int ret;
872
873	ret = platform_driver_register(&lpass_aon_cc_sc7280_driver);
874	if (ret)
875		return ret;
876
877	return platform_driver_register(&lpass_audio_cc_sc7280_driver);
878}
879subsys_initcall(lpass_audio_cc_sc7280_init);
880
881static void __exit lpass_audio_cc_sc7280_exit(void)
882{
883	platform_driver_unregister(&lpass_audio_cc_sc7280_driver);
884	platform_driver_unregister(&lpass_aon_cc_sc7280_driver);
885}
886module_exit(lpass_audio_cc_sc7280_exit);
887
888MODULE_DESCRIPTION("QTI LPASS_AUDIO_CC SC7280 Driver");
889MODULE_LICENSE("GPL v2");