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