1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright(c) 2015-17 Intel Corporation
5 * skl-ssp-clk.c - ASoC skylake ssp clock driver
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/err.h>
11 #include <linux/platform_device.h>
12 #include <linux/clk-provider.h>
13 #include <linux/clkdev.h>
14 #include <sound/intel-nhlt.h>
16 #include "skl-ssp-clk.h"
17 #include "skl-topology.h"
19 #define to_skl_clk(_hw) container_of(_hw, struct skl_clk, hw)
21 struct skl_clk_parent
{
23 struct clk_lookup
*lookup
;
28 struct clk_lookup
*lookup
;
30 struct skl_clk_pdata
*pdata
;
35 struct skl_clk_parent parent
[SKL_MAX_CLK_SRC
];
36 struct skl_clk
*clk
[SKL_MAX_CLK_CNT
];
40 static int skl_get_clk_type(u32 index
)
43 case 0 ... (SKL_SCLK_OFS
- 1):
46 case SKL_SCLK_OFS
... (SKL_SCLKFS_OFS
- 1):
49 case SKL_SCLKFS_OFS
... (SKL_MAX_CLK_CNT
- 1):
57 static int skl_get_vbus_id(u32 index
, u8 clk_type
)
64 return index
- SKL_SCLK_OFS
;
67 return index
- SKL_SCLKFS_OFS
;
74 static void skl_fill_clk_ipc(struct skl_clk_rate_cfg_table
*rcfg
, u8 clk_type
)
76 struct nhlt_fmt_cfg
*fmt_cfg
;
77 union skl_clk_ctrl_ipc
*ipc
;
83 ipc
= &rcfg
->dma_ctl_ipc
;
84 if (clk_type
== SKL_SCLK_FS
) {
85 fmt_cfg
= (struct nhlt_fmt_cfg
*)rcfg
->config
;
86 wfmt
= &fmt_cfg
->fmt_ext
.fmt
;
88 /* Remove TLV Header size */
89 ipc
->sclk_fs
.hdr
.size
= sizeof(struct skl_dmactrl_sclkfs_cfg
) -
90 sizeof(struct skl_tlv_hdr
);
91 ipc
->sclk_fs
.sampling_frequency
= wfmt
->samples_per_sec
;
92 ipc
->sclk_fs
.bit_depth
= wfmt
->bits_per_sample
;
93 ipc
->sclk_fs
.valid_bit_depth
=
94 fmt_cfg
->fmt_ext
.sample
.valid_bits_per_sample
;
95 ipc
->sclk_fs
.number_of_channels
= wfmt
->channels
;
97 ipc
->mclk
.hdr
.type
= DMA_CLK_CONTROLS
;
98 /* Remove TLV Header size */
99 ipc
->mclk
.hdr
.size
= sizeof(struct skl_dmactrl_mclk_cfg
) -
100 sizeof(struct skl_tlv_hdr
);
104 /* Sends dma control IPC to turn the clock ON/OFF */
105 static int skl_send_clk_dma_control(struct skl_dev
*skl
,
106 struct skl_clk_rate_cfg_table
*rcfg
,
107 u32 vbus_id
, u8 clk_type
,
110 struct nhlt_specific_cfg
*sp_cfg
;
111 u32 i2s_config_size
, node_id
= 0;
112 struct nhlt_fmt_cfg
*fmt_cfg
;
113 union skl_clk_ctrl_ipc
*ipc
;
114 void *i2s_config
= NULL
;
121 ipc
= &rcfg
->dma_ctl_ipc
;
122 fmt_cfg
= (struct nhlt_fmt_cfg
*)rcfg
->config
;
123 sp_cfg
= &fmt_cfg
->config
;
125 if (clk_type
== SKL_SCLK_FS
) {
126 ipc
->sclk_fs
.hdr
.type
=
127 enable
? DMA_TRANSMITION_START
: DMA_TRANSMITION_STOP
;
128 data
= (u8
*)&ipc
->sclk_fs
;
129 size
= sizeof(struct skl_dmactrl_sclkfs_cfg
);
131 /* 1 to enable mclk, 0 to enable sclk */
132 if (clk_type
== SKL_SCLK
)
137 ipc
->mclk
.keep_running
= enable
;
138 ipc
->mclk
.warm_up_over
= enable
;
139 ipc
->mclk
.clk_stop_over
= !enable
;
140 data
= (u8
*)&ipc
->mclk
;
141 size
= sizeof(struct skl_dmactrl_mclk_cfg
);
144 i2s_config_size
= sp_cfg
->size
+ size
;
145 i2s_config
= kzalloc(i2s_config_size
, GFP_KERNEL
);
150 memcpy(i2s_config
, sp_cfg
->caps
, sp_cfg
->size
);
152 /* copy additional dma controls information */
153 memcpy(i2s_config
+ sp_cfg
->size
, data
, size
);
155 node_id
= ((SKL_DMA_I2S_LINK_INPUT_CLASS
<< 8) | (vbus_id
<< 4));
156 ret
= skl_dsp_set_dma_control(skl
, (u32
*)i2s_config
,
157 i2s_config_size
, node_id
);
163 static struct skl_clk_rate_cfg_table
*skl_get_rate_cfg(
164 struct skl_clk_rate_cfg_table
*rcfg
,
169 for (i
= 0; (i
< SKL_MAX_CLK_RATES
) && rcfg
[i
].rate
; i
++) {
170 if (rcfg
[i
].rate
== rate
)
177 static int skl_clk_change_status(struct skl_clk
*clkdev
,
180 struct skl_clk_rate_cfg_table
*rcfg
;
181 int vbus_id
, clk_type
;
183 clk_type
= skl_get_clk_type(clkdev
->id
);
187 vbus_id
= skl_get_vbus_id(clkdev
->id
, clk_type
);
191 rcfg
= skl_get_rate_cfg(clkdev
->pdata
->ssp_clks
[clkdev
->id
].rate_cfg
,
196 return skl_send_clk_dma_control(clkdev
->pdata
->pvt_data
, rcfg
,
197 vbus_id
, clk_type
, enable
);
200 static int skl_clk_prepare(struct clk_hw
*hw
)
202 struct skl_clk
*clkdev
= to_skl_clk(hw
);
204 return skl_clk_change_status(clkdev
, true);
207 static void skl_clk_unprepare(struct clk_hw
*hw
)
209 struct skl_clk
*clkdev
= to_skl_clk(hw
);
211 skl_clk_change_status(clkdev
, false);
214 static int skl_clk_set_rate(struct clk_hw
*hw
, unsigned long rate
,
215 unsigned long parent_rate
)
217 struct skl_clk
*clkdev
= to_skl_clk(hw
);
218 struct skl_clk_rate_cfg_table
*rcfg
;
224 rcfg
= skl_get_rate_cfg(clkdev
->pdata
->ssp_clks
[clkdev
->id
].rate_cfg
,
229 clk_type
= skl_get_clk_type(clkdev
->id
);
233 skl_fill_clk_ipc(rcfg
, clk_type
);
239 static unsigned long skl_clk_recalc_rate(struct clk_hw
*hw
,
240 unsigned long parent_rate
)
242 struct skl_clk
*clkdev
= to_skl_clk(hw
);
250 /* Not supported by clk driver. Implemented to satisfy clk fw */
251 static long skl_clk_round_rate(struct clk_hw
*hw
, unsigned long rate
,
252 unsigned long *parent_rate
)
258 * prepare/unprepare are used instead of enable/disable as IPC will be sent
259 * in non-atomic context.
261 static const struct clk_ops skl_clk_ops
= {
262 .prepare
= skl_clk_prepare
,
263 .unprepare
= skl_clk_unprepare
,
264 .set_rate
= skl_clk_set_rate
,
265 .round_rate
= skl_clk_round_rate
,
266 .recalc_rate
= skl_clk_recalc_rate
,
269 static void unregister_parent_src_clk(struct skl_clk_parent
*pclk
,
273 clkdev_drop(pclk
[id
].lookup
);
274 clk_hw_unregister_fixed_rate(pclk
[id
].hw
);
278 static void unregister_src_clk(struct skl_clk_data
*dclk
)
280 while (dclk
->avail_clk_cnt
--)
281 clkdev_drop(dclk
->clk
[dclk
->avail_clk_cnt
]->lookup
);
284 static int skl_register_parent_clks(struct device
*dev
,
285 struct skl_clk_parent
*parent
,
286 struct skl_clk_parent_src
*pclk
)
290 for (i
= 0; i
< SKL_MAX_CLK_SRC
; i
++) {
292 /* Register Parent clock */
293 parent
[i
].hw
= clk_hw_register_fixed_rate(dev
, pclk
[i
].name
,
294 pclk
[i
].parent_name
, 0, pclk
[i
].rate
);
295 if (IS_ERR(parent
[i
].hw
)) {
296 ret
= PTR_ERR(parent
[i
].hw
);
300 parent
[i
].lookup
= clkdev_hw_create(parent
[i
].hw
, pclk
[i
].name
,
302 if (!parent
[i
].lookup
) {
303 clk_hw_unregister_fixed_rate(parent
[i
].hw
);
311 unregister_parent_src_clk(parent
, i
);
315 /* Assign fmt_config to clk_data */
316 static struct skl_clk
*register_skl_clk(struct device
*dev
,
317 struct skl_ssp_clk
*clk
,
318 struct skl_clk_pdata
*clk_pdata
, int id
)
320 struct clk_init_data init
;
321 struct skl_clk
*clkdev
;
324 clkdev
= devm_kzalloc(dev
, sizeof(*clkdev
), GFP_KERNEL
);
326 return ERR_PTR(-ENOMEM
);
328 init
.name
= clk
->name
;
329 init
.ops
= &skl_clk_ops
;
330 init
.flags
= CLK_SET_RATE_GATE
;
331 init
.parent_names
= &clk
->parent_name
;
332 init
.num_parents
= 1;
333 clkdev
->hw
.init
= &init
;
334 clkdev
->pdata
= clk_pdata
;
337 ret
= devm_clk_hw_register(dev
, &clkdev
->hw
);
339 clkdev
= ERR_PTR(ret
);
343 clkdev
->lookup
= clkdev_hw_create(&clkdev
->hw
, init
.name
, NULL
);
345 clkdev
= ERR_PTR(-ENOMEM
);
350 static int skl_clk_dev_probe(struct platform_device
*pdev
)
352 struct device
*dev
= &pdev
->dev
;
353 struct device
*parent_dev
= dev
->parent
;
354 struct skl_clk_parent_src
*parent_clks
;
355 struct skl_clk_pdata
*clk_pdata
;
356 struct skl_clk_data
*data
;
357 struct skl_ssp_clk
*clks
;
360 clk_pdata
= dev_get_platdata(&pdev
->dev
);
361 parent_clks
= clk_pdata
->parent_clks
;
362 clks
= clk_pdata
->ssp_clks
;
363 if (!parent_clks
|| !clks
)
366 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
370 /* Register Parent clock */
371 ret
= skl_register_parent_clks(parent_dev
, data
->parent
, parent_clks
);
375 for (i
= 0; i
< clk_pdata
->num_clks
; i
++) {
377 * Only register valid clocks
378 * i.e. for which nhlt entry is present.
380 if (clks
[i
].rate_cfg
[0].rate
== 0)
383 data
->clk
[data
->avail_clk_cnt
] = register_skl_clk(dev
,
384 &clks
[i
], clk_pdata
, i
);
386 if (IS_ERR(data
->clk
[data
->avail_clk_cnt
])) {
387 ret
= PTR_ERR(data
->clk
[data
->avail_clk_cnt
++]);
388 goto err_unreg_skl_clk
;
392 platform_set_drvdata(pdev
, data
);
397 unregister_src_clk(data
);
398 unregister_parent_src_clk(data
->parent
, SKL_MAX_CLK_SRC
);
403 static int skl_clk_dev_remove(struct platform_device
*pdev
)
405 struct skl_clk_data
*data
;
407 data
= platform_get_drvdata(pdev
);
408 unregister_src_clk(data
);
409 unregister_parent_src_clk(data
->parent
, SKL_MAX_CLK_SRC
);
414 static struct platform_driver skl_clk_driver
= {
416 .name
= "skl-ssp-clk",
418 .probe
= skl_clk_dev_probe
,
419 .remove
= skl_clk_dev_remove
,
422 module_platform_driver(skl_clk_driver
);
424 MODULE_DESCRIPTION("Skylake clock driver");
425 MODULE_AUTHOR("Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>");
426 MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
427 MODULE_LICENSE("GPL v2");
428 MODULE_ALIAS("platform:skl-ssp-clk");