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 simple_card_data { 25 struct snd_soc_card snd_card; 26 struct simple_dai_props { 27 struct asoc_simple_dai cpu_dai; 28 struct asoc_simple_dai codec_dai; 29 unsigned int mclk_fs; 30 } *dai_props; 31 unsigned int mclk_fs; 32 int gpio_hp_det; 33 int gpio_hp_det_invert; 34 int gpio_mic_det; 35 int gpio_mic_det_invert; 36 struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ 37 }; 38 39 #define simple_priv_to_dev(priv) ((priv)->snd_card.dev) 40 #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) 41 #define simple_priv_to_props(priv, i) ((priv)->dai_props + i) 42 43 static int asoc_simple_card_startup(struct snd_pcm_substream *substream) 44 { 45 struct snd_soc_pcm_runtime *rtd = substream->private_data; 46 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 47 struct simple_dai_props *dai_props = 48 &priv->dai_props[rtd - rtd->card->rtd]; 49 int ret; 50 51 ret = clk_prepare_enable(dai_props->cpu_dai.clk); 52 if (ret) 53 return ret; 54 55 ret = clk_prepare_enable(dai_props->codec_dai.clk); 56 if (ret) 57 clk_disable_unprepare(dai_props->cpu_dai.clk); 58 59 return ret; 60 } 61 62 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) 63 { 64 struct snd_soc_pcm_runtime *rtd = substream->private_data; 65 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 66 struct simple_dai_props *dai_props = 67 &priv->dai_props[rtd - rtd->card->rtd]; 68 69 clk_disable_unprepare(dai_props->cpu_dai.clk); 70 71 clk_disable_unprepare(dai_props->codec_dai.clk); 72 } 73 74 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, 75 struct snd_pcm_hw_params *params) 76 { 77 struct snd_soc_pcm_runtime *rtd = substream->private_data; 78 struct snd_soc_dai *codec_dai = rtd->codec_dai; 79 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 80 struct simple_dai_props *dai_props = 81 &priv->dai_props[rtd - rtd->card->rtd]; 82 unsigned int mclk, mclk_fs = 0; 83 int ret = 0; 84 85 if (priv->mclk_fs) 86 mclk_fs = priv->mclk_fs; 87 else if (dai_props->mclk_fs) 88 mclk_fs = dai_props->mclk_fs; 89 90 if (mclk_fs) { 91 mclk = params_rate(params) * mclk_fs; 92 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 93 SND_SOC_CLOCK_IN); 94 } 95 96 return ret; 97 } 98 99 static struct snd_soc_ops asoc_simple_card_ops = { 100 .startup = asoc_simple_card_startup, 101 .shutdown = asoc_simple_card_shutdown, 102 .hw_params = asoc_simple_card_hw_params, 103 }; 104 105 static struct snd_soc_jack simple_card_hp_jack; 106 static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = { 107 { 108 .pin = "Headphones", 109 .mask = SND_JACK_HEADPHONE, 110 }, 111 }; 112 static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = { 113 .name = "Headphone detection", 114 .report = SND_JACK_HEADPHONE, 115 .debounce_time = 150, 116 }; 117 118 static struct snd_soc_jack simple_card_mic_jack; 119 static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = { 120 { 121 .pin = "Mic Jack", 122 .mask = SND_JACK_MICROPHONE, 123 }, 124 }; 125 static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = { 126 .name = "Mic detection", 127 .report = SND_JACK_MICROPHONE, 128 .debounce_time = 150, 129 }; 130 131 static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, 132 struct asoc_simple_dai *set) 133 { 134 int ret; 135 136 if (set->sysclk) { 137 ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); 138 if (ret && ret != -ENOTSUPP) { 139 dev_err(dai->dev, "simple-card: set_sysclk error\n"); 140 goto err; 141 } 142 } 143 144 if (set->slots) { 145 ret = snd_soc_dai_set_tdm_slot(dai, 0, 0, 146 set->slots, 147 set->slot_width); 148 if (ret && ret != -ENOTSUPP) { 149 dev_err(dai->dev, "simple-card: set_tdm_slot error\n"); 150 goto err; 151 } 152 } 153 154 ret = 0; 155 156 err: 157 return ret; 158 } 159 160 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) 161 { 162 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 163 struct snd_soc_dai *codec = rtd->codec_dai; 164 struct snd_soc_dai *cpu = rtd->cpu_dai; 165 struct simple_dai_props *dai_props; 166 int num, ret; 167 168 num = rtd - rtd->card->rtd; 169 dai_props = &priv->dai_props[num]; 170 ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai); 171 if (ret < 0) 172 return ret; 173 174 ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai); 175 if (ret < 0) 176 return ret; 177 178 if (gpio_is_valid(priv->gpio_hp_det)) { 179 snd_soc_card_jack_new(rtd->card, "Headphones", 180 SND_JACK_HEADPHONE, 181 &simple_card_hp_jack, 182 simple_card_hp_jack_pins, 183 ARRAY_SIZE(simple_card_hp_jack_pins)); 184 185 simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; 186 simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert; 187 snd_soc_jack_add_gpios(&simple_card_hp_jack, 1, 188 &simple_card_hp_jack_gpio); 189 } 190 191 if (gpio_is_valid(priv->gpio_mic_det)) { 192 snd_soc_card_jack_new(rtd->card, "Mic Jack", 193 SND_JACK_MICROPHONE, 194 &simple_card_mic_jack, 195 simple_card_mic_jack_pins, 196 ARRAY_SIZE(simple_card_mic_jack_pins)); 197 simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; 198 simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert; 199 snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, 200 &simple_card_mic_jack_gpio); 201 } 202 return 0; 203 } 204 205 static int 206 asoc_simple_card_sub_parse_of(struct device_node *np, 207 struct asoc_simple_dai *dai, 208 struct device_node **p_node, 209 const char **name, 210 int *args_count) 211 { 212 struct of_phandle_args args; 213 struct clk *clk; 214 u32 val; 215 int ret; 216 217 /* 218 * Get node via "sound-dai = <&phandle port>" 219 * it will be used as xxx_of_node on soc_bind_dai_link() 220 */ 221 ret = of_parse_phandle_with_args(np, "sound-dai", 222 "#sound-dai-cells", 0, &args); 223 if (ret) 224 return ret; 225 226 *p_node = args.np; 227 228 if (args_count) 229 *args_count = args.args_count; 230 231 /* Get dai->name */ 232 ret = snd_soc_of_get_dai_name(np, name); 233 if (ret < 0) 234 return ret; 235 236 /* Parse TDM slot */ 237 ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width); 238 if (ret) 239 return ret; 240 241 /* 242 * Parse dai->sysclk come from "clocks = <&xxx>" 243 * (if system has common clock) 244 * or "system-clock-frequency = <xxx>" 245 * or device's module clock. 246 */ 247 if (of_property_read_bool(np, "clocks")) { 248 clk = of_clk_get(np, 0); 249 if (IS_ERR(clk)) { 250 ret = PTR_ERR(clk); 251 return ret; 252 } 253 254 dai->sysclk = clk_get_rate(clk); 255 dai->clk = clk; 256 } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { 257 dai->sysclk = val; 258 } else { 259 clk = of_clk_get(args.np, 0); 260 if (!IS_ERR(clk)) 261 dai->sysclk = clk_get_rate(clk); 262 } 263 264 return 0; 265 } 266 267 static int asoc_simple_card_parse_daifmt(struct device_node *node, 268 struct simple_card_data *priv, 269 struct device_node *codec, 270 char *prefix, int idx) 271 { 272 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); 273 struct device *dev = simple_priv_to_dev(priv); 274 struct device_node *bitclkmaster = NULL; 275 struct device_node *framemaster = NULL; 276 unsigned int daifmt; 277 278 daifmt = snd_soc_of_parse_daifmt(node, prefix, 279 &bitclkmaster, &framemaster); 280 daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; 281 282 if (strlen(prefix) && !bitclkmaster && !framemaster) { 283 /* 284 * No dai-link level and master setting was not found from 285 * sound node level, revert back to legacy DT parsing and 286 * take the settings from codec node. 287 */ 288 dev_dbg(dev, "Revert to legacy daifmt parsing\n"); 289 290 daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | 291 (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); 292 } else { 293 if (codec == bitclkmaster) 294 daifmt |= (codec == framemaster) ? 295 SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; 296 else 297 daifmt |= (codec == framemaster) ? 298 SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; 299 } 300 301 dai_link->dai_fmt = daifmt; 302 303 of_node_put(bitclkmaster); 304 of_node_put(framemaster); 305 306 return 0; 307 } 308 309 static int asoc_simple_card_dai_link_of(struct device_node *node, 310 struct simple_card_data *priv, 311 int idx, 312 bool is_top_level_node) 313 { 314 struct device *dev = simple_priv_to_dev(priv); 315 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); 316 struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); 317 struct device_node *cpu = NULL; 318 struct device_node *plat = NULL; 319 struct device_node *codec = NULL; 320 char *name; 321 char prop[128]; 322 char *prefix = ""; 323 int ret, cpu_args; 324 u32 val; 325 326 /* For single DAI link & old style of DT node */ 327 if (is_top_level_node) 328 prefix = "simple-audio-card,"; 329 330 snprintf(prop, sizeof(prop), "%scpu", prefix); 331 cpu = of_get_child_by_name(node, prop); 332 333 snprintf(prop, sizeof(prop), "%splat", prefix); 334 plat = of_get_child_by_name(node, prop); 335 336 snprintf(prop, sizeof(prop), "%scodec", prefix); 337 codec = of_get_child_by_name(node, prop); 338 339 if (!cpu || !codec) { 340 ret = -EINVAL; 341 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 342 goto dai_link_of_err; 343 } 344 345 ret = asoc_simple_card_parse_daifmt(node, priv, 346 codec, prefix, idx); 347 if (ret < 0) 348 goto dai_link_of_err; 349 350 if (!of_property_read_u32(node, "mclk-fs", &val)) 351 dai_props->mclk_fs = val; 352 353 ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai, 354 &dai_link->cpu_of_node, 355 &dai_link->cpu_dai_name, 356 &cpu_args); 357 if (ret < 0) 358 goto dai_link_of_err; 359 360 ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai, 361 &dai_link->codec_of_node, 362 &dai_link->codec_dai_name, NULL); 363 if (ret < 0) 364 goto dai_link_of_err; 365 366 if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { 367 ret = -EINVAL; 368 goto dai_link_of_err; 369 } 370 371 if (plat) { 372 struct of_phandle_args args; 373 374 ret = of_parse_phandle_with_args(plat, "sound-dai", 375 "#sound-dai-cells", 0, &args); 376 dai_link->platform_of_node = args.np; 377 } else { 378 /* Assumes platform == cpu */ 379 dai_link->platform_of_node = dai_link->cpu_of_node; 380 } 381 382 /* DAI link name is created from CPU/CODEC dai name */ 383 name = devm_kzalloc(dev, 384 strlen(dai_link->cpu_dai_name) + 385 strlen(dai_link->codec_dai_name) + 2, 386 GFP_KERNEL); 387 if (!name) { 388 ret = -ENOMEM; 389 goto dai_link_of_err; 390 } 391 392 sprintf(name, "%s-%s", dai_link->cpu_dai_name, 393 dai_link->codec_dai_name); 394 dai_link->name = dai_link->stream_name = name; 395 dai_link->ops = &asoc_simple_card_ops; 396 dai_link->init = asoc_simple_card_dai_init; 397 398 dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); 399 dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt); 400 dev_dbg(dev, "\tcpu : %s / %d\n", 401 dai_link->cpu_dai_name, 402 dai_props->cpu_dai.sysclk); 403 dev_dbg(dev, "\tcodec : %s / %d\n", 404 dai_link->codec_dai_name, 405 dai_props->codec_dai.sysclk); 406 407 /* 408 * In soc_bind_dai_link() will check cpu name after 409 * of_node matching if dai_link has cpu_dai_name. 410 * but, it will never match if name was created by 411 * fmt_single_name() remove cpu_dai_name if cpu_args 412 * was 0. See: 413 * fmt_single_name() 414 * fmt_multiple_name() 415 */ 416 if (!cpu_args) 417 dai_link->cpu_dai_name = NULL; 418 419 dai_link_of_err: 420 of_node_put(cpu); 421 of_node_put(codec); 422 423 return ret; 424 } 425 426 static int asoc_simple_card_parse_of(struct device_node *node, 427 struct simple_card_data *priv) 428 { 429 struct device *dev = simple_priv_to_dev(priv); 430 enum of_gpio_flags flags; 431 u32 val; 432 int ret; 433 434 if (!node) 435 return -EINVAL; 436 437 /* Parse the card name from DT */ 438 snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); 439 440 /* The off-codec widgets */ 441 if (of_property_read_bool(node, "simple-audio-card,widgets")) { 442 ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, 443 "simple-audio-card,widgets"); 444 if (ret) 445 return ret; 446 } 447 448 /* DAPM routes */ 449 if (of_property_read_bool(node, "simple-audio-card,routing")) { 450 ret = snd_soc_of_parse_audio_routing(&priv->snd_card, 451 "simple-audio-card,routing"); 452 if (ret) 453 return ret; 454 } 455 456 /* Factor to mclk, used in hw_params() */ 457 ret = of_property_read_u32(node, "simple-audio-card,mclk-fs", &val); 458 if (ret == 0) 459 priv->mclk_fs = val; 460 461 dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? 462 priv->snd_card.name : ""); 463 464 /* Single/Muti DAI link(s) & New style of DT node */ 465 if (of_get_child_by_name(node, "simple-audio-card,dai-link")) { 466 struct device_node *np = NULL; 467 int i = 0; 468 469 for_each_child_of_node(node, np) { 470 dev_dbg(dev, "\tlink %d:\n", i); 471 ret = asoc_simple_card_dai_link_of(np, priv, 472 i, false); 473 if (ret < 0) { 474 of_node_put(np); 475 return ret; 476 } 477 i++; 478 } 479 } else { 480 /* For single DAI link & old style of DT node */ 481 ret = asoc_simple_card_dai_link_of(node, priv, 0, true); 482 if (ret < 0) 483 return ret; 484 } 485 486 priv->gpio_hp_det = of_get_named_gpio_flags(node, 487 "simple-audio-card,hp-det-gpio", 0, &flags); 488 priv->gpio_hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); 489 if (priv->gpio_hp_det == -EPROBE_DEFER) 490 return -EPROBE_DEFER; 491 492 priv->gpio_mic_det = of_get_named_gpio_flags(node, 493 "simple-audio-card,mic-det-gpio", 0, &flags); 494 priv->gpio_mic_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); 495 if (priv->gpio_mic_det == -EPROBE_DEFER) 496 return -EPROBE_DEFER; 497 498 if (!priv->snd_card.name) 499 priv->snd_card.name = priv->snd_card.dai_link->name; 500 501 return 0; 502 } 503 504 /* Decrease the reference count of the device nodes */ 505 static int asoc_simple_card_unref(struct snd_soc_card *card) 506 { 507 struct snd_soc_dai_link *dai_link; 508 int num_links; 509 510 for (num_links = 0, dai_link = card->dai_link; 511 num_links < card->num_links; 512 num_links++, dai_link++) { 513 of_node_put(dai_link->cpu_of_node); 514 of_node_put(dai_link->codec_of_node); 515 } 516 return 0; 517 } 518 519 static int asoc_simple_card_probe(struct platform_device *pdev) 520 { 521 struct simple_card_data *priv; 522 struct snd_soc_dai_link *dai_link; 523 struct device_node *np = pdev->dev.of_node; 524 struct device *dev = &pdev->dev; 525 int num_links, ret; 526 527 /* Get the number of DAI links */ 528 if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) 529 num_links = of_get_child_count(np); 530 else 531 num_links = 1; 532 533 /* Allocate the private data and the DAI link array */ 534 priv = devm_kzalloc(dev, 535 sizeof(*priv) + sizeof(*dai_link) * num_links, 536 GFP_KERNEL); 537 if (!priv) 538 return -ENOMEM; 539 540 /* Init snd_soc_card */ 541 priv->snd_card.owner = THIS_MODULE; 542 priv->snd_card.dev = dev; 543 dai_link = priv->dai_link; 544 priv->snd_card.dai_link = dai_link; 545 priv->snd_card.num_links = num_links; 546 547 priv->gpio_hp_det = -ENOENT; 548 priv->gpio_mic_det = -ENOENT; 549 550 /* Get room for the other properties */ 551 priv->dai_props = devm_kzalloc(dev, 552 sizeof(*priv->dai_props) * num_links, 553 GFP_KERNEL); 554 if (!priv->dai_props) 555 return -ENOMEM; 556 557 if (np && of_device_is_available(np)) { 558 559 ret = asoc_simple_card_parse_of(np, priv); 560 if (ret < 0) { 561 if (ret != -EPROBE_DEFER) 562 dev_err(dev, "parse error %d\n", ret); 563 goto err; 564 } 565 566 } else { 567 struct asoc_simple_card_info *cinfo; 568 569 cinfo = dev->platform_data; 570 if (!cinfo) { 571 dev_err(dev, "no info for asoc-simple-card\n"); 572 return -EINVAL; 573 } 574 575 if (!cinfo->name || 576 !cinfo->codec_dai.name || 577 !cinfo->codec || 578 !cinfo->platform || 579 !cinfo->cpu_dai.name) { 580 dev_err(dev, "insufficient asoc_simple_card_info settings\n"); 581 return -EINVAL; 582 } 583 584 priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name; 585 dai_link->name = cinfo->name; 586 dai_link->stream_name = cinfo->name; 587 dai_link->platform_name = cinfo->platform; 588 dai_link->codec_name = cinfo->codec; 589 dai_link->cpu_dai_name = cinfo->cpu_dai.name; 590 dai_link->codec_dai_name = cinfo->codec_dai.name; 591 dai_link->dai_fmt = cinfo->daifmt; 592 dai_link->init = asoc_simple_card_dai_init; 593 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, 594 sizeof(priv->dai_props->cpu_dai)); 595 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, 596 sizeof(priv->dai_props->codec_dai)); 597 598 } 599 600 snd_soc_card_set_drvdata(&priv->snd_card, priv); 601 602 ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); 603 if (ret >= 0) 604 return ret; 605 606 err: 607 asoc_simple_card_unref(&priv->snd_card); 608 return ret; 609 } 610 611 static int asoc_simple_card_remove(struct platform_device *pdev) 612 { 613 struct snd_soc_card *card = platform_get_drvdata(pdev); 614 struct simple_card_data *priv = snd_soc_card_get_drvdata(card); 615 616 if (gpio_is_valid(priv->gpio_hp_det)) 617 snd_soc_jack_free_gpios(&simple_card_hp_jack, 1, 618 &simple_card_hp_jack_gpio); 619 if (gpio_is_valid(priv->gpio_mic_det)) 620 snd_soc_jack_free_gpios(&simple_card_mic_jack, 1, 621 &simple_card_mic_jack_gpio); 622 623 return asoc_simple_card_unref(card); 624 } 625 626 static const struct of_device_id asoc_simple_of_match[] = { 627 { .compatible = "simple-audio-card", }, 628 {}, 629 }; 630 MODULE_DEVICE_TABLE(of, asoc_simple_of_match); 631 632 static struct platform_driver asoc_simple_card = { 633 .driver = { 634 .name = "asoc-simple-card", 635 .of_match_table = asoc_simple_of_match, 636 }, 637 .probe = asoc_simple_card_probe, 638 .remove = asoc_simple_card_remove, 639 }; 640 641 module_platform_driver(asoc_simple_card); 642 643 MODULE_ALIAS("platform:asoc-simple-card"); 644 MODULE_LICENSE("GPL"); 645 MODULE_DESCRIPTION("ASoC Simple Sound Card"); 646 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 647