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