xref: /openbmc/linux/drivers/clk/qcom/lcc-msm8960.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b82875eeSStephen Boyd /*
3b82875eeSStephen Boyd  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
4b82875eeSStephen Boyd  */
5b82875eeSStephen Boyd 
6b82875eeSStephen Boyd #include <linux/kernel.h>
7b82875eeSStephen Boyd #include <linux/bitops.h>
8b82875eeSStephen Boyd #include <linux/err.h>
9b82875eeSStephen Boyd #include <linux/platform_device.h>
10b82875eeSStephen Boyd #include <linux/module.h>
11b82875eeSStephen Boyd #include <linux/of.h>
12b82875eeSStephen Boyd #include <linux/clk-provider.h>
13b82875eeSStephen Boyd #include <linux/regmap.h>
14b82875eeSStephen Boyd 
15b82875eeSStephen Boyd #include <dt-bindings/clock/qcom,lcc-msm8960.h>
16b82875eeSStephen Boyd 
17b82875eeSStephen Boyd #include "common.h"
18b82875eeSStephen Boyd #include "clk-regmap.h"
19b82875eeSStephen Boyd #include "clk-pll.h"
20b82875eeSStephen Boyd #include "clk-rcg.h"
21b82875eeSStephen Boyd #include "clk-branch.h"
22b82875eeSStephen Boyd #include "clk-regmap-divider.h"
23b82875eeSStephen Boyd #include "clk-regmap-mux.h"
24b82875eeSStephen Boyd 
25*e39d0fa7SYang Yingliang static struct clk_parent_data pxo_parent_data = {
26bac4675aSDmitry Baryshkov 	.fw_name = "pxo", .name = "pxo_board",
27bac4675aSDmitry Baryshkov };
28bac4675aSDmitry Baryshkov 
29b82875eeSStephen Boyd static struct clk_pll pll4 = {
30b82875eeSStephen Boyd 	.l_reg = 0x4,
31b82875eeSStephen Boyd 	.m_reg = 0x8,
32b82875eeSStephen Boyd 	.n_reg = 0xc,
33b82875eeSStephen Boyd 	.config_reg = 0x14,
34b82875eeSStephen Boyd 	.mode_reg = 0x0,
35b82875eeSStephen Boyd 	.status_reg = 0x18,
36b82875eeSStephen Boyd 	.status_bit = 16,
37b82875eeSStephen Boyd 	.clkr.hw.init = &(struct clk_init_data){
38b82875eeSStephen Boyd 		.name = "pll4",
39bac4675aSDmitry Baryshkov 		.parent_data = &pxo_parent_data,
40b82875eeSStephen Boyd 		.num_parents = 1,
41b82875eeSStephen Boyd 		.ops = &clk_pll_ops,
42b82875eeSStephen Boyd 	},
43b82875eeSStephen Boyd };
44b82875eeSStephen Boyd 
45293d2e97SGeorgi Djakov enum {
46293d2e97SGeorgi Djakov 	P_PXO,
47293d2e97SGeorgi Djakov 	P_PLL4,
48293d2e97SGeorgi Djakov };
49b82875eeSStephen Boyd 
50293d2e97SGeorgi Djakov static const struct parent_map lcc_pxo_pll4_map[] = {
51293d2e97SGeorgi Djakov 	{ P_PXO, 0 },
52293d2e97SGeorgi Djakov 	{ P_PLL4, 2 }
53b82875eeSStephen Boyd };
54b82875eeSStephen Boyd 
55bac4675aSDmitry Baryshkov static struct clk_parent_data lcc_pxo_pll4[] = {
56a6976f85SDmitry Baryshkov 	{ .fw_name = "pxo", .name = "pxo_board" },
57a6976f85SDmitry Baryshkov 	{ .fw_name = "pll4_vote", .name = "pll4_vote" },
58b82875eeSStephen Boyd };
59b82875eeSStephen Boyd 
60b82875eeSStephen Boyd static struct freq_tbl clk_tbl_aif_osr_492[] = {
61b82875eeSStephen Boyd 	{   512000, P_PLL4, 4, 1, 240 },
62b82875eeSStephen Boyd 	{   768000, P_PLL4, 4, 1, 160 },
63b82875eeSStephen Boyd 	{  1024000, P_PLL4, 4, 1, 120 },
64b82875eeSStephen Boyd 	{  1536000, P_PLL4, 4, 1,  80 },
65b82875eeSStephen Boyd 	{  2048000, P_PLL4, 4, 1,  60 },
66b82875eeSStephen Boyd 	{  3072000, P_PLL4, 4, 1,  40 },
67b82875eeSStephen Boyd 	{  4096000, P_PLL4, 4, 1,  30 },
68b82875eeSStephen Boyd 	{  6144000, P_PLL4, 4, 1,  20 },
69b82875eeSStephen Boyd 	{  8192000, P_PLL4, 4, 1,  15 },
70b82875eeSStephen Boyd 	{ 12288000, P_PLL4, 4, 1,  10 },
71b82875eeSStephen Boyd 	{ 24576000, P_PLL4, 4, 1,   5 },
72b82875eeSStephen Boyd 	{ 27000000, P_PXO,  1, 0,   0 },
73b82875eeSStephen Boyd 	{ }
74b82875eeSStephen Boyd };
75b82875eeSStephen Boyd 
76b82875eeSStephen Boyd static struct freq_tbl clk_tbl_aif_osr_393[] = {
77b82875eeSStephen Boyd 	{   512000, P_PLL4, 4, 1, 192 },
78b82875eeSStephen Boyd 	{   768000, P_PLL4, 4, 1, 128 },
79b82875eeSStephen Boyd 	{  1024000, P_PLL4, 4, 1,  96 },
80b82875eeSStephen Boyd 	{  1536000, P_PLL4, 4, 1,  64 },
81b82875eeSStephen Boyd 	{  2048000, P_PLL4, 4, 1,  48 },
82b82875eeSStephen Boyd 	{  3072000, P_PLL4, 4, 1,  32 },
83b82875eeSStephen Boyd 	{  4096000, P_PLL4, 4, 1,  24 },
84b82875eeSStephen Boyd 	{  6144000, P_PLL4, 4, 1,  16 },
85b82875eeSStephen Boyd 	{  8192000, P_PLL4, 4, 1,  12 },
86b82875eeSStephen Boyd 	{ 12288000, P_PLL4, 4, 1,   8 },
87b82875eeSStephen Boyd 	{ 24576000, P_PLL4, 4, 1,   4 },
88b82875eeSStephen Boyd 	{ 27000000, P_PXO,  1, 0,   0 },
89b82875eeSStephen Boyd 	{ }
90b82875eeSStephen Boyd };
91b82875eeSStephen Boyd 
927026af10SDmitry Baryshkov #define CLK_AIF_OSR_SRC(prefix, _ns, _md)			\
93b82875eeSStephen Boyd static struct clk_rcg prefix##_osr_src = {			\
94b82875eeSStephen Boyd 	.ns_reg = _ns,						\
95b82875eeSStephen Boyd 	.md_reg = _md,						\
96b82875eeSStephen Boyd 	.mn = {							\
97b82875eeSStephen Boyd 		.mnctr_en_bit = 8,				\
98b82875eeSStephen Boyd 		.mnctr_reset_bit = 7,				\
99b82875eeSStephen Boyd 		.mnctr_mode_shift = 5,				\
100b82875eeSStephen Boyd 		.n_val_shift = 24,				\
101b82875eeSStephen Boyd 		.m_val_shift = 8,				\
102b82875eeSStephen Boyd 		.width = 8,					\
103b82875eeSStephen Boyd 	},							\
104b82875eeSStephen Boyd 	.p = {							\
105b82875eeSStephen Boyd 		.pre_div_shift = 3,				\
106b82875eeSStephen Boyd 		.pre_div_width = 2,				\
107b82875eeSStephen Boyd 	},							\
108b82875eeSStephen Boyd 	.s = {							\
109b82875eeSStephen Boyd 		.src_sel_shift = 0,				\
110b82875eeSStephen Boyd 		.parent_map = lcc_pxo_pll4_map,			\
111b82875eeSStephen Boyd 	},							\
112b82875eeSStephen Boyd 	.freq_tbl = clk_tbl_aif_osr_393,			\
113b82875eeSStephen Boyd 	.clkr = {						\
114b82875eeSStephen Boyd 		.enable_reg = _ns,				\
115b82875eeSStephen Boyd 		.enable_mask = BIT(9),				\
116b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){		\
117b82875eeSStephen Boyd 			.name = #prefix "_osr_src",		\
118a6976f85SDmitry Baryshkov 			.parent_data = lcc_pxo_pll4,		\
119a6976f85SDmitry Baryshkov 			.num_parents = ARRAY_SIZE(lcc_pxo_pll4), \
120b82875eeSStephen Boyd 			.ops = &clk_rcg_ops,			\
121b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_GATE,		\
122b82875eeSStephen Boyd 		},						\
123b82875eeSStephen Boyd 	},							\
124b82875eeSStephen Boyd };								\
1257026af10SDmitry Baryshkov 
1267026af10SDmitry Baryshkov #define CLK_AIF_OSR_CLK(prefix, _ns, hr, en_bit)		\
127b82875eeSStephen Boyd static struct clk_branch prefix##_osr_clk = {			\
128b82875eeSStephen Boyd 	.halt_reg = hr,						\
129b82875eeSStephen Boyd 	.halt_bit = 1,						\
130b82875eeSStephen Boyd 	.halt_check = BRANCH_HALT_ENABLE,			\
131b82875eeSStephen Boyd 	.clkr = {						\
132b82875eeSStephen Boyd 		.enable_reg = _ns,				\
1337026af10SDmitry Baryshkov 		.enable_mask = BIT(en_bit),			\
134b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){		\
135b82875eeSStephen Boyd 			.name = #prefix "_osr_clk",		\
136a6976f85SDmitry Baryshkov 			.parent_hws = (const struct clk_hw*[]){	\
137a6976f85SDmitry Baryshkov 				&prefix##_osr_src.clkr.hw,	\
138a6976f85SDmitry Baryshkov 			},					\
139b82875eeSStephen Boyd 			.num_parents = 1,			\
140b82875eeSStephen Boyd 			.ops = &clk_branch_ops,			\
141b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_PARENT,		\
142b82875eeSStephen Boyd 		},						\
143b82875eeSStephen Boyd 	},							\
144b82875eeSStephen Boyd };								\
1457026af10SDmitry Baryshkov 
1467026af10SDmitry Baryshkov #define CLK_AIF_OSR_DIV_CLK(prefix, _ns, _width)		\
147b82875eeSStephen Boyd static struct clk_regmap_div prefix##_div_clk = {		\
148b82875eeSStephen Boyd 	.reg = _ns,						\
149b82875eeSStephen Boyd 	.shift = 10,						\
1507026af10SDmitry Baryshkov 	.width = _width,					\
151b82875eeSStephen Boyd 	.clkr = {						\
152b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){		\
153b82875eeSStephen Boyd 			.name = #prefix "_div_clk",		\
154a6976f85SDmitry Baryshkov 			.parent_hws = (const struct clk_hw*[]){	\
155a6976f85SDmitry Baryshkov 				&prefix##_osr_src.clkr.hw,	\
156a6976f85SDmitry Baryshkov 			},					\
157b82875eeSStephen Boyd 			.num_parents = 1,			\
158b82875eeSStephen Boyd 			.ops = &clk_regmap_div_ops,		\
159b82875eeSStephen Boyd 		},						\
160b82875eeSStephen Boyd 	},							\
161b82875eeSStephen Boyd };								\
1627026af10SDmitry Baryshkov 
1637026af10SDmitry Baryshkov #define CLK_AIF_OSR_BIT_DIV_CLK(prefix, _ns, hr, en_bit)	\
164b82875eeSStephen Boyd static struct clk_branch prefix##_bit_div_clk = {		\
165b82875eeSStephen Boyd 	.halt_reg = hr,						\
166b82875eeSStephen Boyd 	.halt_bit = 0,						\
167b82875eeSStephen Boyd 	.halt_check = BRANCH_HALT_ENABLE,			\
168b82875eeSStephen Boyd 	.clkr = {						\
169b82875eeSStephen Boyd 		.enable_reg = _ns,				\
1707026af10SDmitry Baryshkov 		.enable_mask = BIT(en_bit),			\
171b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){		\
172b82875eeSStephen Boyd 			.name = #prefix "_bit_div_clk",		\
173a6976f85SDmitry Baryshkov 			.parent_hws = (const struct clk_hw*[]){	\
174a6976f85SDmitry Baryshkov 				&prefix##_div_clk.clkr.hw,	\
175b82875eeSStephen Boyd 			},					\
176b82875eeSStephen Boyd 			.num_parents = 1,			\
177b82875eeSStephen Boyd 			.ops = &clk_branch_ops,			\
178b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_PARENT,		\
179b82875eeSStephen Boyd 		},						\
180b82875eeSStephen Boyd 	},							\
181b82875eeSStephen Boyd };								\
1827026af10SDmitry Baryshkov 
1837026af10SDmitry Baryshkov #define CLK_AIF_OSR_BIT_CLK(prefix, _ns, _shift)		\
184b82875eeSStephen Boyd static struct clk_regmap_mux prefix##_bit_clk = {		\
185b82875eeSStephen Boyd 	.reg = _ns,						\
1867026af10SDmitry Baryshkov 	.shift = _shift,					\
187b82875eeSStephen Boyd 	.width = 1,						\
188b82875eeSStephen Boyd 	.clkr = {						\
189b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){		\
190b82875eeSStephen Boyd 			.name = #prefix "_bit_clk",		\
191a6976f85SDmitry Baryshkov 			.parent_data = (const struct clk_parent_data[]){ \
192a6976f85SDmitry Baryshkov 				{ .hw = &prefix##_bit_div_clk.clkr.hw, }, \
193a6976f85SDmitry Baryshkov 				{ .fw_name = #prefix "_codec_clk", \
194a6976f85SDmitry Baryshkov 				  .name = #prefix "_codec_clk", }, \
195b82875eeSStephen Boyd 			},					\
196b82875eeSStephen Boyd 			.num_parents = 2,			\
197b82875eeSStephen Boyd 			.ops = &clk_regmap_mux_closest_ops,	\
198b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_PARENT,		\
199b82875eeSStephen Boyd 		},						\
200b82875eeSStephen Boyd 	},							\
2017026af10SDmitry Baryshkov };
2027026af10SDmitry Baryshkov 
2037026af10SDmitry Baryshkov CLK_AIF_OSR_SRC(mi2s, 0x48, 0x4c)
2047026af10SDmitry Baryshkov CLK_AIF_OSR_CLK(mi2s, 0x48, 0x50, 17)
2057026af10SDmitry Baryshkov CLK_AIF_OSR_DIV_CLK(mi2s, 0x48, 4)
2067026af10SDmitry Baryshkov CLK_AIF_OSR_BIT_DIV_CLK(mi2s, 0x48, 0x50, 15)
2077026af10SDmitry Baryshkov CLK_AIF_OSR_BIT_CLK(mi2s, 0x48, 14)
2087026af10SDmitry Baryshkov 
2097026af10SDmitry Baryshkov #define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr)			\
2107026af10SDmitry Baryshkov 	CLK_AIF_OSR_SRC(prefix, _ns, _md)			\
2117026af10SDmitry Baryshkov 	CLK_AIF_OSR_CLK(prefix, _ns, hr, 21)			\
2127026af10SDmitry Baryshkov 	CLK_AIF_OSR_DIV_CLK(prefix, _ns, 8)			\
2137026af10SDmitry Baryshkov 	CLK_AIF_OSR_BIT_DIV_CLK(prefix, _ns, hr, 19)		\
2147026af10SDmitry Baryshkov 	CLK_AIF_OSR_BIT_CLK(prefix, _ns, 18)
215b82875eeSStephen Boyd 
216b82875eeSStephen Boyd CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68);
217b82875eeSStephen Boyd CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80);
218b82875eeSStephen Boyd CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74);
219b82875eeSStephen Boyd CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c);
220b82875eeSStephen Boyd 
221b82875eeSStephen Boyd static struct freq_tbl clk_tbl_pcm_492[] = {
222b82875eeSStephen Boyd 	{   256000, P_PLL4, 4, 1, 480 },
223b82875eeSStephen Boyd 	{   512000, P_PLL4, 4, 1, 240 },
224b82875eeSStephen Boyd 	{   768000, P_PLL4, 4, 1, 160 },
225b82875eeSStephen Boyd 	{  1024000, P_PLL4, 4, 1, 120 },
226b82875eeSStephen Boyd 	{  1536000, P_PLL4, 4, 1,  80 },
227b82875eeSStephen Boyd 	{  2048000, P_PLL4, 4, 1,  60 },
228b82875eeSStephen Boyd 	{  3072000, P_PLL4, 4, 1,  40 },
229b82875eeSStephen Boyd 	{  4096000, P_PLL4, 4, 1,  30 },
230b82875eeSStephen Boyd 	{  6144000, P_PLL4, 4, 1,  20 },
231b82875eeSStephen Boyd 	{  8192000, P_PLL4, 4, 1,  15 },
232b82875eeSStephen Boyd 	{ 12288000, P_PLL4, 4, 1,  10 },
233b82875eeSStephen Boyd 	{ 24576000, P_PLL4, 4, 1,   5 },
234b82875eeSStephen Boyd 	{ 27000000, P_PXO,  1, 0,   0 },
235b82875eeSStephen Boyd 	{ }
236b82875eeSStephen Boyd };
237b82875eeSStephen Boyd 
238b82875eeSStephen Boyd static struct freq_tbl clk_tbl_pcm_393[] = {
239b82875eeSStephen Boyd 	{   256000, P_PLL4, 4, 1, 384 },
240b82875eeSStephen Boyd 	{   512000, P_PLL4, 4, 1, 192 },
241b82875eeSStephen Boyd 	{   768000, P_PLL4, 4, 1, 128 },
242b82875eeSStephen Boyd 	{  1024000, P_PLL4, 4, 1,  96 },
243b82875eeSStephen Boyd 	{  1536000, P_PLL4, 4, 1,  64 },
244b82875eeSStephen Boyd 	{  2048000, P_PLL4, 4, 1,  48 },
245b82875eeSStephen Boyd 	{  3072000, P_PLL4, 4, 1,  32 },
246b82875eeSStephen Boyd 	{  4096000, P_PLL4, 4, 1,  24 },
247b82875eeSStephen Boyd 	{  6144000, P_PLL4, 4, 1,  16 },
248b82875eeSStephen Boyd 	{  8192000, P_PLL4, 4, 1,  12 },
249b82875eeSStephen Boyd 	{ 12288000, P_PLL4, 4, 1,   8 },
250b82875eeSStephen Boyd 	{ 24576000, P_PLL4, 4, 1,   4 },
251b82875eeSStephen Boyd 	{ 27000000, P_PXO,  1, 0,   0 },
252b82875eeSStephen Boyd 	{ }
253b82875eeSStephen Boyd };
254b82875eeSStephen Boyd 
255b82875eeSStephen Boyd static struct clk_rcg pcm_src = {
256b82875eeSStephen Boyd 	.ns_reg = 0x54,
257b82875eeSStephen Boyd 	.md_reg = 0x58,
258b82875eeSStephen Boyd 	.mn = {
259b82875eeSStephen Boyd 		.mnctr_en_bit = 8,
260b82875eeSStephen Boyd 		.mnctr_reset_bit = 7,
261b82875eeSStephen Boyd 		.mnctr_mode_shift = 5,
262b82875eeSStephen Boyd 		.n_val_shift = 16,
263b82875eeSStephen Boyd 		.m_val_shift = 16,
264b82875eeSStephen Boyd 		.width = 16,
265b82875eeSStephen Boyd 	},
266b82875eeSStephen Boyd 	.p = {
267b82875eeSStephen Boyd 		.pre_div_shift = 3,
268b82875eeSStephen Boyd 		.pre_div_width = 2,
269b82875eeSStephen Boyd 	},
270b82875eeSStephen Boyd 	.s = {
271b82875eeSStephen Boyd 		.src_sel_shift = 0,
272b82875eeSStephen Boyd 		.parent_map = lcc_pxo_pll4_map,
273b82875eeSStephen Boyd 	},
274b82875eeSStephen Boyd 	.freq_tbl = clk_tbl_pcm_393,
275b82875eeSStephen Boyd 	.clkr = {
276b82875eeSStephen Boyd 		.enable_reg = 0x54,
277b82875eeSStephen Boyd 		.enable_mask = BIT(9),
278b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){
279b82875eeSStephen Boyd 			.name = "pcm_src",
280a6976f85SDmitry Baryshkov 			.parent_data = lcc_pxo_pll4,
281a6976f85SDmitry Baryshkov 			.num_parents = ARRAY_SIZE(lcc_pxo_pll4),
282b82875eeSStephen Boyd 			.ops = &clk_rcg_ops,
283b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_GATE,
284b82875eeSStephen Boyd 		},
285b82875eeSStephen Boyd 	},
286b82875eeSStephen Boyd };
287b82875eeSStephen Boyd 
288b82875eeSStephen Boyd static struct clk_branch pcm_clk_out = {
289b82875eeSStephen Boyd 	.halt_reg = 0x5c,
290b82875eeSStephen Boyd 	.halt_bit = 0,
291b82875eeSStephen Boyd 	.halt_check = BRANCH_HALT_ENABLE,
292b82875eeSStephen Boyd 	.clkr = {
293b82875eeSStephen Boyd 		.enable_reg = 0x54,
294b82875eeSStephen Boyd 		.enable_mask = BIT(11),
295b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){
296b82875eeSStephen Boyd 			.name = "pcm_clk_out",
297a6976f85SDmitry Baryshkov 			.parent_hws = (const struct clk_hw*[]){
298a6976f85SDmitry Baryshkov 				&pcm_src.clkr.hw
299a6976f85SDmitry Baryshkov 			},
300b82875eeSStephen Boyd 			.num_parents = 1,
301b82875eeSStephen Boyd 			.ops = &clk_branch_ops,
302b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_PARENT,
303b82875eeSStephen Boyd 		},
304b82875eeSStephen Boyd 	},
305b82875eeSStephen Boyd };
306b82875eeSStephen Boyd 
307b82875eeSStephen Boyd static struct clk_regmap_mux pcm_clk = {
308b82875eeSStephen Boyd 	.reg = 0x54,
309b82875eeSStephen Boyd 	.shift = 10,
310b82875eeSStephen Boyd 	.width = 1,
311b82875eeSStephen Boyd 	.clkr = {
312b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){
313b82875eeSStephen Boyd 			.name = "pcm_clk",
314a6976f85SDmitry Baryshkov 			.parent_data = (const struct clk_parent_data[]){
315a6976f85SDmitry Baryshkov 				{ .hw = &pcm_clk_out.clkr.hw },
316a6976f85SDmitry Baryshkov 				{ .fw_name = "pcm_codec_clk", .name = "pcm_codec_clk" },
317b82875eeSStephen Boyd 			},
318b82875eeSStephen Boyd 			.num_parents = 2,
319b82875eeSStephen Boyd 			.ops = &clk_regmap_mux_closest_ops,
320b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_PARENT,
321b82875eeSStephen Boyd 		},
322b82875eeSStephen Boyd 	},
323b82875eeSStephen Boyd };
324b82875eeSStephen Boyd 
325b82875eeSStephen Boyd static struct clk_rcg slimbus_src = {
326b82875eeSStephen Boyd 	.ns_reg = 0xcc,
327b82875eeSStephen Boyd 	.md_reg = 0xd0,
328b82875eeSStephen Boyd 	.mn = {
329b82875eeSStephen Boyd 		.mnctr_en_bit = 8,
330b82875eeSStephen Boyd 		.mnctr_reset_bit = 7,
331b82875eeSStephen Boyd 		.mnctr_mode_shift = 5,
3327dd47b8eSStephen Boyd 		.n_val_shift = 24,
3337dd47b8eSStephen Boyd 		.m_val_shift = 8,
334b82875eeSStephen Boyd 		.width = 8,
335b82875eeSStephen Boyd 	},
336b82875eeSStephen Boyd 	.p = {
337b82875eeSStephen Boyd 		.pre_div_shift = 3,
338b82875eeSStephen Boyd 		.pre_div_width = 2,
339b82875eeSStephen Boyd 	},
340b82875eeSStephen Boyd 	.s = {
341b82875eeSStephen Boyd 		.src_sel_shift = 0,
342b82875eeSStephen Boyd 		.parent_map = lcc_pxo_pll4_map,
343b82875eeSStephen Boyd 	},
344b82875eeSStephen Boyd 	.freq_tbl = clk_tbl_aif_osr_393,
345b82875eeSStephen Boyd 	.clkr = {
346b82875eeSStephen Boyd 		.enable_reg = 0xcc,
347b82875eeSStephen Boyd 		.enable_mask = BIT(9),
348b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){
349b82875eeSStephen Boyd 			.name = "slimbus_src",
350a6976f85SDmitry Baryshkov 			.parent_data = lcc_pxo_pll4,
351a6976f85SDmitry Baryshkov 			.num_parents = ARRAY_SIZE(lcc_pxo_pll4),
352b82875eeSStephen Boyd 			.ops = &clk_rcg_ops,
353b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_GATE,
354b82875eeSStephen Boyd 		},
355b82875eeSStephen Boyd 	},
356b82875eeSStephen Boyd };
357b82875eeSStephen Boyd 
358b82875eeSStephen Boyd static struct clk_branch audio_slimbus_clk = {
359b82875eeSStephen Boyd 	.halt_reg = 0xd4,
360b82875eeSStephen Boyd 	.halt_bit = 0,
361b82875eeSStephen Boyd 	.halt_check = BRANCH_HALT_ENABLE,
362b82875eeSStephen Boyd 	.clkr = {
363b82875eeSStephen Boyd 		.enable_reg = 0xcc,
364b82875eeSStephen Boyd 		.enable_mask = BIT(10),
365b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){
366b82875eeSStephen Boyd 			.name = "audio_slimbus_clk",
367a6976f85SDmitry Baryshkov 			.parent_hws = (const struct clk_hw*[]){
368a6976f85SDmitry Baryshkov 				&slimbus_src.clkr.hw,
369a6976f85SDmitry Baryshkov 			},
370b82875eeSStephen Boyd 			.num_parents = 1,
371b82875eeSStephen Boyd 			.ops = &clk_branch_ops,
372b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_PARENT,
373b82875eeSStephen Boyd 		},
374b82875eeSStephen Boyd 	},
375b82875eeSStephen Boyd };
376b82875eeSStephen Boyd 
377b82875eeSStephen Boyd static struct clk_branch sps_slimbus_clk = {
378b82875eeSStephen Boyd 	.halt_reg = 0xd4,
379b82875eeSStephen Boyd 	.halt_bit = 1,
380b82875eeSStephen Boyd 	.halt_check = BRANCH_HALT_ENABLE,
381b82875eeSStephen Boyd 	.clkr = {
382b82875eeSStephen Boyd 		.enable_reg = 0xcc,
383b82875eeSStephen Boyd 		.enable_mask = BIT(12),
384b82875eeSStephen Boyd 		.hw.init = &(struct clk_init_data){
385b82875eeSStephen Boyd 			.name = "sps_slimbus_clk",
386a6976f85SDmitry Baryshkov 			.parent_hws = (const struct clk_hw*[]){
387a6976f85SDmitry Baryshkov 				&slimbus_src.clkr.hw,
388a6976f85SDmitry Baryshkov 			},
389b82875eeSStephen Boyd 			.num_parents = 1,
390b82875eeSStephen Boyd 			.ops = &clk_branch_ops,
391b82875eeSStephen Boyd 			.flags = CLK_SET_RATE_PARENT,
392b82875eeSStephen Boyd 		},
393b82875eeSStephen Boyd 	},
394b82875eeSStephen Boyd };
395b82875eeSStephen Boyd 
396b82875eeSStephen Boyd static struct clk_regmap *lcc_msm8960_clks[] = {
397b82875eeSStephen Boyd 	[PLL4] = &pll4.clkr,
398b82875eeSStephen Boyd 	[MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
399b82875eeSStephen Boyd 	[MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
400b82875eeSStephen Boyd 	[MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
401b82875eeSStephen Boyd 	[MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
402b82875eeSStephen Boyd 	[MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
403b82875eeSStephen Boyd 	[PCM_SRC] = &pcm_src.clkr,
404b82875eeSStephen Boyd 	[PCM_CLK_OUT] = &pcm_clk_out.clkr,
405b82875eeSStephen Boyd 	[PCM_CLK] = &pcm_clk.clkr,
406b82875eeSStephen Boyd 	[SLIMBUS_SRC] = &slimbus_src.clkr,
407b82875eeSStephen Boyd 	[AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr,
408b82875eeSStephen Boyd 	[SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr,
409b82875eeSStephen Boyd 	[CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr,
410b82875eeSStephen Boyd 	[CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr,
411b82875eeSStephen Boyd 	[CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr,
412b82875eeSStephen Boyd 	[CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr,
413b82875eeSStephen Boyd 	[CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr,
414b82875eeSStephen Boyd 	[SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr,
415b82875eeSStephen Boyd 	[SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr,
416b82875eeSStephen Boyd 	[SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr,
417b82875eeSStephen Boyd 	[SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr,
418b82875eeSStephen Boyd 	[SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr,
419b82875eeSStephen Boyd 	[CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr,
420b82875eeSStephen Boyd 	[CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr,
421b82875eeSStephen Boyd 	[CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr,
422b82875eeSStephen Boyd 	[CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr,
423b82875eeSStephen Boyd 	[CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr,
424b82875eeSStephen Boyd 	[SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr,
425b82875eeSStephen Boyd 	[SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr,
426b82875eeSStephen Boyd 	[SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr,
427b82875eeSStephen Boyd 	[SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr,
428b82875eeSStephen Boyd 	[SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr,
429b82875eeSStephen Boyd };
430b82875eeSStephen Boyd 
431b82875eeSStephen Boyd static const struct regmap_config lcc_msm8960_regmap_config = {
432b82875eeSStephen Boyd 	.reg_bits	= 32,
433b82875eeSStephen Boyd 	.reg_stride	= 4,
434b82875eeSStephen Boyd 	.val_bits	= 32,
435b82875eeSStephen Boyd 	.max_register	= 0xfc,
436b82875eeSStephen Boyd 	.fast_io	= true,
437b82875eeSStephen Boyd };
438b82875eeSStephen Boyd 
439b82875eeSStephen Boyd static const struct qcom_cc_desc lcc_msm8960_desc = {
440b82875eeSStephen Boyd 	.config = &lcc_msm8960_regmap_config,
441b82875eeSStephen Boyd 	.clks = lcc_msm8960_clks,
442b82875eeSStephen Boyd 	.num_clks = ARRAY_SIZE(lcc_msm8960_clks),
443b82875eeSStephen Boyd };
444b82875eeSStephen Boyd 
445b82875eeSStephen Boyd static const struct of_device_id lcc_msm8960_match_table[] = {
446b82875eeSStephen Boyd 	{ .compatible = "qcom,lcc-msm8960" },
447b82875eeSStephen Boyd 	{ .compatible = "qcom,lcc-apq8064" },
448bac4675aSDmitry Baryshkov 	{ .compatible = "qcom,lcc-mdm9615" },
449b82875eeSStephen Boyd 	{ }
450b82875eeSStephen Boyd };
451b82875eeSStephen Boyd MODULE_DEVICE_TABLE(of, lcc_msm8960_match_table);
452b82875eeSStephen Boyd 
lcc_msm8960_probe(struct platform_device * pdev)453b82875eeSStephen Boyd static int lcc_msm8960_probe(struct platform_device *pdev)
454b82875eeSStephen Boyd {
455b82875eeSStephen Boyd 	u32 val;
456b82875eeSStephen Boyd 	struct regmap *regmap;
457b82875eeSStephen Boyd 
458bac4675aSDmitry Baryshkov 	/* patch for the cxo <-> pxo difference */
459bac4675aSDmitry Baryshkov 	if (of_device_is_compatible(pdev->dev.of_node, "qcom,lcc-mdm9615")) {
460bac4675aSDmitry Baryshkov 		pxo_parent_data.fw_name = "cxo";
461bac4675aSDmitry Baryshkov 		pxo_parent_data.name = "cxo_board";
462bac4675aSDmitry Baryshkov 		lcc_pxo_pll4[0].fw_name = "cxo";
463bac4675aSDmitry Baryshkov 		lcc_pxo_pll4[0].name = "cxo_board";
464bac4675aSDmitry Baryshkov 	}
465bac4675aSDmitry Baryshkov 
466b82875eeSStephen Boyd 	regmap = qcom_cc_map(pdev, &lcc_msm8960_desc);
467b82875eeSStephen Boyd 	if (IS_ERR(regmap))
468b82875eeSStephen Boyd 		return PTR_ERR(regmap);
469b82875eeSStephen Boyd 
470b82875eeSStephen Boyd 	/* Use the correct frequency plan depending on speed of PLL4 */
47184b919fdSStephen Boyd 	regmap_read(regmap, 0x4, &val);
472b82875eeSStephen Boyd 	if (val == 0x12) {
473b82875eeSStephen Boyd 		slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
474b82875eeSStephen Boyd 		mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
475b82875eeSStephen Boyd 		codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
476b82875eeSStephen Boyd 		spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
477b82875eeSStephen Boyd 		codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
478b82875eeSStephen Boyd 		spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
479b82875eeSStephen Boyd 		pcm_src.freq_tbl = clk_tbl_pcm_492;
480b82875eeSStephen Boyd 	}
481b82875eeSStephen Boyd 	/* Enable PLL4 source on the LPASS Primary PLL Mux */
482b82875eeSStephen Boyd 	regmap_write(regmap, 0xc4, 0x1);
483b82875eeSStephen Boyd 
484b82875eeSStephen Boyd 	return qcom_cc_really_probe(pdev, &lcc_msm8960_desc, regmap);
485b82875eeSStephen Boyd }
486b82875eeSStephen Boyd 
487b82875eeSStephen Boyd static struct platform_driver lcc_msm8960_driver = {
488b82875eeSStephen Boyd 	.probe		= lcc_msm8960_probe,
489b82875eeSStephen Boyd 	.driver		= {
490b82875eeSStephen Boyd 		.name	= "lcc-msm8960",
491b82875eeSStephen Boyd 		.of_match_table = lcc_msm8960_match_table,
492b82875eeSStephen Boyd 	},
493b82875eeSStephen Boyd };
494b82875eeSStephen Boyd module_platform_driver(lcc_msm8960_driver);
495b82875eeSStephen Boyd 
496b82875eeSStephen Boyd MODULE_DESCRIPTION("QCOM LCC MSM8960 Driver");
497b82875eeSStephen Boyd MODULE_LICENSE("GPL v2");
498b82875eeSStephen Boyd MODULE_ALIAS("platform:lcc-msm8960");
499