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