1*3730fe60SJoakim Zhang // SPDX-License-Identifier: GPL-2.0-only
2*3730fe60SJoakim Zhang // Copyright 2026 Cix Technology Group Co., Ltd.
3*3730fe60SJoakim Zhang
4*3730fe60SJoakim Zhang #include <linux/auxiliary_bus.h>
5*3730fe60SJoakim Zhang #include <linux/clk.h>
6*3730fe60SJoakim Zhang #include <linux/clk-provider.h>
7*3730fe60SJoakim Zhang #include <linux/device.h>
8*3730fe60SJoakim Zhang #include <linux/module.h>
9*3730fe60SJoakim Zhang #include <linux/of.h>
10*3730fe60SJoakim Zhang #include <linux/platform_device.h>
11*3730fe60SJoakim Zhang #include <linux/pm_runtime.h>
12*3730fe60SJoakim Zhang #include <linux/regmap.h>
13*3730fe60SJoakim Zhang #include <linux/reset.h>
14*3730fe60SJoakim Zhang
15*3730fe60SJoakim Zhang #include <dt-bindings/clock/cix,sky1-audss-cru.h>
16*3730fe60SJoakim Zhang
17*3730fe60SJoakim Zhang #define INFO_HIFI0 0x00
18*3730fe60SJoakim Zhang #define INFO_CLK_GATE 0x10
19*3730fe60SJoakim Zhang #define INFO_CLK_DIV 0x14
20*3730fe60SJoakim Zhang #define INFO_CLK_MUX 0x18
21*3730fe60SJoakim Zhang #define INFO_MCLK 0x70
22*3730fe60SJoakim Zhang
23*3730fe60SJoakim Zhang #define SKY1_AUDSS_CLK_PARENTS_CNT 4
24*3730fe60SJoakim Zhang #define SKY1_AUDSS_NUM_CLKS (CLK_MCLK4 + 1)
25*3730fe60SJoakim Zhang
26*3730fe60SJoakim Zhang static u32 sky1_reg_save[][2] = {
27*3730fe60SJoakim Zhang { INFO_HIFI0, 0 },
28*3730fe60SJoakim Zhang { INFO_CLK_GATE, 0 },
29*3730fe60SJoakim Zhang { INFO_CLK_DIV, 0 },
30*3730fe60SJoakim Zhang { INFO_CLK_MUX, 0 },
31*3730fe60SJoakim Zhang { INFO_MCLK, 0 },
32*3730fe60SJoakim Zhang };
33*3730fe60SJoakim Zhang
34*3730fe60SJoakim Zhang static const char * const sky1_audss_clk_names[SKY1_AUDSS_CLK_PARENTS_CNT] = {
35*3730fe60SJoakim Zhang "x8k", "x11k", "sys", "48m",
36*3730fe60SJoakim Zhang };
37*3730fe60SJoakim Zhang
38*3730fe60SJoakim Zhang static const u32 sky1_clk_rate_default[SKY1_AUDSS_CLK_PARENTS_CNT] = {
39*3730fe60SJoakim Zhang 294912000,
40*3730fe60SJoakim Zhang 270950400,
41*3730fe60SJoakim Zhang 800000000,
42*3730fe60SJoakim Zhang 48000000,
43*3730fe60SJoakim Zhang };
44*3730fe60SJoakim Zhang
45*3730fe60SJoakim Zhang static const char * const dsp_clk_parent[] = {
46*3730fe60SJoakim Zhang "audio_clk4"
47*3730fe60SJoakim Zhang };
48*3730fe60SJoakim Zhang
49*3730fe60SJoakim Zhang static const char * const dsp_bclk_parent[] = {
50*3730fe60SJoakim Zhang "audio_clk4_div2"
51*3730fe60SJoakim Zhang };
52*3730fe60SJoakim Zhang
53*3730fe60SJoakim Zhang static const char * const dsp_pbclk_parent[] = {
54*3730fe60SJoakim Zhang "audio_clk4_div4"
55*3730fe60SJoakim Zhang };
56*3730fe60SJoakim Zhang
57*3730fe60SJoakim Zhang static const char * const sram_axi_parent[] = {
58*3730fe60SJoakim Zhang "audio_clk4_div2"
59*3730fe60SJoakim Zhang };
60*3730fe60SJoakim Zhang
61*3730fe60SJoakim Zhang static const char * const hda_sys_parent[] = {
62*3730fe60SJoakim Zhang "audio_clk4_div2"
63*3730fe60SJoakim Zhang };
64*3730fe60SJoakim Zhang
65*3730fe60SJoakim Zhang static const char * const hda_hda_parent[] = {
66*3730fe60SJoakim Zhang "audio_clk5"
67*3730fe60SJoakim Zhang };
68*3730fe60SJoakim Zhang
69*3730fe60SJoakim Zhang static const char * const dmac_axi_parent[] = {
70*3730fe60SJoakim Zhang "audio_clk4_div2"
71*3730fe60SJoakim Zhang };
72*3730fe60SJoakim Zhang
73*3730fe60SJoakim Zhang static const char * const wdg_apb_parent[] = {
74*3730fe60SJoakim Zhang "audio_clk5_div2"
75*3730fe60SJoakim Zhang };
76*3730fe60SJoakim Zhang
77*3730fe60SJoakim Zhang static const char * const wdg_wdg_parent[] = {
78*3730fe60SJoakim Zhang "audio_clk5_div2"
79*3730fe60SJoakim Zhang };
80*3730fe60SJoakim Zhang
81*3730fe60SJoakim Zhang static const char * const timer_apb_parent[] = {
82*3730fe60SJoakim Zhang "audio_clk4_div4"
83*3730fe60SJoakim Zhang };
84*3730fe60SJoakim Zhang
85*3730fe60SJoakim Zhang static const char * const timer_timer_parent[] = {
86*3730fe60SJoakim Zhang "audio_clk5_div2"
87*3730fe60SJoakim Zhang };
88*3730fe60SJoakim Zhang
89*3730fe60SJoakim Zhang static const char * const mailbox_apb_parent[] = {
90*3730fe60SJoakim Zhang "audio_clk4_div4"
91*3730fe60SJoakim Zhang };
92*3730fe60SJoakim Zhang
93*3730fe60SJoakim Zhang static const char * const i2s_apb_parent[] = {
94*3730fe60SJoakim Zhang "audio_clk4_div4"
95*3730fe60SJoakim Zhang };
96*3730fe60SJoakim Zhang
97*3730fe60SJoakim Zhang static const char * const i2s0_parents[] = {
98*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
99*3730fe60SJoakim Zhang };
100*3730fe60SJoakim Zhang
101*3730fe60SJoakim Zhang static const char * const i2s1_parents[] = {
102*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
103*3730fe60SJoakim Zhang };
104*3730fe60SJoakim Zhang
105*3730fe60SJoakim Zhang static const char * const i2s2_parents[] = {
106*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
107*3730fe60SJoakim Zhang };
108*3730fe60SJoakim Zhang
109*3730fe60SJoakim Zhang static const char * const i2s3_parents[] = {
110*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
111*3730fe60SJoakim Zhang };
112*3730fe60SJoakim Zhang
113*3730fe60SJoakim Zhang static const char * const i2s4_parents[] = {
114*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
115*3730fe60SJoakim Zhang };
116*3730fe60SJoakim Zhang
117*3730fe60SJoakim Zhang static const char * const i2s5_parents[] = {
118*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
119*3730fe60SJoakim Zhang };
120*3730fe60SJoakim Zhang
121*3730fe60SJoakim Zhang static const char * const i2s6_parents[] = {
122*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
123*3730fe60SJoakim Zhang };
124*3730fe60SJoakim Zhang
125*3730fe60SJoakim Zhang static const char * const i2s7_parents[] = {
126*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
127*3730fe60SJoakim Zhang };
128*3730fe60SJoakim Zhang
129*3730fe60SJoakim Zhang static const char * const i2s8_parents[] = {
130*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
131*3730fe60SJoakim Zhang };
132*3730fe60SJoakim Zhang
133*3730fe60SJoakim Zhang static const char * const i2s9_parents[] = {
134*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
135*3730fe60SJoakim Zhang };
136*3730fe60SJoakim Zhang
137*3730fe60SJoakim Zhang static const char * const mclk_parents[] = {
138*3730fe60SJoakim Zhang "audio_clk0", "audio_clk2"
139*3730fe60SJoakim Zhang };
140*3730fe60SJoakim Zhang
141*3730fe60SJoakim Zhang static const u32 i2s3_mux_table[] = { 0, 2 };
142*3730fe60SJoakim Zhang static const u32 i2s4_mux_table[] = { 0, 2 };
143*3730fe60SJoakim Zhang
144*3730fe60SJoakim Zhang /*
145*3730fe60SJoakim Zhang * audss composite clock definition
146*3730fe60SJoakim Zhang */
147*3730fe60SJoakim Zhang struct muxdiv_cfg {
148*3730fe60SJoakim Zhang int offset;
149*3730fe60SJoakim Zhang u8 shift;
150*3730fe60SJoakim Zhang u8 width;
151*3730fe60SJoakim Zhang u8 flags;
152*3730fe60SJoakim Zhang };
153*3730fe60SJoakim Zhang
154*3730fe60SJoakim Zhang struct gate_cfg {
155*3730fe60SJoakim Zhang int offset;
156*3730fe60SJoakim Zhang u8 shift;
157*3730fe60SJoakim Zhang u8 flags;
158*3730fe60SJoakim Zhang };
159*3730fe60SJoakim Zhang
160*3730fe60SJoakim Zhang struct composite_clk_cfg {
161*3730fe60SJoakim Zhang u32 id;
162*3730fe60SJoakim Zhang const char * const name;
163*3730fe60SJoakim Zhang const char * const *parent_names;
164*3730fe60SJoakim Zhang int num_parents;
165*3730fe60SJoakim Zhang const u32 *mux_table;
166*3730fe60SJoakim Zhang struct muxdiv_cfg *mux_cfg;
167*3730fe60SJoakim Zhang struct muxdiv_cfg *div_cfg;
168*3730fe60SJoakim Zhang struct gate_cfg *gate_cfg;
169*3730fe60SJoakim Zhang unsigned long flags;
170*3730fe60SJoakim Zhang };
171*3730fe60SJoakim Zhang
172*3730fe60SJoakim Zhang #define CFG(_id,\
173*3730fe60SJoakim Zhang _name,\
174*3730fe60SJoakim Zhang _parent_names,\
175*3730fe60SJoakim Zhang _mux_table,\
176*3730fe60SJoakim Zhang _mux_offset, _mux_shift, _mux_width, _mux_flags,\
177*3730fe60SJoakim Zhang _div_offset, _div_shift, _div_width, _div_flags,\
178*3730fe60SJoakim Zhang _gate_offset, _gate_shift, _gate_flags,\
179*3730fe60SJoakim Zhang _flags)\
180*3730fe60SJoakim Zhang {\
181*3730fe60SJoakim Zhang .id = _id,\
182*3730fe60SJoakim Zhang .name = _name,\
183*3730fe60SJoakim Zhang .parent_names = _parent_names,\
184*3730fe60SJoakim Zhang .num_parents = ARRAY_SIZE(_parent_names),\
185*3730fe60SJoakim Zhang .mux_table = _mux_table,\
186*3730fe60SJoakim Zhang .mux_cfg = &(struct muxdiv_cfg) { _mux_offset, _mux_shift, _mux_width, _mux_flags },\
187*3730fe60SJoakim Zhang .div_cfg = &(struct muxdiv_cfg) { _div_offset, _div_shift, _div_width, _div_flags },\
188*3730fe60SJoakim Zhang .gate_cfg = &(struct gate_cfg) { _gate_offset, _gate_shift, _gate_flags },\
189*3730fe60SJoakim Zhang .flags = _flags,\
190*3730fe60SJoakim Zhang }
191*3730fe60SJoakim Zhang
192*3730fe60SJoakim Zhang static const struct composite_clk_cfg sky1_audss_clks[] = {
193*3730fe60SJoakim Zhang /* dsp */
194*3730fe60SJoakim Zhang CFG(CLK_DSP_CLK,
195*3730fe60SJoakim Zhang "audss_dsp_clk",
196*3730fe60SJoakim Zhang dsp_clk_parent,
197*3730fe60SJoakim Zhang NULL,
198*3730fe60SJoakim Zhang -1, 0, 0, 0,
199*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
200*3730fe60SJoakim Zhang INFO_HIFI0, 0, 0,
201*3730fe60SJoakim Zhang 0),
202*3730fe60SJoakim Zhang CFG(CLK_DSP_BCLK,
203*3730fe60SJoakim Zhang "audss_dsp_bclk",
204*3730fe60SJoakim Zhang dsp_bclk_parent,
205*3730fe60SJoakim Zhang NULL,
206*3730fe60SJoakim Zhang -1, 0, 0, 0,
207*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
208*3730fe60SJoakim Zhang -1, 0, 0,
209*3730fe60SJoakim Zhang 0),
210*3730fe60SJoakim Zhang CFG(CLK_DSP_PBCLK,
211*3730fe60SJoakim Zhang "audss_dsp_pbclk",
212*3730fe60SJoakim Zhang dsp_pbclk_parent,
213*3730fe60SJoakim Zhang NULL,
214*3730fe60SJoakim Zhang -1, 0, 0, 0,
215*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
216*3730fe60SJoakim Zhang -1, 0, 0,
217*3730fe60SJoakim Zhang 0),
218*3730fe60SJoakim Zhang /* sram */
219*3730fe60SJoakim Zhang CFG(CLK_SRAM_AXI,
220*3730fe60SJoakim Zhang "audss_sram_axi",
221*3730fe60SJoakim Zhang sram_axi_parent,
222*3730fe60SJoakim Zhang NULL,
223*3730fe60SJoakim Zhang -1, 0, 0, 0,
224*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
225*3730fe60SJoakim Zhang INFO_CLK_GATE, 16, 0,
226*3730fe60SJoakim Zhang 0),
227*3730fe60SJoakim Zhang /* hda */
228*3730fe60SJoakim Zhang CFG(CLK_HDA_SYS,
229*3730fe60SJoakim Zhang "audss_hda_sys",
230*3730fe60SJoakim Zhang hda_sys_parent,
231*3730fe60SJoakim Zhang NULL,
232*3730fe60SJoakim Zhang -1, 0, 0, 0,
233*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
234*3730fe60SJoakim Zhang INFO_CLK_GATE, 14, 0,
235*3730fe60SJoakim Zhang 0),
236*3730fe60SJoakim Zhang CFG(CLK_HDA_HDA,
237*3730fe60SJoakim Zhang "audss_hda_hda",
238*3730fe60SJoakim Zhang hda_hda_parent,
239*3730fe60SJoakim Zhang NULL,
240*3730fe60SJoakim Zhang -1, 0, 0, 0,
241*3730fe60SJoakim Zhang -1, 0, 0, 0,
242*3730fe60SJoakim Zhang INFO_CLK_GATE, 14, 0,
243*3730fe60SJoakim Zhang 0),
244*3730fe60SJoakim Zhang /* dmac */
245*3730fe60SJoakim Zhang CFG(CLK_DMAC_AXI,
246*3730fe60SJoakim Zhang "audss_dmac_axi",
247*3730fe60SJoakim Zhang dmac_axi_parent,
248*3730fe60SJoakim Zhang NULL,
249*3730fe60SJoakim Zhang -1, 0, 0, 0,
250*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
251*3730fe60SJoakim Zhang INFO_CLK_GATE, 15, 0,
252*3730fe60SJoakim Zhang 0),
253*3730fe60SJoakim Zhang /* wdg */
254*3730fe60SJoakim Zhang CFG(CLK_WDG_APB,
255*3730fe60SJoakim Zhang "audss_wdg_apb",
256*3730fe60SJoakim Zhang wdg_apb_parent,
257*3730fe60SJoakim Zhang NULL,
258*3730fe60SJoakim Zhang -1, 0, 0, 0,
259*3730fe60SJoakim Zhang -1, 0, 0, 0,
260*3730fe60SJoakim Zhang INFO_CLK_GATE, 10, 0,
261*3730fe60SJoakim Zhang 0),
262*3730fe60SJoakim Zhang CFG(CLK_WDG_WDG,
263*3730fe60SJoakim Zhang "audss_wdg_wdg",
264*3730fe60SJoakim Zhang wdg_wdg_parent,
265*3730fe60SJoakim Zhang NULL,
266*3730fe60SJoakim Zhang -1, 0, 0, 0,
267*3730fe60SJoakim Zhang -1, 0, 0, 0,
268*3730fe60SJoakim Zhang INFO_CLK_GATE, 10, 0,
269*3730fe60SJoakim Zhang 0),
270*3730fe60SJoakim Zhang /* timer */
271*3730fe60SJoakim Zhang CFG(CLK_TIMER_APB,
272*3730fe60SJoakim Zhang "audss_timer_apb",
273*3730fe60SJoakim Zhang timer_apb_parent,
274*3730fe60SJoakim Zhang NULL,
275*3730fe60SJoakim Zhang -1, 0, 0, 0,
276*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
277*3730fe60SJoakim Zhang INFO_CLK_GATE, 11, 0,
278*3730fe60SJoakim Zhang 0),
279*3730fe60SJoakim Zhang CFG(CLK_TIMER_TIMER,
280*3730fe60SJoakim Zhang "audss_timer_timer",
281*3730fe60SJoakim Zhang timer_timer_parent,
282*3730fe60SJoakim Zhang NULL,
283*3730fe60SJoakim Zhang -1, 0, 0, 0,
284*3730fe60SJoakim Zhang -1, 0, 0, 0,
285*3730fe60SJoakim Zhang INFO_CLK_GATE, 11, 0,
286*3730fe60SJoakim Zhang 0),
287*3730fe60SJoakim Zhang /* mailbox: mb0(ap->dsp), mb1(dsp->ap) */
288*3730fe60SJoakim Zhang CFG(CLK_MB_0_APB,
289*3730fe60SJoakim Zhang "audss_mb_0_apb",
290*3730fe60SJoakim Zhang mailbox_apb_parent,
291*3730fe60SJoakim Zhang NULL,
292*3730fe60SJoakim Zhang -1, 0, 0, 0,
293*3730fe60SJoakim Zhang -1, 0, 0, 0,
294*3730fe60SJoakim Zhang INFO_CLK_GATE, 12, 0,
295*3730fe60SJoakim Zhang 0),
296*3730fe60SJoakim Zhang CFG(CLK_MB_1_APB,
297*3730fe60SJoakim Zhang "audss_mb_1_apb",
298*3730fe60SJoakim Zhang mailbox_apb_parent,
299*3730fe60SJoakim Zhang NULL,
300*3730fe60SJoakim Zhang -1, 0, 0, 0,
301*3730fe60SJoakim Zhang -1, 0, 0, 0,
302*3730fe60SJoakim Zhang INFO_CLK_GATE, 13, 0,
303*3730fe60SJoakim Zhang 0),
304*3730fe60SJoakim Zhang /* i2s */
305*3730fe60SJoakim Zhang CFG(CLK_I2S0_APB,
306*3730fe60SJoakim Zhang "audss_i2s0_apb",
307*3730fe60SJoakim Zhang i2s_apb_parent,
308*3730fe60SJoakim Zhang NULL,
309*3730fe60SJoakim Zhang -1, 0, 0, 0,
310*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
311*3730fe60SJoakim Zhang INFO_CLK_GATE, 0, 0,
312*3730fe60SJoakim Zhang 0),
313*3730fe60SJoakim Zhang CFG(CLK_I2S1_APB,
314*3730fe60SJoakim Zhang "audss_i2s1_apb",
315*3730fe60SJoakim Zhang i2s_apb_parent,
316*3730fe60SJoakim Zhang NULL,
317*3730fe60SJoakim Zhang -1, 0, 0, 0,
318*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
319*3730fe60SJoakim Zhang INFO_CLK_GATE, 1, 0,
320*3730fe60SJoakim Zhang 0),
321*3730fe60SJoakim Zhang CFG(CLK_I2S2_APB,
322*3730fe60SJoakim Zhang "audss_i2s2_apb",
323*3730fe60SJoakim Zhang i2s_apb_parent,
324*3730fe60SJoakim Zhang NULL,
325*3730fe60SJoakim Zhang -1, 0, 0, 0,
326*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
327*3730fe60SJoakim Zhang INFO_CLK_GATE, 2, 0,
328*3730fe60SJoakim Zhang 0),
329*3730fe60SJoakim Zhang CFG(CLK_I2S3_APB,
330*3730fe60SJoakim Zhang "audss_i2s3_apb",
331*3730fe60SJoakim Zhang i2s_apb_parent,
332*3730fe60SJoakim Zhang NULL,
333*3730fe60SJoakim Zhang -1, 0, 0, 0,
334*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
335*3730fe60SJoakim Zhang INFO_CLK_GATE, 3, 0,
336*3730fe60SJoakim Zhang 0),
337*3730fe60SJoakim Zhang CFG(CLK_I2S4_APB,
338*3730fe60SJoakim Zhang "audss_i2s4_apb",
339*3730fe60SJoakim Zhang i2s_apb_parent,
340*3730fe60SJoakim Zhang NULL,
341*3730fe60SJoakim Zhang -1, 0, 0, 0,
342*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
343*3730fe60SJoakim Zhang INFO_CLK_GATE, 4, 0,
344*3730fe60SJoakim Zhang 0),
345*3730fe60SJoakim Zhang CFG(CLK_I2S5_APB,
346*3730fe60SJoakim Zhang "audss_i2s5_apb",
347*3730fe60SJoakim Zhang i2s_apb_parent,
348*3730fe60SJoakim Zhang NULL,
349*3730fe60SJoakim Zhang -1, 0, 0, 0,
350*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
351*3730fe60SJoakim Zhang INFO_CLK_GATE, 5, 0,
352*3730fe60SJoakim Zhang 0),
353*3730fe60SJoakim Zhang CFG(CLK_I2S6_APB,
354*3730fe60SJoakim Zhang "audss_i2s6_apb",
355*3730fe60SJoakim Zhang i2s_apb_parent,
356*3730fe60SJoakim Zhang NULL,
357*3730fe60SJoakim Zhang -1, 0, 0, 0,
358*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
359*3730fe60SJoakim Zhang INFO_CLK_GATE, 6, 0,
360*3730fe60SJoakim Zhang 0),
361*3730fe60SJoakim Zhang CFG(CLK_I2S7_APB,
362*3730fe60SJoakim Zhang "audss_i2s7_apb",
363*3730fe60SJoakim Zhang i2s_apb_parent,
364*3730fe60SJoakim Zhang NULL,
365*3730fe60SJoakim Zhang -1, 0, 0, 0,
366*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
367*3730fe60SJoakim Zhang INFO_CLK_GATE, 7, 0,
368*3730fe60SJoakim Zhang 0),
369*3730fe60SJoakim Zhang CFG(CLK_I2S8_APB,
370*3730fe60SJoakim Zhang "audss_i2s8_apb",
371*3730fe60SJoakim Zhang i2s_apb_parent,
372*3730fe60SJoakim Zhang NULL,
373*3730fe60SJoakim Zhang -1, 0, 0, 0,
374*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
375*3730fe60SJoakim Zhang INFO_CLK_GATE, 8, 0,
376*3730fe60SJoakim Zhang 0),
377*3730fe60SJoakim Zhang CFG(CLK_I2S9_APB,
378*3730fe60SJoakim Zhang "audss_i2s9_apb",
379*3730fe60SJoakim Zhang i2s_apb_parent,
380*3730fe60SJoakim Zhang NULL,
381*3730fe60SJoakim Zhang -1, 0, 0, 0,
382*3730fe60SJoakim Zhang INFO_CLK_DIV, 0, 2, 0,
383*3730fe60SJoakim Zhang INFO_CLK_GATE, 9, 0,
384*3730fe60SJoakim Zhang 0),
385*3730fe60SJoakim Zhang CFG(CLK_I2S0,
386*3730fe60SJoakim Zhang "audss_i2s0",
387*3730fe60SJoakim Zhang i2s0_parents,
388*3730fe60SJoakim Zhang NULL,
389*3730fe60SJoakim Zhang INFO_CLK_MUX, 0, 2, 0,
390*3730fe60SJoakim Zhang INFO_CLK_DIV, 2, 2, 0,
391*3730fe60SJoakim Zhang INFO_CLK_GATE, 0, 0,
392*3730fe60SJoakim Zhang 0),
393*3730fe60SJoakim Zhang CFG(CLK_I2S1,
394*3730fe60SJoakim Zhang "audss_i2s1",
395*3730fe60SJoakim Zhang i2s1_parents,
396*3730fe60SJoakim Zhang NULL,
397*3730fe60SJoakim Zhang INFO_CLK_MUX, 2, 2, 0,
398*3730fe60SJoakim Zhang INFO_CLK_DIV, 4, 2, 0,
399*3730fe60SJoakim Zhang INFO_CLK_GATE, 1, 0,
400*3730fe60SJoakim Zhang 0),
401*3730fe60SJoakim Zhang CFG(CLK_I2S2,
402*3730fe60SJoakim Zhang "audss_i2s2",
403*3730fe60SJoakim Zhang i2s2_parents,
404*3730fe60SJoakim Zhang NULL,
405*3730fe60SJoakim Zhang INFO_CLK_MUX, 4, 2, 0,
406*3730fe60SJoakim Zhang INFO_CLK_DIV, 6, 2, 0,
407*3730fe60SJoakim Zhang INFO_CLK_GATE, 2, 0,
408*3730fe60SJoakim Zhang 0),
409*3730fe60SJoakim Zhang CFG(CLK_I2S3,
410*3730fe60SJoakim Zhang "audss_i2s3",
411*3730fe60SJoakim Zhang i2s3_parents,
412*3730fe60SJoakim Zhang i2s3_mux_table,
413*3730fe60SJoakim Zhang INFO_CLK_MUX, 6, 2, 0,
414*3730fe60SJoakim Zhang INFO_CLK_DIV, 8, 2, 0,
415*3730fe60SJoakim Zhang INFO_CLK_GATE, 3, 0,
416*3730fe60SJoakim Zhang 0),
417*3730fe60SJoakim Zhang CFG(CLK_I2S4,
418*3730fe60SJoakim Zhang "audss_i2s4",
419*3730fe60SJoakim Zhang i2s4_parents,
420*3730fe60SJoakim Zhang i2s4_mux_table,
421*3730fe60SJoakim Zhang INFO_CLK_MUX, 8, 2, 0,
422*3730fe60SJoakim Zhang INFO_CLK_DIV, 10, 2, 0,
423*3730fe60SJoakim Zhang INFO_CLK_GATE, 4, 0,
424*3730fe60SJoakim Zhang 0),
425*3730fe60SJoakim Zhang CFG(CLK_I2S5,
426*3730fe60SJoakim Zhang "audss_i2s5",
427*3730fe60SJoakim Zhang i2s5_parents,
428*3730fe60SJoakim Zhang NULL,
429*3730fe60SJoakim Zhang INFO_CLK_MUX, 10, 2, 0,
430*3730fe60SJoakim Zhang INFO_CLK_DIV, 12, 2, 0,
431*3730fe60SJoakim Zhang INFO_CLK_GATE, 5, 0,
432*3730fe60SJoakim Zhang 0),
433*3730fe60SJoakim Zhang CFG(CLK_I2S6,
434*3730fe60SJoakim Zhang "audss_i2s6",
435*3730fe60SJoakim Zhang i2s6_parents,
436*3730fe60SJoakim Zhang NULL,
437*3730fe60SJoakim Zhang INFO_CLK_MUX, 12, 2, 0,
438*3730fe60SJoakim Zhang INFO_CLK_DIV, 14, 2, 0,
439*3730fe60SJoakim Zhang INFO_CLK_GATE, 6, 0,
440*3730fe60SJoakim Zhang 0),
441*3730fe60SJoakim Zhang CFG(CLK_I2S7,
442*3730fe60SJoakim Zhang "audss_i2s7",
443*3730fe60SJoakim Zhang i2s7_parents,
444*3730fe60SJoakim Zhang NULL,
445*3730fe60SJoakim Zhang INFO_CLK_MUX, 14, 2, 0,
446*3730fe60SJoakim Zhang INFO_CLK_DIV, 16, 2, 0,
447*3730fe60SJoakim Zhang INFO_CLK_GATE, 7, 0,
448*3730fe60SJoakim Zhang 0),
449*3730fe60SJoakim Zhang CFG(CLK_I2S8,
450*3730fe60SJoakim Zhang "audss_i2s8",
451*3730fe60SJoakim Zhang i2s8_parents,
452*3730fe60SJoakim Zhang NULL,
453*3730fe60SJoakim Zhang INFO_CLK_MUX, 16, 2, 0,
454*3730fe60SJoakim Zhang INFO_CLK_DIV, 18, 2, 0,
455*3730fe60SJoakim Zhang INFO_CLK_GATE, 8, 0,
456*3730fe60SJoakim Zhang 0),
457*3730fe60SJoakim Zhang CFG(CLK_I2S9,
458*3730fe60SJoakim Zhang "audss_i2s9",
459*3730fe60SJoakim Zhang i2s9_parents,
460*3730fe60SJoakim Zhang NULL,
461*3730fe60SJoakim Zhang INFO_CLK_MUX, 18, 2, 0,
462*3730fe60SJoakim Zhang INFO_CLK_DIV, 20, 2, 0,
463*3730fe60SJoakim Zhang INFO_CLK_GATE, 9, 0,
464*3730fe60SJoakim Zhang 0),
465*3730fe60SJoakim Zhang /* mclk */
466*3730fe60SJoakim Zhang CFG(CLK_MCLK0,
467*3730fe60SJoakim Zhang "audss_mclk0",
468*3730fe60SJoakim Zhang mclk_parents,
469*3730fe60SJoakim Zhang NULL,
470*3730fe60SJoakim Zhang INFO_MCLK, 5, 1, 0,
471*3730fe60SJoakim Zhang -1, 0, 0, 0,
472*3730fe60SJoakim Zhang INFO_MCLK, 0, 0,
473*3730fe60SJoakim Zhang 0),
474*3730fe60SJoakim Zhang CFG(CLK_MCLK1,
475*3730fe60SJoakim Zhang "audss_mclk1",
476*3730fe60SJoakim Zhang mclk_parents,
477*3730fe60SJoakim Zhang NULL,
478*3730fe60SJoakim Zhang INFO_MCLK, 6, 1, 0,
479*3730fe60SJoakim Zhang -1, 0, 0, 0,
480*3730fe60SJoakim Zhang INFO_MCLK, 1, 0,
481*3730fe60SJoakim Zhang 0),
482*3730fe60SJoakim Zhang CFG(CLK_MCLK2,
483*3730fe60SJoakim Zhang "audss_mclk2",
484*3730fe60SJoakim Zhang mclk_parents,
485*3730fe60SJoakim Zhang NULL,
486*3730fe60SJoakim Zhang INFO_MCLK, 7, 1, 0,
487*3730fe60SJoakim Zhang -1, 0, 0, 0,
488*3730fe60SJoakim Zhang INFO_MCLK, 2, 0,
489*3730fe60SJoakim Zhang 0),
490*3730fe60SJoakim Zhang CFG(CLK_MCLK3,
491*3730fe60SJoakim Zhang "audss_mclk3",
492*3730fe60SJoakim Zhang mclk_parents,
493*3730fe60SJoakim Zhang NULL,
494*3730fe60SJoakim Zhang INFO_MCLK, 8, 1, 0,
495*3730fe60SJoakim Zhang -1, 0, 0, 0,
496*3730fe60SJoakim Zhang INFO_MCLK, 3, 0,
497*3730fe60SJoakim Zhang 0),
498*3730fe60SJoakim Zhang CFG(CLK_MCLK4,
499*3730fe60SJoakim Zhang "audss_mclk4",
500*3730fe60SJoakim Zhang mclk_parents,
501*3730fe60SJoakim Zhang NULL,
502*3730fe60SJoakim Zhang INFO_MCLK, 9, 1, 0,
503*3730fe60SJoakim Zhang -1, 0, 0, 0,
504*3730fe60SJoakim Zhang INFO_MCLK, 4, 0,
505*3730fe60SJoakim Zhang 0),
506*3730fe60SJoakim Zhang };
507*3730fe60SJoakim Zhang
508*3730fe60SJoakim Zhang struct sky1_audss_clks_devtype_data {
509*3730fe60SJoakim Zhang u32 (*reg_save)[2];
510*3730fe60SJoakim Zhang size_t reg_save_size;
511*3730fe60SJoakim Zhang const char * const *clk_names;
512*3730fe60SJoakim Zhang size_t clk_num;
513*3730fe60SJoakim Zhang const u32 *clk_rate_default;
514*3730fe60SJoakim Zhang const struct composite_clk_cfg *clk_cfg;
515*3730fe60SJoakim Zhang size_t clk_cfg_size;
516*3730fe60SJoakim Zhang };
517*3730fe60SJoakim Zhang
518*3730fe60SJoakim Zhang static const struct regmap_config sky1_audss_regmap_config = {
519*3730fe60SJoakim Zhang .reg_bits = 32,
520*3730fe60SJoakim Zhang .val_bits = 32,
521*3730fe60SJoakim Zhang .reg_stride = 4,
522*3730fe60SJoakim Zhang };
523*3730fe60SJoakim Zhang
524*3730fe60SJoakim Zhang struct sky1_audss_clks_priv {
525*3730fe60SJoakim Zhang struct device *dev;
526*3730fe60SJoakim Zhang struct regmap *regmap_cru;
527*3730fe60SJoakim Zhang struct reset_control *rst_noc;
528*3730fe60SJoakim Zhang struct clk *clks[SKY1_AUDSS_CLK_PARENTS_CNT];
529*3730fe60SJoakim Zhang const struct sky1_audss_clks_devtype_data *devtype_data;
530*3730fe60SJoakim Zhang spinlock_t lock;
531*3730fe60SJoakim Zhang struct clk_hw_onecell_data *clk_data;
532*3730fe60SJoakim Zhang };
533*3730fe60SJoakim Zhang
534*3730fe60SJoakim Zhang #if IS_ENABLED(CONFIG_RESET_SKY1_AUDSS)
535*3730fe60SJoakim Zhang
sky1_audss_reset_controller_register(struct device * dev)536*3730fe60SJoakim Zhang static int sky1_audss_reset_controller_register(struct device *dev)
537*3730fe60SJoakim Zhang {
538*3730fe60SJoakim Zhang struct auxiliary_device *adev;
539*3730fe60SJoakim Zhang
540*3730fe60SJoakim Zhang if (!of_property_present(dev->of_node, "#reset-cells"))
541*3730fe60SJoakim Zhang return 0;
542*3730fe60SJoakim Zhang
543*3730fe60SJoakim Zhang adev = devm_auxiliary_device_create(dev, "reset", NULL);
544*3730fe60SJoakim Zhang if (!adev)
545*3730fe60SJoakim Zhang return -ENODEV;
546*3730fe60SJoakim Zhang
547*3730fe60SJoakim Zhang return 0;
548*3730fe60SJoakim Zhang }
549*3730fe60SJoakim Zhang
550*3730fe60SJoakim Zhang #else
551*3730fe60SJoakim Zhang
sky1_audss_reset_controller_register(struct device * dev)552*3730fe60SJoakim Zhang static int sky1_audss_reset_controller_register(struct device *dev)
553*3730fe60SJoakim Zhang {
554*3730fe60SJoakim Zhang return 0;
555*3730fe60SJoakim Zhang }
556*3730fe60SJoakim Zhang
557*3730fe60SJoakim Zhang #endif
558*3730fe60SJoakim Zhang
559*3730fe60SJoakim Zhang /*
560*3730fe60SJoakim Zhang * clk_ops for audss clock mux/divider/gate
561*3730fe60SJoakim Zhang */
562*3730fe60SJoakim Zhang struct sky1_clk_divider {
563*3730fe60SJoakim Zhang struct clk_divider div;
564*3730fe60SJoakim Zhang struct regmap *regmap;
565*3730fe60SJoakim Zhang int offset;
566*3730fe60SJoakim Zhang };
567*3730fe60SJoakim Zhang
568*3730fe60SJoakim Zhang struct sky1_clk_gate {
569*3730fe60SJoakim Zhang struct clk_gate gate;
570*3730fe60SJoakim Zhang struct regmap *regmap;
571*3730fe60SJoakim Zhang int offset;
572*3730fe60SJoakim Zhang };
573*3730fe60SJoakim Zhang
574*3730fe60SJoakim Zhang struct sky1_clk_mux {
575*3730fe60SJoakim Zhang struct clk_mux mux;
576*3730fe60SJoakim Zhang struct regmap *regmap;
577*3730fe60SJoakim Zhang int offset;
578*3730fe60SJoakim Zhang };
579*3730fe60SJoakim Zhang
to_sky1_clk_mux(struct clk_mux * mux)580*3730fe60SJoakim Zhang static inline struct sky1_clk_mux *to_sky1_clk_mux(struct clk_mux *mux)
581*3730fe60SJoakim Zhang {
582*3730fe60SJoakim Zhang return container_of(mux, struct sky1_clk_mux, mux);
583*3730fe60SJoakim Zhang }
584*3730fe60SJoakim Zhang
sky1_audss_clk_mux_get_parent(struct clk_hw * hw)585*3730fe60SJoakim Zhang static u8 sky1_audss_clk_mux_get_parent(struct clk_hw *hw)
586*3730fe60SJoakim Zhang {
587*3730fe60SJoakim Zhang struct clk_mux *mux = to_clk_mux(hw);
588*3730fe60SJoakim Zhang struct sky1_clk_mux *sky1_mux = to_sky1_clk_mux(mux);
589*3730fe60SJoakim Zhang u32 val;
590*3730fe60SJoakim Zhang
591*3730fe60SJoakim Zhang regmap_read(sky1_mux->regmap, sky1_mux->offset, &val);
592*3730fe60SJoakim Zhang val = val >> mux->shift;
593*3730fe60SJoakim Zhang val &= mux->mask;
594*3730fe60SJoakim Zhang
595*3730fe60SJoakim Zhang return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
596*3730fe60SJoakim Zhang }
597*3730fe60SJoakim Zhang
sky1_audss_clk_mux_set_parent(struct clk_hw * hw,u8 index)598*3730fe60SJoakim Zhang static int sky1_audss_clk_mux_set_parent(struct clk_hw *hw, u8 index)
599*3730fe60SJoakim Zhang {
600*3730fe60SJoakim Zhang struct clk_mux *mux = to_clk_mux(hw);
601*3730fe60SJoakim Zhang u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
602*3730fe60SJoakim Zhang struct sky1_clk_mux *sky1_mux = to_sky1_clk_mux(mux);
603*3730fe60SJoakim Zhang unsigned long flags = 0;
604*3730fe60SJoakim Zhang u32 reg;
605*3730fe60SJoakim Zhang
606*3730fe60SJoakim Zhang if (mux->lock)
607*3730fe60SJoakim Zhang spin_lock_irqsave(mux->lock, flags);
608*3730fe60SJoakim Zhang else
609*3730fe60SJoakim Zhang __acquire(mux->lock);
610*3730fe60SJoakim Zhang
611*3730fe60SJoakim Zhang if (mux->flags & CLK_MUX_HIWORD_MASK) {
612*3730fe60SJoakim Zhang reg = mux->mask << (mux->shift + 16);
613*3730fe60SJoakim Zhang } else {
614*3730fe60SJoakim Zhang regmap_read(sky1_mux->regmap, sky1_mux->offset, ®);
615*3730fe60SJoakim Zhang reg &= ~(mux->mask << mux->shift);
616*3730fe60SJoakim Zhang }
617*3730fe60SJoakim Zhang val = val << mux->shift;
618*3730fe60SJoakim Zhang reg |= val;
619*3730fe60SJoakim Zhang regmap_write(sky1_mux->regmap, sky1_mux->offset, reg);
620*3730fe60SJoakim Zhang
621*3730fe60SJoakim Zhang if (mux->lock)
622*3730fe60SJoakim Zhang spin_unlock_irqrestore(mux->lock, flags);
623*3730fe60SJoakim Zhang else
624*3730fe60SJoakim Zhang __release(mux->lock);
625*3730fe60SJoakim Zhang
626*3730fe60SJoakim Zhang return 0;
627*3730fe60SJoakim Zhang }
628*3730fe60SJoakim Zhang
sky1_audss_clk_mux_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)629*3730fe60SJoakim Zhang static int sky1_audss_clk_mux_determine_rate(struct clk_hw *hw,
630*3730fe60SJoakim Zhang struct clk_rate_request *req)
631*3730fe60SJoakim Zhang {
632*3730fe60SJoakim Zhang struct clk_mux *mux = to_clk_mux(hw);
633*3730fe60SJoakim Zhang
634*3730fe60SJoakim Zhang return clk_mux_determine_rate_flags(hw, req, mux->flags);
635*3730fe60SJoakim Zhang }
636*3730fe60SJoakim Zhang
637*3730fe60SJoakim Zhang static const struct clk_ops sky1_audss_clk_mux_ops = {
638*3730fe60SJoakim Zhang .get_parent = sky1_audss_clk_mux_get_parent,
639*3730fe60SJoakim Zhang .set_parent = sky1_audss_clk_mux_set_parent,
640*3730fe60SJoakim Zhang .determine_rate = sky1_audss_clk_mux_determine_rate,
641*3730fe60SJoakim Zhang };
642*3730fe60SJoakim Zhang
to_sky1_clk_divider(struct clk_divider * div)643*3730fe60SJoakim Zhang static inline struct sky1_clk_divider *to_sky1_clk_divider(struct clk_divider *div)
644*3730fe60SJoakim Zhang {
645*3730fe60SJoakim Zhang return container_of(div, struct sky1_clk_divider, div);
646*3730fe60SJoakim Zhang }
647*3730fe60SJoakim Zhang
sky1_audss_clk_divider_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)648*3730fe60SJoakim Zhang static unsigned long sky1_audss_clk_divider_recalc_rate(struct clk_hw *hw,
649*3730fe60SJoakim Zhang unsigned long parent_rate)
650*3730fe60SJoakim Zhang {
651*3730fe60SJoakim Zhang struct clk_divider *divider = to_clk_divider(hw);
652*3730fe60SJoakim Zhang struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
653*3730fe60SJoakim Zhang unsigned int val;
654*3730fe60SJoakim Zhang
655*3730fe60SJoakim Zhang regmap_read(sky1_div->regmap, sky1_div->offset, &val);
656*3730fe60SJoakim Zhang val = val >> divider->shift;
657*3730fe60SJoakim Zhang val &= clk_div_mask(divider->width);
658*3730fe60SJoakim Zhang
659*3730fe60SJoakim Zhang return divider_recalc_rate(hw, parent_rate, val, divider->table,
660*3730fe60SJoakim Zhang divider->flags, divider->width);
661*3730fe60SJoakim Zhang }
662*3730fe60SJoakim Zhang
sky1_audss_clk_divider_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)663*3730fe60SJoakim Zhang static int sky1_audss_clk_divider_determine_rate(struct clk_hw *hw,
664*3730fe60SJoakim Zhang struct clk_rate_request *req)
665*3730fe60SJoakim Zhang {
666*3730fe60SJoakim Zhang struct clk_divider *divider = to_clk_divider(hw);
667*3730fe60SJoakim Zhang struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
668*3730fe60SJoakim Zhang
669*3730fe60SJoakim Zhang /* if read only, just return current value */
670*3730fe60SJoakim Zhang if (divider->flags & CLK_DIVIDER_READ_ONLY) {
671*3730fe60SJoakim Zhang u32 val;
672*3730fe60SJoakim Zhang
673*3730fe60SJoakim Zhang regmap_read(sky1_div->regmap, sky1_div->offset, &val);
674*3730fe60SJoakim Zhang val = val >> divider->shift;
675*3730fe60SJoakim Zhang val &= clk_div_mask(divider->width);
676*3730fe60SJoakim Zhang
677*3730fe60SJoakim Zhang return divider_ro_determine_rate(hw, req, divider->table,
678*3730fe60SJoakim Zhang divider->width,
679*3730fe60SJoakim Zhang divider->flags, val);
680*3730fe60SJoakim Zhang }
681*3730fe60SJoakim Zhang
682*3730fe60SJoakim Zhang return divider_determine_rate(hw, req, divider->table, divider->width,
683*3730fe60SJoakim Zhang divider->flags);
684*3730fe60SJoakim Zhang }
685*3730fe60SJoakim Zhang
sky1_audss_clk_divider_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)686*3730fe60SJoakim Zhang static int sky1_audss_clk_divider_set_rate(struct clk_hw *hw,
687*3730fe60SJoakim Zhang unsigned long rate,
688*3730fe60SJoakim Zhang unsigned long parent_rate)
689*3730fe60SJoakim Zhang {
690*3730fe60SJoakim Zhang struct clk_divider *divider = to_clk_divider(hw);
691*3730fe60SJoakim Zhang struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
692*3730fe60SJoakim Zhang int value;
693*3730fe60SJoakim Zhang unsigned long flags = 0;
694*3730fe60SJoakim Zhang u32 val;
695*3730fe60SJoakim Zhang
696*3730fe60SJoakim Zhang value = divider_get_val(rate, parent_rate, divider->table,
697*3730fe60SJoakim Zhang divider->width, divider->flags);
698*3730fe60SJoakim Zhang if (value < 0)
699*3730fe60SJoakim Zhang return value;
700*3730fe60SJoakim Zhang
701*3730fe60SJoakim Zhang if (divider->lock)
702*3730fe60SJoakim Zhang spin_lock_irqsave(divider->lock, flags);
703*3730fe60SJoakim Zhang else
704*3730fe60SJoakim Zhang __acquire(divider->lock);
705*3730fe60SJoakim Zhang
706*3730fe60SJoakim Zhang if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
707*3730fe60SJoakim Zhang val = clk_div_mask(divider->width) << (divider->shift + 16);
708*3730fe60SJoakim Zhang } else {
709*3730fe60SJoakim Zhang regmap_read(sky1_div->regmap, sky1_div->offset, &val);
710*3730fe60SJoakim Zhang val &= ~(clk_div_mask(divider->width) << divider->shift);
711*3730fe60SJoakim Zhang }
712*3730fe60SJoakim Zhang val |= (u32)value << divider->shift;
713*3730fe60SJoakim Zhang regmap_write(sky1_div->regmap, sky1_div->offset, val);
714*3730fe60SJoakim Zhang
715*3730fe60SJoakim Zhang if (divider->lock)
716*3730fe60SJoakim Zhang spin_unlock_irqrestore(divider->lock, flags);
717*3730fe60SJoakim Zhang else
718*3730fe60SJoakim Zhang __release(divider->lock);
719*3730fe60SJoakim Zhang
720*3730fe60SJoakim Zhang return 0;
721*3730fe60SJoakim Zhang }
722*3730fe60SJoakim Zhang
723*3730fe60SJoakim Zhang static const struct clk_ops sky1_audss_clk_divider_ops = {
724*3730fe60SJoakim Zhang .recalc_rate = sky1_audss_clk_divider_recalc_rate,
725*3730fe60SJoakim Zhang .determine_rate = sky1_audss_clk_divider_determine_rate,
726*3730fe60SJoakim Zhang .set_rate = sky1_audss_clk_divider_set_rate,
727*3730fe60SJoakim Zhang };
728*3730fe60SJoakim Zhang
to_sky1_clk_gate(struct clk_gate * gate)729*3730fe60SJoakim Zhang static inline struct sky1_clk_gate *to_sky1_clk_gate(struct clk_gate *gate)
730*3730fe60SJoakim Zhang {
731*3730fe60SJoakim Zhang return container_of(gate, struct sky1_clk_gate, gate);
732*3730fe60SJoakim Zhang }
733*3730fe60SJoakim Zhang
sky1_audss_clk_gate_endisable(struct clk_hw * hw,int enable)734*3730fe60SJoakim Zhang static void sky1_audss_clk_gate_endisable(struct clk_hw *hw, int enable)
735*3730fe60SJoakim Zhang {
736*3730fe60SJoakim Zhang struct clk_gate *gate = to_clk_gate(hw);
737*3730fe60SJoakim Zhang struct sky1_clk_gate *sky1_gate = to_sky1_clk_gate(gate);
738*3730fe60SJoakim Zhang int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
739*3730fe60SJoakim Zhang unsigned long flags = 0;
740*3730fe60SJoakim Zhang u32 reg;
741*3730fe60SJoakim Zhang
742*3730fe60SJoakim Zhang set ^= enable;
743*3730fe60SJoakim Zhang
744*3730fe60SJoakim Zhang if (gate->lock)
745*3730fe60SJoakim Zhang spin_lock_irqsave(gate->lock, flags);
746*3730fe60SJoakim Zhang else
747*3730fe60SJoakim Zhang __acquire(gate->lock);
748*3730fe60SJoakim Zhang
749*3730fe60SJoakim Zhang if (gate->flags & CLK_GATE_HIWORD_MASK) {
750*3730fe60SJoakim Zhang reg = BIT(gate->bit_idx + 16);
751*3730fe60SJoakim Zhang if (set)
752*3730fe60SJoakim Zhang reg |= BIT(gate->bit_idx);
753*3730fe60SJoakim Zhang } else {
754*3730fe60SJoakim Zhang regmap_read(sky1_gate->regmap, sky1_gate->offset, ®);
755*3730fe60SJoakim Zhang
756*3730fe60SJoakim Zhang if (set)
757*3730fe60SJoakim Zhang reg |= BIT(gate->bit_idx);
758*3730fe60SJoakim Zhang else
759*3730fe60SJoakim Zhang reg &= ~BIT(gate->bit_idx);
760*3730fe60SJoakim Zhang }
761*3730fe60SJoakim Zhang
762*3730fe60SJoakim Zhang regmap_write(sky1_gate->regmap, sky1_gate->offset, reg);
763*3730fe60SJoakim Zhang
764*3730fe60SJoakim Zhang if (gate->lock)
765*3730fe60SJoakim Zhang spin_unlock_irqrestore(gate->lock, flags);
766*3730fe60SJoakim Zhang else
767*3730fe60SJoakim Zhang __release(gate->lock);
768*3730fe60SJoakim Zhang }
769*3730fe60SJoakim Zhang
sky1_audss_clk_gate_enable(struct clk_hw * hw)770*3730fe60SJoakim Zhang static int sky1_audss_clk_gate_enable(struct clk_hw *hw)
771*3730fe60SJoakim Zhang {
772*3730fe60SJoakim Zhang sky1_audss_clk_gate_endisable(hw, 1);
773*3730fe60SJoakim Zhang
774*3730fe60SJoakim Zhang return 0;
775*3730fe60SJoakim Zhang }
776*3730fe60SJoakim Zhang
sky1_audss_clk_gate_disable(struct clk_hw * hw)777*3730fe60SJoakim Zhang static void sky1_audss_clk_gate_disable(struct clk_hw *hw)
778*3730fe60SJoakim Zhang {
779*3730fe60SJoakim Zhang sky1_audss_clk_gate_endisable(hw, 0);
780*3730fe60SJoakim Zhang }
781*3730fe60SJoakim Zhang
sky1_audss_clk_gate_is_enabled(struct clk_hw * hw)782*3730fe60SJoakim Zhang static int sky1_audss_clk_gate_is_enabled(struct clk_hw *hw)
783*3730fe60SJoakim Zhang {
784*3730fe60SJoakim Zhang struct clk_gate *gate = to_clk_gate(hw);
785*3730fe60SJoakim Zhang struct sky1_clk_gate *sky1_gate = to_sky1_clk_gate(gate);
786*3730fe60SJoakim Zhang u32 reg;
787*3730fe60SJoakim Zhang
788*3730fe60SJoakim Zhang regmap_read(sky1_gate->regmap, sky1_gate->offset, ®);
789*3730fe60SJoakim Zhang
790*3730fe60SJoakim Zhang /* if a set bit disables this clk, flip it before masking */
791*3730fe60SJoakim Zhang if (gate->flags & CLK_GATE_SET_TO_DISABLE)
792*3730fe60SJoakim Zhang reg ^= BIT(gate->bit_idx);
793*3730fe60SJoakim Zhang
794*3730fe60SJoakim Zhang reg &= BIT(gate->bit_idx);
795*3730fe60SJoakim Zhang
796*3730fe60SJoakim Zhang return !!reg;
797*3730fe60SJoakim Zhang }
798*3730fe60SJoakim Zhang
799*3730fe60SJoakim Zhang static const struct clk_ops sky1_audss_clk_gate_ops = {
800*3730fe60SJoakim Zhang .enable = sky1_audss_clk_gate_enable,
801*3730fe60SJoakim Zhang .disable = sky1_audss_clk_gate_disable,
802*3730fe60SJoakim Zhang .is_enabled = sky1_audss_clk_gate_is_enabled,
803*3730fe60SJoakim Zhang };
804*3730fe60SJoakim Zhang
sky1_audss_clk_register(struct device * dev,const char * name,const char * const * parent_names,int num_parents,struct regmap * regmap,const u32 * mux_table,struct muxdiv_cfg * mux_cfg,struct muxdiv_cfg * div_cfg,struct gate_cfg * gate_cfg,unsigned long flags,spinlock_t * lock)805*3730fe60SJoakim Zhang static struct clk_hw *sky1_audss_clk_register(struct device *dev,
806*3730fe60SJoakim Zhang const char *name,
807*3730fe60SJoakim Zhang const char * const *parent_names,
808*3730fe60SJoakim Zhang int num_parents,
809*3730fe60SJoakim Zhang struct regmap *regmap,
810*3730fe60SJoakim Zhang const u32 *mux_table,
811*3730fe60SJoakim Zhang struct muxdiv_cfg *mux_cfg,
812*3730fe60SJoakim Zhang struct muxdiv_cfg *div_cfg,
813*3730fe60SJoakim Zhang struct gate_cfg *gate_cfg,
814*3730fe60SJoakim Zhang unsigned long flags,
815*3730fe60SJoakim Zhang spinlock_t *lock)
816*3730fe60SJoakim Zhang {
817*3730fe60SJoakim Zhang const struct clk_ops *sky1_gate_ops = NULL;
818*3730fe60SJoakim Zhang const struct clk_ops *sky1_mux_ops = NULL;
819*3730fe60SJoakim Zhang const struct clk_ops *sky1_div_ops = NULL;
820*3730fe60SJoakim Zhang struct sky1_clk_divider *sky1_div = NULL;
821*3730fe60SJoakim Zhang struct sky1_clk_gate *sky1_gate = NULL;
822*3730fe60SJoakim Zhang struct sky1_clk_mux *sky1_mux = NULL;
823*3730fe60SJoakim Zhang struct clk_hw *hw = ERR_PTR(-ENOMEM);
824*3730fe60SJoakim Zhang struct clk_parent_data *parent_data;
825*3730fe60SJoakim Zhang int i;
826*3730fe60SJoakim Zhang
827*3730fe60SJoakim Zhang parent_data = devm_kcalloc(dev, num_parents, sizeof(*parent_data), GFP_KERNEL);
828*3730fe60SJoakim Zhang if (!parent_data)
829*3730fe60SJoakim Zhang return ERR_PTR(-ENOMEM);
830*3730fe60SJoakim Zhang
831*3730fe60SJoakim Zhang for (i = 0; i < num_parents; i++)
832*3730fe60SJoakim Zhang parent_data[i].name = parent_names[i];
833*3730fe60SJoakim Zhang
834*3730fe60SJoakim Zhang if (mux_cfg->offset >= 0) {
835*3730fe60SJoakim Zhang sky1_mux = devm_kzalloc(dev, sizeof(*sky1_mux), GFP_KERNEL);
836*3730fe60SJoakim Zhang if (!sky1_mux)
837*3730fe60SJoakim Zhang return ERR_PTR(-ENOMEM);
838*3730fe60SJoakim Zhang
839*3730fe60SJoakim Zhang sky1_mux->mux.reg = NULL;
840*3730fe60SJoakim Zhang sky1_mux->mux.shift = mux_cfg->shift;
841*3730fe60SJoakim Zhang sky1_mux->mux.mask = BIT(mux_cfg->width) - 1;
842*3730fe60SJoakim Zhang sky1_mux->mux.flags = mux_cfg->flags;
843*3730fe60SJoakim Zhang sky1_mux->mux.table = mux_table;
844*3730fe60SJoakim Zhang sky1_mux->mux.lock = lock;
845*3730fe60SJoakim Zhang sky1_mux_ops = &sky1_audss_clk_mux_ops;
846*3730fe60SJoakim Zhang sky1_mux->regmap = regmap;
847*3730fe60SJoakim Zhang sky1_mux->offset = mux_cfg->offset;
848*3730fe60SJoakim Zhang }
849*3730fe60SJoakim Zhang
850*3730fe60SJoakim Zhang if (div_cfg->offset >= 0) {
851*3730fe60SJoakim Zhang sky1_div = devm_kzalloc(dev, sizeof(*sky1_div), GFP_KERNEL);
852*3730fe60SJoakim Zhang if (!sky1_div)
853*3730fe60SJoakim Zhang return ERR_PTR(-ENOMEM);
854*3730fe60SJoakim Zhang
855*3730fe60SJoakim Zhang sky1_div->div.reg = NULL;
856*3730fe60SJoakim Zhang sky1_div->div.shift = div_cfg->shift;
857*3730fe60SJoakim Zhang sky1_div->div.width = div_cfg->width;
858*3730fe60SJoakim Zhang sky1_div->div.flags = div_cfg->flags | CLK_DIVIDER_POWER_OF_TWO;
859*3730fe60SJoakim Zhang sky1_div->div.lock = lock;
860*3730fe60SJoakim Zhang sky1_div_ops = &sky1_audss_clk_divider_ops;
861*3730fe60SJoakim Zhang sky1_div->regmap = regmap;
862*3730fe60SJoakim Zhang sky1_div->offset = div_cfg->offset;
863*3730fe60SJoakim Zhang }
864*3730fe60SJoakim Zhang
865*3730fe60SJoakim Zhang if (gate_cfg->offset >= 0) {
866*3730fe60SJoakim Zhang sky1_gate = devm_kzalloc(dev, sizeof(*sky1_gate), GFP_KERNEL);
867*3730fe60SJoakim Zhang if (!sky1_gate)
868*3730fe60SJoakim Zhang return ERR_PTR(-ENOMEM);
869*3730fe60SJoakim Zhang
870*3730fe60SJoakim Zhang sky1_gate->gate.reg = NULL;
871*3730fe60SJoakim Zhang sky1_gate->gate.bit_idx = gate_cfg->shift;
872*3730fe60SJoakim Zhang sky1_gate->gate.flags = gate_cfg->flags;
873*3730fe60SJoakim Zhang sky1_gate->gate.lock = lock;
874*3730fe60SJoakim Zhang sky1_gate_ops = &sky1_audss_clk_gate_ops;
875*3730fe60SJoakim Zhang sky1_gate->regmap = regmap;
876*3730fe60SJoakim Zhang sky1_gate->offset = gate_cfg->offset;
877*3730fe60SJoakim Zhang }
878*3730fe60SJoakim Zhang
879*3730fe60SJoakim Zhang hw = devm_clk_hw_register_composite_pdata(dev, name, parent_data, num_parents,
880*3730fe60SJoakim Zhang sky1_mux ? &sky1_mux->mux.hw : NULL, sky1_mux_ops,
881*3730fe60SJoakim Zhang sky1_div ? &sky1_div->div.hw : NULL, sky1_div_ops,
882*3730fe60SJoakim Zhang sky1_gate ? &sky1_gate->gate.hw : NULL, sky1_gate_ops,
883*3730fe60SJoakim Zhang flags);
884*3730fe60SJoakim Zhang if (IS_ERR(hw)) {
885*3730fe60SJoakim Zhang dev_err(dev, "register %s clock failed with err = %ld\n",
886*3730fe60SJoakim Zhang name, PTR_ERR(hw));
887*3730fe60SJoakim Zhang return hw;
888*3730fe60SJoakim Zhang }
889*3730fe60SJoakim Zhang
890*3730fe60SJoakim Zhang return hw;
891*3730fe60SJoakim Zhang }
892*3730fe60SJoakim Zhang
sky1_audss_clks_get(struct sky1_audss_clks_priv * priv)893*3730fe60SJoakim Zhang static int sky1_audss_clks_get(struct sky1_audss_clks_priv *priv)
894*3730fe60SJoakim Zhang {
895*3730fe60SJoakim Zhang const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
896*3730fe60SJoakim Zhang int i;
897*3730fe60SJoakim Zhang
898*3730fe60SJoakim Zhang for (i = 0; i < devtype_data->clk_num; i++) {
899*3730fe60SJoakim Zhang priv->clks[i] = devm_clk_get(priv->dev, devtype_data->clk_names[i]);
900*3730fe60SJoakim Zhang if (IS_ERR(priv->clks[i]))
901*3730fe60SJoakim Zhang return dev_err_probe(priv->dev, PTR_ERR(priv->clks[i]),
902*3730fe60SJoakim Zhang "failed to get clock %s", devtype_data->clk_names[i]);
903*3730fe60SJoakim Zhang }
904*3730fe60SJoakim Zhang
905*3730fe60SJoakim Zhang return 0;
906*3730fe60SJoakim Zhang }
907*3730fe60SJoakim Zhang
sky1_audss_clks_enable(struct sky1_audss_clks_priv * priv)908*3730fe60SJoakim Zhang static int sky1_audss_clks_enable(struct sky1_audss_clks_priv *priv)
909*3730fe60SJoakim Zhang {
910*3730fe60SJoakim Zhang const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
911*3730fe60SJoakim Zhang int i, err;
912*3730fe60SJoakim Zhang
913*3730fe60SJoakim Zhang for (i = 0; i < devtype_data->clk_num; i++) {
914*3730fe60SJoakim Zhang err = clk_prepare_enable(priv->clks[i]);
915*3730fe60SJoakim Zhang if (err) {
916*3730fe60SJoakim Zhang dev_err(priv->dev, "failed to enable clock %s\n",
917*3730fe60SJoakim Zhang devtype_data->clk_names[i]);
918*3730fe60SJoakim Zhang goto err_clks;
919*3730fe60SJoakim Zhang }
920*3730fe60SJoakim Zhang }
921*3730fe60SJoakim Zhang
922*3730fe60SJoakim Zhang return 0;
923*3730fe60SJoakim Zhang
924*3730fe60SJoakim Zhang err_clks:
925*3730fe60SJoakim Zhang while (--i >= 0)
926*3730fe60SJoakim Zhang clk_disable_unprepare(priv->clks[i]);
927*3730fe60SJoakim Zhang
928*3730fe60SJoakim Zhang return err;
929*3730fe60SJoakim Zhang }
930*3730fe60SJoakim Zhang
sky1_audss_clks_disable(struct sky1_audss_clks_priv * priv)931*3730fe60SJoakim Zhang static void sky1_audss_clks_disable(struct sky1_audss_clks_priv *priv)
932*3730fe60SJoakim Zhang {
933*3730fe60SJoakim Zhang const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
934*3730fe60SJoakim Zhang int i;
935*3730fe60SJoakim Zhang
936*3730fe60SJoakim Zhang for (i = 0; i < devtype_data->clk_num; i++)
937*3730fe60SJoakim Zhang clk_disable_unprepare(priv->clks[i]);
938*3730fe60SJoakim Zhang }
939*3730fe60SJoakim Zhang
sky1_audss_clks_set_rate(struct sky1_audss_clks_priv * priv)940*3730fe60SJoakim Zhang static int sky1_audss_clks_set_rate(struct sky1_audss_clks_priv *priv)
941*3730fe60SJoakim Zhang {
942*3730fe60SJoakim Zhang const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
943*3730fe60SJoakim Zhang int i, err;
944*3730fe60SJoakim Zhang
945*3730fe60SJoakim Zhang for (i = 0; i < devtype_data->clk_num; i++) {
946*3730fe60SJoakim Zhang err = clk_set_rate(priv->clks[i], devtype_data->clk_rate_default[i]);
947*3730fe60SJoakim Zhang if (err) {
948*3730fe60SJoakim Zhang dev_err(priv->dev, "failed to set clock rate %s\n",
949*3730fe60SJoakim Zhang devtype_data->clk_names[i]);
950*3730fe60SJoakim Zhang return err;
951*3730fe60SJoakim Zhang }
952*3730fe60SJoakim Zhang }
953*3730fe60SJoakim Zhang
954*3730fe60SJoakim Zhang return 0;
955*3730fe60SJoakim Zhang }
956*3730fe60SJoakim Zhang
sky1_audss_clk_rpm_cleanup(void * data)957*3730fe60SJoakim Zhang static void sky1_audss_clk_rpm_cleanup(void *data)
958*3730fe60SJoakim Zhang {
959*3730fe60SJoakim Zhang pm_runtime_force_suspend(data);
960*3730fe60SJoakim Zhang }
961*3730fe60SJoakim Zhang
962*3730fe60SJoakim Zhang /* register sky1 audio subsystem clocks */
sky1_audss_clk_probe(struct platform_device * pdev)963*3730fe60SJoakim Zhang static int sky1_audss_clk_probe(struct platform_device *pdev)
964*3730fe60SJoakim Zhang {
965*3730fe60SJoakim Zhang const struct sky1_audss_clks_devtype_data *devtype_data;
966*3730fe60SJoakim Zhang struct sky1_audss_clks_priv *priv;
967*3730fe60SJoakim Zhang struct device *dev = &pdev->dev;
968*3730fe60SJoakim Zhang struct clk_hw **clk_table;
969*3730fe60SJoakim Zhang void __iomem *base;
970*3730fe60SJoakim Zhang int i, ret;
971*3730fe60SJoakim Zhang
972*3730fe60SJoakim Zhang devtype_data = device_get_match_data(dev);
973*3730fe60SJoakim Zhang if (!devtype_data)
974*3730fe60SJoakim Zhang return -ENODEV;
975*3730fe60SJoakim Zhang
976*3730fe60SJoakim Zhang priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
977*3730fe60SJoakim Zhang if (!priv)
978*3730fe60SJoakim Zhang return -ENOMEM;
979*3730fe60SJoakim Zhang
980*3730fe60SJoakim Zhang spin_lock_init(&priv->lock);
981*3730fe60SJoakim Zhang
982*3730fe60SJoakim Zhang priv->clk_data = devm_kzalloc(dev,
983*3730fe60SJoakim Zhang struct_size(priv->clk_data, hws, SKY1_AUDSS_NUM_CLKS),
984*3730fe60SJoakim Zhang GFP_KERNEL);
985*3730fe60SJoakim Zhang if (!priv->clk_data)
986*3730fe60SJoakim Zhang return -ENOMEM;
987*3730fe60SJoakim Zhang
988*3730fe60SJoakim Zhang priv->clk_data->num = SKY1_AUDSS_NUM_CLKS;
989*3730fe60SJoakim Zhang clk_table = priv->clk_data->hws;
990*3730fe60SJoakim Zhang
991*3730fe60SJoakim Zhang base = devm_platform_ioremap_resource(pdev, 0);
992*3730fe60SJoakim Zhang if (IS_ERR(base))
993*3730fe60SJoakim Zhang return PTR_ERR(base);
994*3730fe60SJoakim Zhang
995*3730fe60SJoakim Zhang priv->regmap_cru = devm_regmap_init_mmio(dev, base, &sky1_audss_regmap_config);
996*3730fe60SJoakim Zhang if (IS_ERR(priv->regmap_cru))
997*3730fe60SJoakim Zhang return dev_err_probe(dev, PTR_ERR(priv->regmap_cru),
998*3730fe60SJoakim Zhang "failed to initialize regmap\n");
999*3730fe60SJoakim Zhang
1000*3730fe60SJoakim Zhang priv->dev = dev;
1001*3730fe60SJoakim Zhang priv->devtype_data = devtype_data;
1002*3730fe60SJoakim Zhang
1003*3730fe60SJoakim Zhang priv->rst_noc = devm_reset_control_get_exclusive(dev, NULL);
1004*3730fe60SJoakim Zhang if (IS_ERR(priv->rst_noc))
1005*3730fe60SJoakim Zhang return dev_err_probe(dev, PTR_ERR(priv->rst_noc),
1006*3730fe60SJoakim Zhang "failed to get audss noc reset");
1007*3730fe60SJoakim Zhang
1008*3730fe60SJoakim Zhang platform_set_drvdata(pdev, priv);
1009*3730fe60SJoakim Zhang
1010*3730fe60SJoakim Zhang reset_control_assert(priv->rst_noc);
1011*3730fe60SJoakim Zhang
1012*3730fe60SJoakim Zhang ret = sky1_audss_clks_get(priv);
1013*3730fe60SJoakim Zhang if (ret)
1014*3730fe60SJoakim Zhang return ret;
1015*3730fe60SJoakim Zhang
1016*3730fe60SJoakim Zhang ret = sky1_audss_clks_enable(priv);
1017*3730fe60SJoakim Zhang if (ret)
1018*3730fe60SJoakim Zhang return ret;
1019*3730fe60SJoakim Zhang
1020*3730fe60SJoakim Zhang /* release noc reset after clock on */
1021*3730fe60SJoakim Zhang ret = reset_control_deassert(priv->rst_noc);
1022*3730fe60SJoakim Zhang if (ret) {
1023*3730fe60SJoakim Zhang sky1_audss_clks_disable(priv);
1024*3730fe60SJoakim Zhang return ret;
1025*3730fe60SJoakim Zhang }
1026*3730fe60SJoakim Zhang
1027*3730fe60SJoakim Zhang pm_runtime_get_noresume(dev);
1028*3730fe60SJoakim Zhang pm_runtime_set_active(dev);
1029*3730fe60SJoakim Zhang pm_runtime_enable(dev);
1030*3730fe60SJoakim Zhang
1031*3730fe60SJoakim Zhang /*
1032*3730fe60SJoakim Zhang * Register cleanup action before clocks/provider (released last under LIFO).
1033*3730fe60SJoakim Zhang */
1034*3730fe60SJoakim Zhang ret = devm_add_action_or_reset(dev, sky1_audss_clk_rpm_cleanup, dev);
1035*3730fe60SJoakim Zhang if (ret)
1036*3730fe60SJoakim Zhang return ret;
1037*3730fe60SJoakim Zhang
1038*3730fe60SJoakim Zhang ret = sky1_audss_clks_set_rate(priv);
1039*3730fe60SJoakim Zhang if (ret)
1040*3730fe60SJoakim Zhang goto fail_pm;
1041*3730fe60SJoakim Zhang
1042*3730fe60SJoakim Zhang /* audio_clk4 clock fixed divider */
1043*3730fe60SJoakim Zhang clk_table[CLK_AUD_CLK4_DIV2] =
1044*3730fe60SJoakim Zhang devm_clk_hw_register_fixed_factor(dev,
1045*3730fe60SJoakim Zhang "audio_clk4_div2",
1046*3730fe60SJoakim Zhang "audio_clk4",
1047*3730fe60SJoakim Zhang 0,
1048*3730fe60SJoakim Zhang 1, 2);
1049*3730fe60SJoakim Zhang if (IS_ERR(clk_table[CLK_AUD_CLK4_DIV2])) {
1050*3730fe60SJoakim Zhang ret = PTR_ERR(clk_table[CLK_AUD_CLK4_DIV2]);
1051*3730fe60SJoakim Zhang dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK4_DIV2, ret);
1052*3730fe60SJoakim Zhang goto fail_pm;
1053*3730fe60SJoakim Zhang }
1054*3730fe60SJoakim Zhang
1055*3730fe60SJoakim Zhang clk_table[CLK_AUD_CLK4_DIV4] =
1056*3730fe60SJoakim Zhang devm_clk_hw_register_fixed_factor(dev,
1057*3730fe60SJoakim Zhang "audio_clk4_div4",
1058*3730fe60SJoakim Zhang "audio_clk4",
1059*3730fe60SJoakim Zhang 0,
1060*3730fe60SJoakim Zhang 1, 4);
1061*3730fe60SJoakim Zhang if (IS_ERR(clk_table[CLK_AUD_CLK4_DIV4])) {
1062*3730fe60SJoakim Zhang ret = PTR_ERR(clk_table[CLK_AUD_CLK4_DIV4]);
1063*3730fe60SJoakim Zhang dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK4_DIV4, ret);
1064*3730fe60SJoakim Zhang goto fail_pm;
1065*3730fe60SJoakim Zhang }
1066*3730fe60SJoakim Zhang
1067*3730fe60SJoakim Zhang /* audio_clk5 clock fixed divider */
1068*3730fe60SJoakim Zhang clk_table[CLK_AUD_CLK5_DIV2] =
1069*3730fe60SJoakim Zhang devm_clk_hw_register_fixed_factor(dev,
1070*3730fe60SJoakim Zhang "audio_clk5_div2",
1071*3730fe60SJoakim Zhang "audio_clk5",
1072*3730fe60SJoakim Zhang 0,
1073*3730fe60SJoakim Zhang 1, 2);
1074*3730fe60SJoakim Zhang if (IS_ERR(clk_table[CLK_AUD_CLK5_DIV2])) {
1075*3730fe60SJoakim Zhang ret = PTR_ERR(clk_table[CLK_AUD_CLK5_DIV2]);
1076*3730fe60SJoakim Zhang dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK5_DIV2, ret);
1077*3730fe60SJoakim Zhang goto fail_pm;
1078*3730fe60SJoakim Zhang }
1079*3730fe60SJoakim Zhang
1080*3730fe60SJoakim Zhang for (i = 0; i < devtype_data->clk_cfg_size; i++) {
1081*3730fe60SJoakim Zhang clk_table[devtype_data->clk_cfg[i].id] =
1082*3730fe60SJoakim Zhang sky1_audss_clk_register(dev,
1083*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].name,
1084*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].parent_names,
1085*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].num_parents,
1086*3730fe60SJoakim Zhang priv->regmap_cru,
1087*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].mux_table,
1088*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].mux_cfg,
1089*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].div_cfg,
1090*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].gate_cfg,
1091*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].flags,
1092*3730fe60SJoakim Zhang &priv->lock);
1093*3730fe60SJoakim Zhang if (IS_ERR(clk_table[devtype_data->clk_cfg[i].id])) {
1094*3730fe60SJoakim Zhang ret = PTR_ERR(clk_table[devtype_data->clk_cfg[i].id]);
1095*3730fe60SJoakim Zhang dev_err(dev, "failed to register clock %d, ret:%d\n",
1096*3730fe60SJoakim Zhang devtype_data->clk_cfg[i].id, ret);
1097*3730fe60SJoakim Zhang goto fail_pm;
1098*3730fe60SJoakim Zhang }
1099*3730fe60SJoakim Zhang }
1100*3730fe60SJoakim Zhang
1101*3730fe60SJoakim Zhang ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, priv->clk_data);
1102*3730fe60SJoakim Zhang if (ret) {
1103*3730fe60SJoakim Zhang dev_err(dev, "failed to add clock provider: %d\n", ret);
1104*3730fe60SJoakim Zhang goto fail_pm;
1105*3730fe60SJoakim Zhang }
1106*3730fe60SJoakim Zhang
1107*3730fe60SJoakim Zhang ret = sky1_audss_reset_controller_register(dev);
1108*3730fe60SJoakim Zhang if (ret) {
1109*3730fe60SJoakim Zhang dev_err(dev, "failed to register reset controller: %d\n", ret);
1110*3730fe60SJoakim Zhang goto fail_pm;
1111*3730fe60SJoakim Zhang }
1112*3730fe60SJoakim Zhang
1113*3730fe60SJoakim Zhang pm_runtime_put_sync(dev);
1114*3730fe60SJoakim Zhang
1115*3730fe60SJoakim Zhang return 0;
1116*3730fe60SJoakim Zhang
1117*3730fe60SJoakim Zhang fail_pm:
1118*3730fe60SJoakim Zhang pm_runtime_put_sync(dev);
1119*3730fe60SJoakim Zhang return ret;
1120*3730fe60SJoakim Zhang }
1121*3730fe60SJoakim Zhang
sky1_audss_clk_runtime_suspend(struct device * dev)1122*3730fe60SJoakim Zhang static int __maybe_unused sky1_audss_clk_runtime_suspend(struct device *dev)
1123*3730fe60SJoakim Zhang {
1124*3730fe60SJoakim Zhang struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev);
1125*3730fe60SJoakim Zhang const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
1126*3730fe60SJoakim Zhang unsigned long flags;
1127*3730fe60SJoakim Zhang int i;
1128*3730fe60SJoakim Zhang
1129*3730fe60SJoakim Zhang spin_lock_irqsave(&priv->lock, flags);
1130*3730fe60SJoakim Zhang for (i = 0; i < devtype_data->reg_save_size; i++)
1131*3730fe60SJoakim Zhang regmap_read(priv->regmap_cru,
1132*3730fe60SJoakim Zhang devtype_data->reg_save[i][0], &devtype_data->reg_save[i][1]);
1133*3730fe60SJoakim Zhang spin_unlock_irqrestore(&priv->lock, flags);
1134*3730fe60SJoakim Zhang
1135*3730fe60SJoakim Zhang reset_control_assert(priv->rst_noc);
1136*3730fe60SJoakim Zhang
1137*3730fe60SJoakim Zhang sky1_audss_clks_disable(priv);
1138*3730fe60SJoakim Zhang
1139*3730fe60SJoakim Zhang return 0;
1140*3730fe60SJoakim Zhang }
1141*3730fe60SJoakim Zhang
sky1_audss_clk_runtime_resume(struct device * dev)1142*3730fe60SJoakim Zhang static int __maybe_unused sky1_audss_clk_runtime_resume(struct device *dev)
1143*3730fe60SJoakim Zhang {
1144*3730fe60SJoakim Zhang struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev);
1145*3730fe60SJoakim Zhang const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
1146*3730fe60SJoakim Zhang unsigned long flags;
1147*3730fe60SJoakim Zhang int i, ret;
1148*3730fe60SJoakim Zhang
1149*3730fe60SJoakim Zhang ret = sky1_audss_clks_enable(priv);
1150*3730fe60SJoakim Zhang if (ret) {
1151*3730fe60SJoakim Zhang dev_err(dev, "failed to enable clocks\n");
1152*3730fe60SJoakim Zhang return ret;
1153*3730fe60SJoakim Zhang }
1154*3730fe60SJoakim Zhang
1155*3730fe60SJoakim Zhang ret = reset_control_deassert(priv->rst_noc);
1156*3730fe60SJoakim Zhang if (ret) {
1157*3730fe60SJoakim Zhang sky1_audss_clks_disable(priv);
1158*3730fe60SJoakim Zhang return ret;
1159*3730fe60SJoakim Zhang }
1160*3730fe60SJoakim Zhang
1161*3730fe60SJoakim Zhang spin_lock_irqsave(&priv->lock, flags);
1162*3730fe60SJoakim Zhang for (i = 0; i < devtype_data->reg_save_size; i++)
1163*3730fe60SJoakim Zhang regmap_write(priv->regmap_cru,
1164*3730fe60SJoakim Zhang devtype_data->reg_save[i][0], devtype_data->reg_save[i][1]);
1165*3730fe60SJoakim Zhang spin_unlock_irqrestore(&priv->lock, flags);
1166*3730fe60SJoakim Zhang
1167*3730fe60SJoakim Zhang return 0;
1168*3730fe60SJoakim Zhang }
1169*3730fe60SJoakim Zhang
1170*3730fe60SJoakim Zhang static const struct dev_pm_ops sky1_audss_clk_pm_ops = {
1171*3730fe60SJoakim Zhang SET_RUNTIME_PM_OPS(sky1_audss_clk_runtime_suspend,
1172*3730fe60SJoakim Zhang sky1_audss_clk_runtime_resume, NULL)
1173*3730fe60SJoakim Zhang SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1174*3730fe60SJoakim Zhang pm_runtime_force_resume)
1175*3730fe60SJoakim Zhang };
1176*3730fe60SJoakim Zhang
1177*3730fe60SJoakim Zhang static const struct sky1_audss_clks_devtype_data sky1_devtype_data = {
1178*3730fe60SJoakim Zhang .reg_save = sky1_reg_save,
1179*3730fe60SJoakim Zhang .reg_save_size = ARRAY_SIZE(sky1_reg_save),
1180*3730fe60SJoakim Zhang .clk_names = sky1_audss_clk_names,
1181*3730fe60SJoakim Zhang .clk_num = ARRAY_SIZE(sky1_audss_clk_names),
1182*3730fe60SJoakim Zhang .clk_rate_default = sky1_clk_rate_default,
1183*3730fe60SJoakim Zhang .clk_cfg = sky1_audss_clks,
1184*3730fe60SJoakim Zhang .clk_cfg_size = ARRAY_SIZE(sky1_audss_clks),
1185*3730fe60SJoakim Zhang };
1186*3730fe60SJoakim Zhang
1187*3730fe60SJoakim Zhang static const struct of_device_id sky1_audss_clk_of_match[] = {
1188*3730fe60SJoakim Zhang { .compatible = "cix,sky1-audss-cru", .data = &sky1_devtype_data, },
1189*3730fe60SJoakim Zhang { /* sentinel */ },
1190*3730fe60SJoakim Zhang };
1191*3730fe60SJoakim Zhang MODULE_DEVICE_TABLE(of, sky1_audss_clk_of_match);
1192*3730fe60SJoakim Zhang
1193*3730fe60SJoakim Zhang static struct platform_driver sky1_audss_clk_driver = {
1194*3730fe60SJoakim Zhang .probe = sky1_audss_clk_probe,
1195*3730fe60SJoakim Zhang .driver = {
1196*3730fe60SJoakim Zhang .name = "sky1-audss-clk",
1197*3730fe60SJoakim Zhang .suppress_bind_attrs = true,
1198*3730fe60SJoakim Zhang .of_match_table = sky1_audss_clk_of_match,
1199*3730fe60SJoakim Zhang .pm = pm_ptr(&sky1_audss_clk_pm_ops),
1200*3730fe60SJoakim Zhang },
1201*3730fe60SJoakim Zhang };
1202*3730fe60SJoakim Zhang module_platform_driver(sky1_audss_clk_driver);
1203*3730fe60SJoakim Zhang
1204*3730fe60SJoakim Zhang MODULE_LICENSE("GPL");
1205*3730fe60SJoakim Zhang MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
1206*3730fe60SJoakim Zhang MODULE_DESCRIPTION("Cixtech Sky1 Audio Subsystem Clock Controller Driver");
1207