skl-ssp-clk.c (9729B)
1// SPDX-License-Identifier: GPL-2.0-only 2// Copyright(c) 2015-17 Intel Corporation 3 4/* 5 * skl-ssp-clk.c - ASoC skylake ssp clock driver 6 */ 7 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" 18 19#define to_skl_clk(_hw) container_of(_hw, struct skl_clk, hw) 20 21struct skl_clk_parent { 22 struct clk_hw *hw; 23 struct clk_lookup *lookup; 24}; 25 26struct 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; 32}; 33 34struct 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; 38}; 39 40static int skl_get_clk_type(u32 index) 41{ 42 switch (index) { 43 case 0 ... (SKL_SCLK_OFS - 1): 44 return SKL_MCLK; 45 46 case SKL_SCLK_OFS ... (SKL_SCLKFS_OFS - 1): 47 return SKL_SCLK; 48 49 case SKL_SCLKFS_OFS ... (SKL_MAX_CLK_CNT - 1): 50 return SKL_SCLK_FS; 51 52 default: 53 return -EINVAL; 54 } 55} 56 57static int skl_get_vbus_id(u32 index, u8 clk_type) 58{ 59 switch (clk_type) { 60 case SKL_MCLK: 61 return index; 62 63 case SKL_SCLK: 64 return index - SKL_SCLK_OFS; 65 66 case SKL_SCLK_FS: 67 return index - SKL_SCLKFS_OFS; 68 69 default: 70 return -EINVAL; 71 } 72} 73 74static void skl_fill_clk_ipc(struct skl_clk_rate_cfg_table *rcfg, u8 clk_type) 75{ 76 struct nhlt_fmt_cfg *fmt_cfg; 77 union skl_clk_ctrl_ipc *ipc; 78 struct wav_fmt *wfmt; 79 80 if (!rcfg) 81 return; 82 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; 87 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); 101 } 102} 103 104/* Sends dma control IPC to turn the clock ON/OFF */ 105static 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) 109{ 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; 117 118 if (!rcfg) 119 return -EIO; 120 121 ipc = &rcfg->dma_ctl_ipc; 122 fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config; 123 sp_cfg = &fmt_cfg->config; 124 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; 136 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); 142 } 143 144 i2s_config_size = sp_cfg->size + size; 145 i2s_config = kzalloc(i2s_config_size, GFP_KERNEL); 146 if (!i2s_config) 147 return -ENOMEM; 148 149 /* copy blob */ 150 memcpy(i2s_config, sp_cfg->caps, sp_cfg->size); 151 152 /* copy additional dma controls information */ 153 memcpy(i2s_config + sp_cfg->size, data, size); 154 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); 159 160 return ret; 161} 162 163static struct skl_clk_rate_cfg_table *skl_get_rate_cfg( 164 struct skl_clk_rate_cfg_table *rcfg, 165 unsigned long rate) 166{ 167 int i; 168 169 for (i = 0; (i < SKL_MAX_CLK_RATES) && rcfg[i].rate; i++) { 170 if (rcfg[i].rate == rate) 171 return &rcfg[i]; 172 } 173 174 return NULL; 175} 176 177static int skl_clk_change_status(struct skl_clk *clkdev, 178 bool enable) 179{ 180 struct skl_clk_rate_cfg_table *rcfg; 181 int vbus_id, clk_type; 182 183 clk_type = skl_get_clk_type(clkdev->id); 184 if (clk_type < 0) 185 return clk_type; 186 187 vbus_id = skl_get_vbus_id(clkdev->id, clk_type); 188 if (vbus_id < 0) 189 return vbus_id; 190 191 rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg, 192 clkdev->rate); 193 if (!rcfg) 194 return -EINVAL; 195 196 return skl_send_clk_dma_control(clkdev->pdata->pvt_data, rcfg, 197 vbus_id, clk_type, enable); 198} 199 200static int skl_clk_prepare(struct clk_hw *hw) 201{ 202 struct skl_clk *clkdev = to_skl_clk(hw); 203 204 return skl_clk_change_status(clkdev, true); 205} 206 207static void skl_clk_unprepare(struct clk_hw *hw) 208{ 209 struct skl_clk *clkdev = to_skl_clk(hw); 210 211 skl_clk_change_status(clkdev, false); 212} 213 214static int skl_clk_set_rate(struct clk_hw *hw, unsigned long rate, 215 unsigned long parent_rate) 216{ 217 struct skl_clk *clkdev = to_skl_clk(hw); 218 struct skl_clk_rate_cfg_table *rcfg; 219 int clk_type; 220 221 if (!rate) 222 return -EINVAL; 223 224 rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg, 225 rate); 226 if (!rcfg) 227 return -EINVAL; 228 229 clk_type = skl_get_clk_type(clkdev->id); 230 if (clk_type < 0) 231 return clk_type; 232 233 skl_fill_clk_ipc(rcfg, clk_type); 234 clkdev->rate = rate; 235 236 return 0; 237} 238 239static unsigned long skl_clk_recalc_rate(struct clk_hw *hw, 240 unsigned long parent_rate) 241{ 242 struct skl_clk *clkdev = to_skl_clk(hw); 243 244 if (clkdev->rate) 245 return clkdev->rate; 246 247 return 0; 248} 249 250/* Not supported by clk driver. Implemented to satisfy clk fw */ 251static long skl_clk_round_rate(struct clk_hw *hw, unsigned long rate, 252 unsigned long *parent_rate) 253{ 254 return rate; 255} 256 257/* 258 * prepare/unprepare are used instead of enable/disable as IPC will be sent 259 * in non-atomic context. 260 */ 261static 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, 267}; 268 269static void unregister_parent_src_clk(struct skl_clk_parent *pclk, 270 unsigned int id) 271{ 272 while (id--) { 273 clkdev_drop(pclk[id].lookup); 274 clk_hw_unregister_fixed_rate(pclk[id].hw); 275 } 276} 277 278static void unregister_src_clk(struct skl_clk_data *dclk) 279{ 280 while (dclk->avail_clk_cnt--) 281 clkdev_drop(dclk->clk[dclk->avail_clk_cnt]->lookup); 282} 283 284static int skl_register_parent_clks(struct device *dev, 285 struct skl_clk_parent *parent, 286 struct skl_clk_parent_src *pclk) 287{ 288 int i, ret; 289 290 for (i = 0; i < SKL_MAX_CLK_SRC; i++) { 291 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; 298 } 299 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; 306 } 307 } 308 309 return 0; 310err: 311 unregister_parent_src_clk(parent, i); 312 return ret; 313} 314 315/* Assign fmt_config to clk_data */ 316static struct skl_clk *register_skl_clk(struct device *dev, 317 struct skl_ssp_clk *clk, 318 struct skl_clk_pdata *clk_pdata, int id) 319{ 320 struct clk_init_data init; 321 struct skl_clk *clkdev; 322 int ret; 323 324 clkdev = devm_kzalloc(dev, sizeof(*clkdev), GFP_KERNEL); 325 if (!clkdev) 326 return ERR_PTR(-ENOMEM); 327 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; 335 336 clkdev->id = id; 337 ret = devm_clk_hw_register(dev, &clkdev->hw); 338 if (ret) { 339 clkdev = ERR_PTR(ret); 340 return clkdev; 341 } 342 343 clkdev->lookup = clkdev_hw_create(&clkdev->hw, init.name, NULL); 344 if (!clkdev->lookup) 345 clkdev = ERR_PTR(-ENOMEM); 346 347 return clkdev; 348} 349 350static int skl_clk_dev_probe(struct platform_device *pdev) 351{ 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; 359 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; 365 366 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 367 if (!data) 368 return -ENOMEM; 369 370 /* Register Parent clock */ 371 ret = skl_register_parent_clks(parent_dev, data->parent, parent_clks); 372 if (ret < 0) 373 return ret; 374 375 for (i = 0; i < clk_pdata->num_clks; i++) { 376 /* 377 * Only register valid clocks 378 * i.e. for which nhlt entry is present. 379 */ 380 if (clks[i].rate_cfg[0].rate == 0) 381 continue; 382 383 data->clk[data->avail_clk_cnt] = register_skl_clk(dev, 384 &clks[i], clk_pdata, i); 385 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; 389 } 390 391 data->avail_clk_cnt++; 392 } 393 394 platform_set_drvdata(pdev, data); 395 396 return 0; 397 398err_unreg_skl_clk: 399 unregister_src_clk(data); 400 unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC); 401 402 return ret; 403} 404 405static int skl_clk_dev_remove(struct platform_device *pdev) 406{ 407 struct skl_clk_data *data; 408 409 data = platform_get_drvdata(pdev); 410 unregister_src_clk(data); 411 unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC); 412 413 return 0; 414} 415 416static struct platform_driver skl_clk_driver = { 417 .driver = { 418 .name = "skl-ssp-clk", 419 }, 420 .probe = skl_clk_dev_probe, 421 .remove = skl_clk_dev_remove, 422}; 423 424module_platform_driver(skl_clk_driver); 425 426MODULE_DESCRIPTION("Skylake clock driver"); 427MODULE_AUTHOR("Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>"); 428MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>"); 429MODULE_LICENSE("GPL v2"); 430MODULE_ALIAS("platform:skl-ssp-clk");