treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / sound / soc / intel / skylake / skl-ssp-clk.c
blob1c0e5226cb5b6b18c72c3f75721a6f38426fb43c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright(c) 2015-17 Intel Corporation
4 /*
5 * skl-ssp-clk.c - ASoC skylake ssp clock driver
6 */
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>
15 #include "skl.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 {
22 struct clk_hw *hw;
23 struct clk_lookup *lookup;
26 struct skl_clk {
27 struct clk_hw hw;
28 struct clk_lookup *lookup;
29 unsigned long rate;
30 struct skl_clk_pdata *pdata;
31 u32 id;
34 struct skl_clk_data {
35 struct skl_clk_parent parent[SKL_MAX_CLK_SRC];
36 struct skl_clk *clk[SKL_MAX_CLK_CNT];
37 u8 avail_clk_cnt;
40 static int skl_get_clk_type(u32 index)
42 switch (index) {
43 case 0 ... (SKL_SCLK_OFS - 1):
44 return SKL_MCLK;
46 case SKL_SCLK_OFS ... (SKL_SCLKFS_OFS - 1):
47 return SKL_SCLK;
49 case SKL_SCLKFS_OFS ... (SKL_MAX_CLK_CNT - 1):
50 return SKL_SCLK_FS;
52 default:
53 return -EINVAL;
57 static int skl_get_vbus_id(u32 index, u8 clk_type)
59 switch (clk_type) {
60 case SKL_MCLK:
61 return index;
63 case SKL_SCLK:
64 return index - SKL_SCLK_OFS;
66 case SKL_SCLK_FS:
67 return index - SKL_SCLKFS_OFS;
69 default:
70 return -EINVAL;
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;
78 struct wav_fmt *wfmt;
80 if (!rcfg)
81 return;
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;
96 } else {
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,
108 bool enable)
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;
115 u8 *data, size;
116 int ret;
118 if (!rcfg)
119 return -EIO;
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);
130 } else {
131 /* 1 to enable mclk, 0 to enable sclk */
132 if (clk_type == SKL_SCLK)
133 ipc->mclk.mclk = 0;
134 else
135 ipc->mclk.mclk = 1;
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);
146 if (!i2s_config)
147 return -ENOMEM;
149 /* copy blob */
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);
158 kfree(i2s_config);
160 return ret;
163 static struct skl_clk_rate_cfg_table *skl_get_rate_cfg(
164 struct skl_clk_rate_cfg_table *rcfg,
165 unsigned long rate)
167 int i;
169 for (i = 0; (i < SKL_MAX_CLK_RATES) && rcfg[i].rate; i++) {
170 if (rcfg[i].rate == rate)
171 return &rcfg[i];
174 return NULL;
177 static int skl_clk_change_status(struct skl_clk *clkdev,
178 bool enable)
180 struct skl_clk_rate_cfg_table *rcfg;
181 int vbus_id, clk_type;
183 clk_type = skl_get_clk_type(clkdev->id);
184 if (clk_type < 0)
185 return clk_type;
187 vbus_id = skl_get_vbus_id(clkdev->id, clk_type);
188 if (vbus_id < 0)
189 return vbus_id;
191 rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg,
192 clkdev->rate);
193 if (!rcfg)
194 return -EINVAL;
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;
219 int clk_type;
221 if (!rate)
222 return -EINVAL;
224 rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg,
225 rate);
226 if (!rcfg)
227 return -EINVAL;
229 clk_type = skl_get_clk_type(clkdev->id);
230 if (clk_type < 0)
231 return clk_type;
233 skl_fill_clk_ipc(rcfg, clk_type);
234 clkdev->rate = rate;
236 return 0;
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);
244 if (clkdev->rate)
245 return clkdev->rate;
247 return 0;
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)
254 return 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,
270 unsigned int id)
272 while (id--) {
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)
288 int i, ret;
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);
297 goto err;
300 parent[i].lookup = clkdev_hw_create(parent[i].hw, pclk[i].name,
301 NULL);
302 if (!parent[i].lookup) {
303 clk_hw_unregister_fixed_rate(parent[i].hw);
304 ret = -ENOMEM;
305 goto err;
309 return 0;
310 err:
311 unregister_parent_src_clk(parent, i);
312 return ret;
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;
322 int ret;
324 clkdev = devm_kzalloc(dev, sizeof(*clkdev), GFP_KERNEL);
325 if (!clkdev)
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;
336 clkdev->id = id;
337 ret = devm_clk_hw_register(dev, &clkdev->hw);
338 if (ret) {
339 clkdev = ERR_PTR(ret);
340 return clkdev;
343 clkdev->lookup = clkdev_hw_create(&clkdev->hw, init.name, NULL);
344 if (!clkdev->lookup)
345 clkdev = ERR_PTR(-ENOMEM);
347 return clkdev;
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;
358 int ret, i;
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)
364 return -EIO;
366 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
367 if (!data)
368 return -ENOMEM;
370 /* Register Parent clock */
371 ret = skl_register_parent_clks(parent_dev, data->parent, parent_clks);
372 if (ret < 0)
373 return ret;
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)
381 continue;
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);
394 return 0;
396 err_unreg_skl_clk:
397 unregister_src_clk(data);
398 unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC);
400 return ret;
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);
411 return 0;
414 static struct platform_driver skl_clk_driver = {
415 .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");