root/sound/soc/intel/skylake/skl-ssp-clk.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. skl_get_clk_type
  2. skl_get_vbus_id
  3. skl_fill_clk_ipc
  4. skl_send_clk_dma_control
  5. skl_get_rate_cfg
  6. skl_clk_change_status
  7. skl_clk_prepare
  8. skl_clk_unprepare
  9. skl_clk_set_rate
  10. skl_clk_recalc_rate
  11. skl_clk_round_rate
  12. unregister_parent_src_clk
  13. unregister_src_clk
  14. skl_register_parent_clks
  15. register_skl_clk
  16. skl_clk_dev_probe
  17. skl_clk_dev_remove

   1 // SPDX-License-Identifier: GPL-2.0
   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 
  21 struct skl_clk_parent {
  22         struct clk_hw *hw;
  23         struct clk_lookup *lookup;
  24 };
  25 
  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;
  32 };
  33 
  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;
  38 };
  39 
  40 static 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 
  57 static 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 
  74 static 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 */
 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)
 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 
 163 static 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 
 177 static 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 
 200 static 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 
 207 static 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 
 214 static 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 
 239 static 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 */
 251 static 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  */
 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,
 267 };
 268 
 269 static 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 
 278 static 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 
 284 static 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;
 310 err:
 311         unregister_parent_src_clk(parent, i);
 312         return ret;
 313 }
 314 
 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)
 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 
 350 static 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 
 398 err_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 
 405 static 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 
 416 static 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 
 424 module_platform_driver(skl_clk_driver);
 425 
 426 MODULE_DESCRIPTION("Skylake clock driver");
 427 MODULE_AUTHOR("Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>");
 428 MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
 429 MODULE_LICENSE("GPL v2");
 430 MODULE_ALIAS("platform:skl-ssp-clk");

/* [<][>][^][v][top][bottom][index][help] */