Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  4 * Copyright (c) BayLibre, SAS.
  5 * Author : Neil Armstrong <narmstrong@baylibre.com>
  6 */
  7
  8#include <linux/kernel.h>
  9#include <linux/bitops.h>
 10#include <linux/err.h>
 11#include <linux/platform_device.h>
 12#include <linux/module.h>
 13#include <linux/of.h>
 14#include <linux/of_device.h>
 15#include <linux/clk-provider.h>
 16#include <linux/regmap.h>
 17
 18#include <dt-bindings/clock/qcom,lcc-mdm9615.h>
 19
 20#include "common.h"
 21#include "clk-regmap.h"
 22#include "clk-pll.h"
 23#include "clk-rcg.h"
 24#include "clk-branch.h"
 25#include "clk-regmap-divider.h"
 26#include "clk-regmap-mux.h"
 27
 28static struct clk_pll pll4 = {
 29	.l_reg = 0x4,
 30	.m_reg = 0x8,
 31	.n_reg = 0xc,
 32	.config_reg = 0x14,
 33	.mode_reg = 0x0,
 34	.status_reg = 0x18,
 35	.status_bit = 16,
 36	.clkr.hw.init = &(struct clk_init_data){
 37		.name = "pll4",
 38		.parent_names = (const char *[]){ "cxo" },
 39		.num_parents = 1,
 40		.ops = &clk_pll_ops,
 41	},
 42};
 43
 44enum {
 45	P_CXO,
 46	P_PLL4,
 47};
 48
 49static const struct parent_map lcc_cxo_pll4_map[] = {
 50	{ P_CXO, 0 },
 51	{ P_PLL4, 2 }
 52};
 53
 54static const char * const lcc_cxo_pll4[] = {
 55	"cxo",
 56	"pll4_vote",
 57};
 58
 59static struct freq_tbl clk_tbl_aif_osr_492[] = {
 60	{   512000, P_PLL4, 4, 1, 240 },
 61	{   768000, P_PLL4, 4, 1, 160 },
 62	{  1024000, P_PLL4, 4, 1, 120 },
 63	{  1536000, P_PLL4, 4, 1,  80 },
 64	{  2048000, P_PLL4, 4, 1,  60 },
 65	{  3072000, P_PLL4, 4, 1,  40 },
 66	{  4096000, P_PLL4, 4, 1,  30 },
 67	{  6144000, P_PLL4, 4, 1,  20 },
 68	{  8192000, P_PLL4, 4, 1,  15 },
 69	{ 12288000, P_PLL4, 4, 1,  10 },
 70	{ 24576000, P_PLL4, 4, 1,   5 },
 71	{ 27000000, P_CXO,  1, 0,   0 },
 72	{ }
 73};
 74
 75static struct freq_tbl clk_tbl_aif_osr_393[] = {
 76	{   512000, P_PLL4, 4, 1, 192 },
 77	{   768000, P_PLL4, 4, 1, 128 },
 78	{  1024000, P_PLL4, 4, 1,  96 },
 79	{  1536000, P_PLL4, 4, 1,  64 },
 80	{  2048000, P_PLL4, 4, 1,  48 },
 81	{  3072000, P_PLL4, 4, 1,  32 },
 82	{  4096000, P_PLL4, 4, 1,  24 },
 83	{  6144000, P_PLL4, 4, 1,  16 },
 84	{  8192000, P_PLL4, 4, 1,  12 },
 85	{ 12288000, P_PLL4, 4, 1,   8 },
 86	{ 24576000, P_PLL4, 4, 1,   4 },
 87	{ 27000000, P_CXO,  1, 0,   0 },
 88	{ }
 89};
 90
 91static struct clk_rcg mi2s_osr_src = {
 92	.ns_reg = 0x48,
 93	.md_reg = 0x4c,
 94	.mn = {
 95		.mnctr_en_bit = 8,
 96		.mnctr_reset_bit = 7,
 97		.mnctr_mode_shift = 5,
 98		.n_val_shift = 24,
 99		.m_val_shift = 8,
100		.width = 8,
101	},
102	.p = {
103		.pre_div_shift = 3,
104		.pre_div_width = 2,
105	},
106	.s = {
107		.src_sel_shift = 0,
108		.parent_map = lcc_cxo_pll4_map,
109	},
110	.freq_tbl = clk_tbl_aif_osr_393,
111	.clkr = {
112		.enable_reg = 0x48,
113		.enable_mask = BIT(9),
114		.hw.init = &(struct clk_init_data){
115			.name = "mi2s_osr_src",
116			.parent_names = lcc_cxo_pll4,
117			.num_parents = 2,
118			.ops = &clk_rcg_ops,
119			.flags = CLK_SET_RATE_GATE,
120		},
121	},
122};
123
124static const char * const lcc_mi2s_parents[] = {
125	"mi2s_osr_src",
126};
127
128static struct clk_branch mi2s_osr_clk = {
129	.halt_reg = 0x50,
130	.halt_bit = 1,
131	.halt_check = BRANCH_HALT_ENABLE,
132	.clkr = {
133		.enable_reg = 0x48,
134		.enable_mask = BIT(17),
135		.hw.init = &(struct clk_init_data){
136			.name = "mi2s_osr_clk",
137			.parent_names = lcc_mi2s_parents,
138			.num_parents = 1,
139			.ops = &clk_branch_ops,
140			.flags = CLK_SET_RATE_PARENT,
141		},
142	},
143};
144
145static struct clk_regmap_div mi2s_div_clk = {
146	.reg = 0x48,
147	.shift = 10,
148	.width = 4,
149	.clkr = {
150		.enable_reg = 0x48,
151		.enable_mask = BIT(15),
152		.hw.init = &(struct clk_init_data){
153			.name = "mi2s_div_clk",
154			.parent_names = lcc_mi2s_parents,
155			.num_parents = 1,
156			.ops = &clk_regmap_div_ops,
157		},
158	},
159};
160
161static struct clk_branch mi2s_bit_div_clk = {
162	.halt_reg = 0x50,
163	.halt_bit = 0,
164	.halt_check = BRANCH_HALT_ENABLE,
165	.clkr = {
166		.enable_reg = 0x48,
167		.enable_mask = BIT(15),
168		.hw.init = &(struct clk_init_data){
169			.name = "mi2s_bit_div_clk",
170			.parent_names = (const char *[]){ "mi2s_div_clk" },
171			.num_parents = 1,
172			.ops = &clk_branch_ops,
173			.flags = CLK_SET_RATE_PARENT,
174		},
175	},
176};
177
178static struct clk_regmap_mux mi2s_bit_clk = {
179	.reg = 0x48,
180	.shift = 14,
181	.width = 1,
182	.clkr = {
183		.hw.init = &(struct clk_init_data){
184			.name = "mi2s_bit_clk",
185			.parent_names = (const char *[]){
186				"mi2s_bit_div_clk",
187				"mi2s_codec_clk",
188			},
189			.num_parents = 2,
190			.ops = &clk_regmap_mux_closest_ops,
191			.flags = CLK_SET_RATE_PARENT,
192		},
193	},
194};
195
196#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr)			\
197static struct clk_rcg prefix##_osr_src = {			\
198	.ns_reg = _ns,						\
199	.md_reg = _md,						\
200	.mn = {							\
201		.mnctr_en_bit = 8,				\
202		.mnctr_reset_bit = 7,				\
203		.mnctr_mode_shift = 5,				\
204		.n_val_shift = 24,				\
205		.m_val_shift = 8,				\
206		.width = 8,					\
207	},							\
208	.p = {							\
209		.pre_div_shift = 3,				\
210		.pre_div_width = 2,				\
211	},							\
212	.s = {							\
213		.src_sel_shift = 0,				\
214		.parent_map = lcc_cxo_pll4_map,			\
215	},							\
216	.freq_tbl = clk_tbl_aif_osr_393,			\
217	.clkr = {						\
218		.enable_reg = _ns,				\
219		.enable_mask = BIT(9),				\
220		.hw.init = &(struct clk_init_data){		\
221			.name = #prefix "_osr_src",		\
222			.parent_names = lcc_cxo_pll4,		\
223			.num_parents = 2,			\
224			.ops = &clk_rcg_ops,			\
225			.flags = CLK_SET_RATE_GATE,		\
226		},						\
227	},							\
228};								\
229								\
230static const char * const lcc_##prefix##_parents[] = {		\
231	#prefix "_osr_src",					\
232};								\
233								\
234static struct clk_branch prefix##_osr_clk = {			\
235	.halt_reg = hr,						\
236	.halt_bit = 1,						\
237	.halt_check = BRANCH_HALT_ENABLE,			\
238	.clkr = {						\
239		.enable_reg = _ns,				\
240		.enable_mask = BIT(21),				\
241		.hw.init = &(struct clk_init_data){		\
242			.name = #prefix "_osr_clk",		\
243			.parent_names = lcc_##prefix##_parents,	\
244			.num_parents = 1,			\
245			.ops = &clk_branch_ops,			\
246			.flags = CLK_SET_RATE_PARENT,		\
247		},						\
248	},							\
249};								\
250								\
251static struct clk_regmap_div prefix##_div_clk = {		\
252	.reg = _ns,						\
253	.shift = 10,						\
254	.width = 8,						\
255	.clkr = {						\
256		.hw.init = &(struct clk_init_data){		\
257			.name = #prefix "_div_clk",		\
258			.parent_names = lcc_##prefix##_parents,	\
259			.num_parents = 1,			\
260			.ops = &clk_regmap_div_ops,		\
261		},						\
262	},							\
263};								\
264								\
265static struct clk_branch prefix##_bit_div_clk = {		\
266	.halt_reg = hr,						\
267	.halt_bit = 0,						\
268	.halt_check = BRANCH_HALT_ENABLE,			\
269	.clkr = {						\
270		.enable_reg = _ns,				\
271		.enable_mask = BIT(19),				\
272		.hw.init = &(struct clk_init_data){		\
273			.name = #prefix "_bit_div_clk",		\
274			.parent_names = (const char *[]){	\
275				#prefix "_div_clk"		\
276			},					\
277			.num_parents = 1,			\
278			.ops = &clk_branch_ops,			\
279			.flags = CLK_SET_RATE_PARENT,		\
280		},						\
281	},							\
282};								\
283								\
284static struct clk_regmap_mux prefix##_bit_clk = {		\
285	.reg = _ns,						\
286	.shift = 18,						\
287	.width = 1,						\
288	.clkr = {						\
289		.hw.init = &(struct clk_init_data){		\
290			.name = #prefix "_bit_clk",		\
291			.parent_names = (const char *[]){	\
292				#prefix "_bit_div_clk",		\
293				#prefix "_codec_clk",		\
294			},					\
295			.num_parents = 2,			\
296			.ops = &clk_regmap_mux_closest_ops,	\
297			.flags = CLK_SET_RATE_PARENT,		\
298		},						\
299	},							\
300}
301
302CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68);
303CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80);
304CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74);
305CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c);
306
307static struct freq_tbl clk_tbl_pcm_492[] = {
308	{   256000, P_PLL4, 4, 1, 480 },
309	{   512000, P_PLL4, 4, 1, 240 },
310	{   768000, P_PLL4, 4, 1, 160 },
311	{  1024000, P_PLL4, 4, 1, 120 },
312	{  1536000, P_PLL4, 4, 1,  80 },
313	{  2048000, P_PLL4, 4, 1,  60 },
314	{  3072000, P_PLL4, 4, 1,  40 },
315	{  4096000, P_PLL4, 4, 1,  30 },
316	{  6144000, P_PLL4, 4, 1,  20 },
317	{  8192000, P_PLL4, 4, 1,  15 },
318	{ 12288000, P_PLL4, 4, 1,  10 },
319	{ 24576000, P_PLL4, 4, 1,   5 },
320	{ 27000000, P_CXO,  1, 0,   0 },
321	{ }
322};
323
324static struct freq_tbl clk_tbl_pcm_393[] = {
325	{   256000, P_PLL4, 4, 1, 384 },
326	{   512000, P_PLL4, 4, 1, 192 },
327	{   768000, P_PLL4, 4, 1, 128 },
328	{  1024000, P_PLL4, 4, 1,  96 },
329	{  1536000, P_PLL4, 4, 1,  64 },
330	{  2048000, P_PLL4, 4, 1,  48 },
331	{  3072000, P_PLL4, 4, 1,  32 },
332	{  4096000, P_PLL4, 4, 1,  24 },
333	{  6144000, P_PLL4, 4, 1,  16 },
334	{  8192000, P_PLL4, 4, 1,  12 },
335	{ 12288000, P_PLL4, 4, 1,   8 },
336	{ 24576000, P_PLL4, 4, 1,   4 },
337	{ 27000000, P_CXO,  1, 0,   0 },
338	{ }
339};
340
341static struct clk_rcg pcm_src = {
342	.ns_reg = 0x54,
343	.md_reg = 0x58,
344	.mn = {
345		.mnctr_en_bit = 8,
346		.mnctr_reset_bit = 7,
347		.mnctr_mode_shift = 5,
348		.n_val_shift = 16,
349		.m_val_shift = 16,
350		.width = 16,
351	},
352	.p = {
353		.pre_div_shift = 3,
354		.pre_div_width = 2,
355	},
356	.s = {
357		.src_sel_shift = 0,
358		.parent_map = lcc_cxo_pll4_map,
359	},
360	.freq_tbl = clk_tbl_pcm_393,
361	.clkr = {
362		.enable_reg = 0x54,
363		.enable_mask = BIT(9),
364		.hw.init = &(struct clk_init_data){
365			.name = "pcm_src",
366			.parent_names = lcc_cxo_pll4,
367			.num_parents = 2,
368			.ops = &clk_rcg_ops,
369			.flags = CLK_SET_RATE_GATE,
370		},
371	},
372};
373
374static struct clk_branch pcm_clk_out = {
375	.halt_reg = 0x5c,
376	.halt_bit = 0,
377	.halt_check = BRANCH_HALT_ENABLE,
378	.clkr = {
379		.enable_reg = 0x54,
380		.enable_mask = BIT(11),
381		.hw.init = &(struct clk_init_data){
382			.name = "pcm_clk_out",
383			.parent_names = (const char *[]){ "pcm_src" },
384			.num_parents = 1,
385			.ops = &clk_branch_ops,
386			.flags = CLK_SET_RATE_PARENT,
387		},
388	},
389};
390
391static struct clk_regmap_mux pcm_clk = {
392	.reg = 0x54,
393	.shift = 10,
394	.width = 1,
395	.clkr = {
396		.hw.init = &(struct clk_init_data){
397			.name = "pcm_clk",
398			.parent_names = (const char *[]){
399				"pcm_clk_out",
400				"pcm_codec_clk",
401			},
402			.num_parents = 2,
403			.ops = &clk_regmap_mux_closest_ops,
404			.flags = CLK_SET_RATE_PARENT,
405		},
406	},
407};
408
409static struct clk_rcg slimbus_src = {
410	.ns_reg = 0xcc,
411	.md_reg = 0xd0,
412	.mn = {
413		.mnctr_en_bit = 8,
414		.mnctr_reset_bit = 7,
415		.mnctr_mode_shift = 5,
416		.n_val_shift = 24,
417		.m_val_shift = 8,
418		.width = 8,
419	},
420	.p = {
421		.pre_div_shift = 3,
422		.pre_div_width = 2,
423	},
424	.s = {
425		.src_sel_shift = 0,
426		.parent_map = lcc_cxo_pll4_map,
427	},
428	.freq_tbl = clk_tbl_aif_osr_393,
429	.clkr = {
430		.enable_reg = 0xcc,
431		.enable_mask = BIT(9),
432		.hw.init = &(struct clk_init_data){
433			.name = "slimbus_src",
434			.parent_names = lcc_cxo_pll4,
435			.num_parents = 2,
436			.ops = &clk_rcg_ops,
437			.flags = CLK_SET_RATE_GATE,
438		},
439	},
440};
441
442static const char * const lcc_slimbus_parents[] = {
443	"slimbus_src",
444};
445
446static struct clk_branch audio_slimbus_clk = {
447	.halt_reg = 0xd4,
448	.halt_bit = 0,
449	.halt_check = BRANCH_HALT_ENABLE,
450	.clkr = {
451		.enable_reg = 0xcc,
452		.enable_mask = BIT(10),
453		.hw.init = &(struct clk_init_data){
454			.name = "audio_slimbus_clk",
455			.parent_names = lcc_slimbus_parents,
456			.num_parents = 1,
457			.ops = &clk_branch_ops,
458			.flags = CLK_SET_RATE_PARENT,
459		},
460	},
461};
462
463static struct clk_branch sps_slimbus_clk = {
464	.halt_reg = 0xd4,
465	.halt_bit = 1,
466	.halt_check = BRANCH_HALT_ENABLE,
467	.clkr = {
468		.enable_reg = 0xcc,
469		.enable_mask = BIT(12),
470		.hw.init = &(struct clk_init_data){
471			.name = "sps_slimbus_clk",
472			.parent_names = lcc_slimbus_parents,
473			.num_parents = 1,
474			.ops = &clk_branch_ops,
475			.flags = CLK_SET_RATE_PARENT,
476		},
477	},
478};
479
480static struct clk_regmap *lcc_mdm9615_clks[] = {
481	[PLL4] = &pll4.clkr,
482	[MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
483	[MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
484	[MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
485	[MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
486	[MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
487	[PCM_SRC] = &pcm_src.clkr,
488	[PCM_CLK_OUT] = &pcm_clk_out.clkr,
489	[PCM_CLK] = &pcm_clk.clkr,
490	[SLIMBUS_SRC] = &slimbus_src.clkr,
491	[AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr,
492	[SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr,
493	[CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr,
494	[CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr,
495	[CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr,
496	[CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr,
497	[CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr,
498	[SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr,
499	[SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr,
500	[SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr,
501	[SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr,
502	[SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr,
503	[CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr,
504	[CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr,
505	[CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr,
506	[CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr,
507	[CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr,
508	[SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr,
509	[SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr,
510	[SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr,
511	[SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr,
512	[SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr,
513};
514
515static const struct regmap_config lcc_mdm9615_regmap_config = {
516	.reg_bits	= 32,
517	.reg_stride	= 4,
518	.val_bits	= 32,
519	.max_register	= 0xfc,
520	.fast_io	= true,
521};
522
523static const struct qcom_cc_desc lcc_mdm9615_desc = {
524	.config = &lcc_mdm9615_regmap_config,
525	.clks = lcc_mdm9615_clks,
526	.num_clks = ARRAY_SIZE(lcc_mdm9615_clks),
527};
528
529static const struct of_device_id lcc_mdm9615_match_table[] = {
530	{ .compatible = "qcom,lcc-mdm9615" },
531	{ }
532};
533MODULE_DEVICE_TABLE(of, lcc_mdm9615_match_table);
534
535static int lcc_mdm9615_probe(struct platform_device *pdev)
536{
537	u32 val;
538	struct regmap *regmap;
539
540	regmap = qcom_cc_map(pdev, &lcc_mdm9615_desc);
541	if (IS_ERR(regmap))
542		return PTR_ERR(regmap);
543
544	/* Use the correct frequency plan depending on speed of PLL4 */
545	regmap_read(regmap, 0x4, &val);
546	if (val == 0x12) {
547		slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
548		mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
549		codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
550		spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
551		codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
552		spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
553		pcm_src.freq_tbl = clk_tbl_pcm_492;
554	}
555	/* Enable PLL4 source on the LPASS Primary PLL Mux */
556	regmap_write(regmap, 0xc4, 0x1);
557
558	return qcom_cc_really_probe(pdev, &lcc_mdm9615_desc, regmap);
559}
560
561static struct platform_driver lcc_mdm9615_driver = {
562	.probe		= lcc_mdm9615_probe,
563	.driver		= {
564		.name	= "lcc-mdm9615",
565		.of_match_table = lcc_mdm9615_match_table,
566	},
567};
568module_platform_driver(lcc_mdm9615_driver);
569
570MODULE_DESCRIPTION("QCOM LCC MDM9615 Driver");
571MODULE_LICENSE("GPL v2");
572MODULE_ALIAS("platform:lcc-mdm9615");