1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // ASoC simple sound card support 4 // 5 // Copyright (C) 2012 Renesas Solutions Corp. 6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7 8 #include <linux/clk.h> 9 #include <linux/device.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/platform_device.h> 13 #include <linux/string.h> 14 #include <sound/simple_card.h> 15 #include <sound/soc-dai.h> 16 #include <sound/soc.h> 17 18 struct simple_card_data { 19 struct snd_soc_card snd_card; 20 struct simple_dai_props { 21 struct asoc_simple_dai cpu_dai; 22 struct asoc_simple_dai codec_dai; 23 struct snd_soc_dai_link_component codecs; /* single codec */ 24 struct snd_soc_dai_link_component platform; 25 unsigned int mclk_fs; 26 } *dai_props; 27 unsigned int mclk_fs; 28 struct asoc_simple_jack hp_jack; 29 struct asoc_simple_jack mic_jack; 30 struct snd_soc_dai_link *dai_link; 31 }; 32 33 #define simple_priv_to_card(priv) (&(priv)->snd_card) 34 #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) 35 #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) 36 #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) 37 38 #define DAI "sound-dai" 39 #define CELL "#sound-dai-cells" 40 #define PREFIX "simple-audio-card," 41 42 static int asoc_simple_card_startup(struct snd_pcm_substream *substream) 43 { 44 struct snd_soc_pcm_runtime *rtd = substream->private_data; 45 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 46 struct simple_dai_props *dai_props = 47 simple_priv_to_props(priv, rtd->num); 48 int ret; 49 50 ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai); 51 if (ret) 52 return ret; 53 54 ret = asoc_simple_card_clk_enable(&dai_props->codec_dai); 55 if (ret) 56 asoc_simple_card_clk_disable(&dai_props->cpu_dai); 57 58 return ret; 59 } 60 61 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) 62 { 63 struct snd_soc_pcm_runtime *rtd = substream->private_data; 64 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 65 struct simple_dai_props *dai_props = 66 simple_priv_to_props(priv, rtd->num); 67 68 asoc_simple_card_clk_disable(&dai_props->cpu_dai); 69 70 asoc_simple_card_clk_disable(&dai_props->codec_dai); 71 } 72 73 static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, 74 unsigned long rate) 75 { 76 if (!simple_dai->clk) 77 return 0; 78 79 if (clk_get_rate(simple_dai->clk) == rate) 80 return 0; 81 82 return clk_set_rate(simple_dai->clk, rate); 83 } 84 85 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, 86 struct snd_pcm_hw_params *params) 87 { 88 struct snd_soc_pcm_runtime *rtd = substream->private_data; 89 struct snd_soc_dai *codec_dai = rtd->codec_dai; 90 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 91 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 92 struct simple_dai_props *dai_props = 93 simple_priv_to_props(priv, rtd->num); 94 unsigned int mclk, mclk_fs = 0; 95 int ret = 0; 96 97 if (priv->mclk_fs) 98 mclk_fs = priv->mclk_fs; 99 else if (dai_props->mclk_fs) 100 mclk_fs = dai_props->mclk_fs; 101 102 if (mclk_fs) { 103 mclk = params_rate(params) * mclk_fs; 104 105 ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk); 106 if (ret < 0) 107 return ret; 108 109 ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk); 110 if (ret < 0) 111 return ret; 112 113 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 114 SND_SOC_CLOCK_IN); 115 if (ret && ret != -ENOTSUPP) 116 goto err; 117 118 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, 119 SND_SOC_CLOCK_OUT); 120 if (ret && ret != -ENOTSUPP) 121 goto err; 122 } 123 return 0; 124 err: 125 return ret; 126 } 127 128 static const struct snd_soc_ops asoc_simple_card_ops = { 129 .startup = asoc_simple_card_startup, 130 .shutdown = asoc_simple_card_shutdown, 131 .hw_params = asoc_simple_card_hw_params, 132 }; 133 134 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) 135 { 136 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 137 struct snd_soc_dai *codec = rtd->codec_dai; 138 struct snd_soc_dai *cpu = rtd->cpu_dai; 139 struct simple_dai_props *dai_props = 140 simple_priv_to_props(priv, rtd->num); 141 int ret; 142 143 ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); 144 if (ret < 0) 145 return ret; 146 147 ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai); 148 if (ret < 0) 149 return ret; 150 151 return 0; 152 } 153 154 static int asoc_simple_card_dai_link_of(struct device_node *node, 155 struct simple_card_data *priv, 156 int idx, 157 bool is_top_level_node) 158 { 159 struct device *dev = simple_priv_to_dev(priv); 160 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); 161 struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); 162 struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; 163 struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; 164 struct device_node *cpu = NULL; 165 struct device_node *plat = NULL; 166 struct device_node *codec = NULL; 167 char prop[128]; 168 char *prefix = ""; 169 int ret, single_cpu; 170 171 /* For single DAI link & old style of DT node */ 172 if (is_top_level_node) 173 prefix = PREFIX; 174 175 snprintf(prop, sizeof(prop), "%scpu", prefix); 176 cpu = of_get_child_by_name(node, prop); 177 178 if (!cpu) { 179 ret = -EINVAL; 180 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 181 goto dai_link_of_err; 182 } 183 184 snprintf(prop, sizeof(prop), "%splat", prefix); 185 plat = of_get_child_by_name(node, prop); 186 187 snprintf(prop, sizeof(prop), "%scodec", prefix); 188 codec = of_get_child_by_name(node, prop); 189 190 if (!codec) { 191 ret = -EINVAL; 192 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 193 goto dai_link_of_err; 194 } 195 196 ret = asoc_simple_card_parse_daifmt(dev, node, codec, 197 prefix, &dai_link->dai_fmt); 198 if (ret < 0) 199 goto dai_link_of_err; 200 201 of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); 202 203 ret = asoc_simple_card_parse_cpu(cpu, dai_link, 204 DAI, CELL, &single_cpu); 205 if (ret < 0) 206 goto dai_link_of_err; 207 208 ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL); 209 if (ret < 0) 210 goto dai_link_of_err; 211 212 ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL); 213 if (ret < 0) 214 goto dai_link_of_err; 215 216 ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai); 217 if (ret < 0) 218 goto dai_link_of_err; 219 220 ret = asoc_simple_card_of_parse_tdm(codec, codec_dai); 221 if (ret < 0) 222 goto dai_link_of_err; 223 224 ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai); 225 if (ret < 0) 226 goto dai_link_of_err; 227 228 ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai); 229 if (ret < 0) 230 goto dai_link_of_err; 231 232 ret = asoc_simple_card_canonicalize_dailink(dai_link); 233 if (ret < 0) 234 goto dai_link_of_err; 235 236 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 237 "%s-%s", 238 dai_link->cpu_dai_name, 239 dai_link->codecs->dai_name); 240 if (ret < 0) 241 goto dai_link_of_err; 242 243 dai_link->ops = &asoc_simple_card_ops; 244 dai_link->init = asoc_simple_card_dai_init; 245 246 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); 247 248 dai_link_of_err: 249 of_node_put(cpu); 250 of_node_put(codec); 251 252 return ret; 253 } 254 255 static int asoc_simple_card_parse_aux_devs(struct device_node *node, 256 struct simple_card_data *priv) 257 { 258 struct device *dev = simple_priv_to_dev(priv); 259 struct device_node *aux_node; 260 struct snd_soc_card *card = simple_priv_to_card(priv); 261 int i, n, len; 262 263 if (!of_find_property(node, PREFIX "aux-devs", &len)) 264 return 0; /* Ok to have no aux-devs */ 265 266 n = len / sizeof(__be32); 267 if (n <= 0) 268 return -EINVAL; 269 270 card->aux_dev = devm_kcalloc(dev, 271 n, sizeof(*card->aux_dev), GFP_KERNEL); 272 if (!card->aux_dev) 273 return -ENOMEM; 274 275 for (i = 0; i < n; i++) { 276 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); 277 if (!aux_node) 278 return -EINVAL; 279 card->aux_dev[i].codec_of_node = aux_node; 280 } 281 282 card->num_aux_devs = n; 283 return 0; 284 } 285 286 static int asoc_simple_card_parse_of(struct simple_card_data *priv) 287 { 288 struct device *dev = simple_priv_to_dev(priv); 289 struct snd_soc_card *card = simple_priv_to_card(priv); 290 struct device_node *dai_link; 291 struct device_node *node = dev->of_node; 292 int ret; 293 294 if (!node) 295 return -EINVAL; 296 297 dai_link = of_get_child_by_name(node, PREFIX "dai-link"); 298 299 ret = asoc_simple_card_of_parse_widgets(card, PREFIX); 300 if (ret < 0) 301 goto card_parse_end; 302 303 ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1); 304 if (ret < 0) 305 goto card_parse_end; 306 307 /* Factor to mclk, used in hw_params() */ 308 of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); 309 310 /* Single/Muti DAI link(s) & New style of DT node */ 311 if (dai_link) { 312 struct device_node *np = NULL; 313 int i = 0; 314 315 for_each_child_of_node(node, np) { 316 dev_dbg(dev, "\tlink %d:\n", i); 317 ret = asoc_simple_card_dai_link_of(np, priv, 318 i, false); 319 if (ret < 0) { 320 of_node_put(np); 321 goto card_parse_end; 322 } 323 i++; 324 } 325 } else { 326 /* For single DAI link & old style of DT node */ 327 ret = asoc_simple_card_dai_link_of(node, priv, 0, true); 328 if (ret < 0) 329 goto card_parse_end; 330 } 331 332 ret = asoc_simple_card_parse_card_name(card, PREFIX); 333 if (ret < 0) 334 goto card_parse_end; 335 336 ret = asoc_simple_card_parse_aux_devs(node, priv); 337 338 card_parse_end: 339 of_node_put(dai_link); 340 341 return ret; 342 } 343 344 static int asoc_simple_soc_card_probe(struct snd_soc_card *card) 345 { 346 struct simple_card_data *priv = snd_soc_card_get_drvdata(card); 347 int ret; 348 349 ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX); 350 if (ret < 0) 351 return ret; 352 353 ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX); 354 if (ret < 0) 355 return ret; 356 357 return 0; 358 } 359 360 static int asoc_simple_card_probe(struct platform_device *pdev) 361 { 362 struct simple_card_data *priv; 363 struct snd_soc_dai_link *dai_link; 364 struct simple_dai_props *dai_props; 365 struct device *dev = &pdev->dev; 366 struct device_node *np = dev->of_node; 367 struct snd_soc_card *card; 368 int num, ret, i; 369 370 /* Get the number of DAI links */ 371 if (np && of_get_child_by_name(np, PREFIX "dai-link")) 372 num = of_get_child_count(np); 373 else 374 num = 1; 375 376 /* Allocate the private data and the DAI link array */ 377 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 378 if (!priv) 379 return -ENOMEM; 380 381 dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); 382 dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); 383 if (!dai_props || !dai_link) 384 return -ENOMEM; 385 386 /* 387 * Use snd_soc_dai_link_component instead of legacy style 388 * It is codec only. but cpu/platform will be supported in the future. 389 * see 390 * soc-core.c :: snd_soc_init_multicodec() 391 */ 392 for (i = 0; i < num; i++) { 393 dai_link[i].codecs = &dai_props[i].codecs; 394 dai_link[i].num_codecs = 1; 395 dai_link[i].platform = &dai_props[i].platform; 396 } 397 398 priv->dai_props = dai_props; 399 priv->dai_link = dai_link; 400 401 /* Init snd_soc_card */ 402 card = simple_priv_to_card(priv); 403 card->owner = THIS_MODULE; 404 card->dev = dev; 405 card->dai_link = priv->dai_link; 406 card->num_links = num; 407 card->probe = asoc_simple_soc_card_probe; 408 409 if (np && of_device_is_available(np)) { 410 411 ret = asoc_simple_card_parse_of(priv); 412 if (ret < 0) { 413 if (ret != -EPROBE_DEFER) 414 dev_err(dev, "parse error %d\n", ret); 415 goto err; 416 } 417 418 } else { 419 struct asoc_simple_card_info *cinfo; 420 struct snd_soc_dai_link_component *codecs; 421 struct snd_soc_dai_link_component *platform; 422 423 cinfo = dev->platform_data; 424 if (!cinfo) { 425 dev_err(dev, "no info for asoc-simple-card\n"); 426 return -EINVAL; 427 } 428 429 if (!cinfo->name || 430 !cinfo->codec_dai.name || 431 !cinfo->codec || 432 !cinfo->platform || 433 !cinfo->cpu_dai.name) { 434 dev_err(dev, "insufficient asoc_simple_card_info settings\n"); 435 return -EINVAL; 436 } 437 438 codecs = dai_link->codecs; 439 codecs->name = cinfo->codec; 440 codecs->dai_name = cinfo->codec_dai.name; 441 442 platform = dai_link->platform; 443 platform->name = cinfo->platform; 444 445 card->name = (cinfo->card) ? cinfo->card : cinfo->name; 446 dai_link->name = cinfo->name; 447 dai_link->stream_name = cinfo->name; 448 dai_link->cpu_dai_name = cinfo->cpu_dai.name; 449 dai_link->dai_fmt = cinfo->daifmt; 450 dai_link->init = asoc_simple_card_dai_init; 451 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, 452 sizeof(priv->dai_props->cpu_dai)); 453 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, 454 sizeof(priv->dai_props->codec_dai)); 455 } 456 457 snd_soc_card_set_drvdata(card, priv); 458 459 ret = devm_snd_soc_register_card(dev, card); 460 if (ret < 0) 461 goto err; 462 463 return 0; 464 err: 465 asoc_simple_card_clean_reference(card); 466 467 return ret; 468 } 469 470 static int asoc_simple_card_remove(struct platform_device *pdev) 471 { 472 struct snd_soc_card *card = platform_get_drvdata(pdev); 473 474 return asoc_simple_card_clean_reference(card); 475 } 476 477 static const struct of_device_id asoc_simple_of_match[] = { 478 { .compatible = "simple-audio-card", }, 479 {}, 480 }; 481 MODULE_DEVICE_TABLE(of, asoc_simple_of_match); 482 483 static struct platform_driver asoc_simple_card = { 484 .driver = { 485 .name = "asoc-simple-card", 486 .pm = &snd_soc_pm_ops, 487 .of_match_table = asoc_simple_of_match, 488 }, 489 .probe = asoc_simple_card_probe, 490 .remove = asoc_simple_card_remove, 491 }; 492 493 module_platform_driver(asoc_simple_card); 494 495 MODULE_ALIAS("platform:asoc-simple-card"); 496 MODULE_LICENSE("GPL v2"); 497 MODULE_DESCRIPTION("ASoC Simple Sound Card"); 498 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 499