1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // simple-card-utils.c 4 // 5 // Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 6 7 #include <linux/clk.h> 8 #include <linux/gpio.h> 9 #include <linux/gpio/consumer.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/of_gpio.h> 13 #include <linux/of_graph.h> 14 #include <sound/jack.h> 15 #include <sound/simple_card_utils.h> 16 17 void asoc_simple_convert_fixup(struct asoc_simple_data *data, 18 struct snd_pcm_hw_params *params) 19 { 20 struct snd_interval *rate = hw_param_interval(params, 21 SNDRV_PCM_HW_PARAM_RATE); 22 struct snd_interval *channels = hw_param_interval(params, 23 SNDRV_PCM_HW_PARAM_CHANNELS); 24 25 if (data->convert_rate) 26 rate->min = 27 rate->max = data->convert_rate; 28 29 if (data->convert_channels) 30 channels->min = 31 channels->max = data->convert_channels; 32 } 33 EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup); 34 35 void asoc_simple_parse_convert(struct device_node *np, 36 char *prefix, 37 struct asoc_simple_data *data) 38 { 39 char prop[128]; 40 41 if (!prefix) 42 prefix = ""; 43 44 /* sampling rate convert */ 45 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate"); 46 of_property_read_u32(np, prop, &data->convert_rate); 47 48 /* channels transfer */ 49 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels"); 50 of_property_read_u32(np, prop, &data->convert_channels); 51 } 52 EXPORT_SYMBOL_GPL(asoc_simple_parse_convert); 53 54 int asoc_simple_parse_daifmt(struct device *dev, 55 struct device_node *node, 56 struct device_node *codec, 57 char *prefix, 58 unsigned int *retfmt) 59 { 60 struct device_node *bitclkmaster = NULL; 61 struct device_node *framemaster = NULL; 62 unsigned int daifmt; 63 64 daifmt = snd_soc_daifmt_parse_format(node, prefix); 65 66 snd_soc_daifmt_parse_clock_provider_as_phandle(node, prefix, &bitclkmaster, &framemaster); 67 if (!bitclkmaster && !framemaster) { 68 /* 69 * No dai-link level and master setting was not found from 70 * sound node level, revert back to legacy DT parsing and 71 * take the settings from codec node. 72 */ 73 dev_dbg(dev, "Revert to legacy daifmt parsing\n"); 74 75 daifmt |= snd_soc_daifmt_parse_clock_provider_as_flag(codec, NULL); 76 } else { 77 daifmt |= snd_soc_daifmt_clock_provider_from_bitmap( 78 ((codec == bitclkmaster) << 4) | (codec == framemaster)); 79 } 80 81 of_node_put(bitclkmaster); 82 of_node_put(framemaster); 83 84 *retfmt = daifmt; 85 86 return 0; 87 } 88 EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt); 89 90 int asoc_simple_set_dailink_name(struct device *dev, 91 struct snd_soc_dai_link *dai_link, 92 const char *fmt, ...) 93 { 94 va_list ap; 95 char *name = NULL; 96 int ret = -ENOMEM; 97 98 va_start(ap, fmt); 99 name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap); 100 va_end(ap); 101 102 if (name) { 103 ret = 0; 104 105 dai_link->name = name; 106 dai_link->stream_name = name; 107 } 108 109 return ret; 110 } 111 EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name); 112 113 int asoc_simple_parse_card_name(struct snd_soc_card *card, 114 char *prefix) 115 { 116 int ret; 117 118 if (!prefix) 119 prefix = ""; 120 121 /* Parse the card name from DT */ 122 ret = snd_soc_of_parse_card_name(card, "label"); 123 if (ret < 0 || !card->name) { 124 char prop[128]; 125 126 snprintf(prop, sizeof(prop), "%sname", prefix); 127 ret = snd_soc_of_parse_card_name(card, prop); 128 if (ret < 0) 129 return ret; 130 } 131 132 if (!card->name && card->dai_link) 133 card->name = card->dai_link->name; 134 135 return 0; 136 } 137 EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name); 138 139 static int asoc_simple_clk_enable(struct asoc_simple_dai *dai) 140 { 141 if (dai) 142 return clk_prepare_enable(dai->clk); 143 144 return 0; 145 } 146 147 static void asoc_simple_clk_disable(struct asoc_simple_dai *dai) 148 { 149 if (dai) 150 clk_disable_unprepare(dai->clk); 151 } 152 153 int asoc_simple_parse_clk(struct device *dev, 154 struct device_node *node, 155 struct asoc_simple_dai *simple_dai, 156 struct snd_soc_dai_link_component *dlc) 157 { 158 struct clk *clk; 159 u32 val; 160 161 /* 162 * Parse dai->sysclk come from "clocks = <&xxx>" 163 * (if system has common clock) 164 * or "system-clock-frequency = <xxx>" 165 * or device's module clock. 166 */ 167 clk = devm_get_clk_from_child(dev, node, NULL); 168 if (!IS_ERR(clk)) { 169 simple_dai->sysclk = clk_get_rate(clk); 170 171 simple_dai->clk = clk; 172 } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { 173 simple_dai->sysclk = val; 174 } else { 175 clk = devm_get_clk_from_child(dev, dlc->of_node, NULL); 176 if (!IS_ERR(clk)) 177 simple_dai->sysclk = clk_get_rate(clk); 178 } 179 180 if (of_property_read_bool(node, "system-clock-direction-out")) 181 simple_dai->clk_direction = SND_SOC_CLOCK_OUT; 182 183 return 0; 184 } 185 EXPORT_SYMBOL_GPL(asoc_simple_parse_clk); 186 187 int asoc_simple_startup(struct snd_pcm_substream *substream) 188 { 189 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 190 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 191 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); 192 struct asoc_simple_dai *dai; 193 int i1, i2, i; 194 int ret; 195 196 for_each_prop_dai_cpu(props, i1, dai) { 197 ret = asoc_simple_clk_enable(dai); 198 if (ret) 199 goto cpu_err; 200 } 201 202 for_each_prop_dai_codec(props, i2, dai) { 203 ret = asoc_simple_clk_enable(dai); 204 if (ret) 205 goto codec_err; 206 } 207 208 return 0; 209 210 codec_err: 211 for_each_prop_dai_codec(props, i, dai) { 212 if (i >= i2) 213 break; 214 asoc_simple_clk_disable(dai); 215 } 216 cpu_err: 217 for_each_prop_dai_cpu(props, i, dai) { 218 if (i >= i1) 219 break; 220 asoc_simple_clk_disable(dai); 221 } 222 return ret; 223 } 224 EXPORT_SYMBOL_GPL(asoc_simple_startup); 225 226 void asoc_simple_shutdown(struct snd_pcm_substream *substream) 227 { 228 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 229 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 230 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 231 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 232 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); 233 struct asoc_simple_dai *dai; 234 int i; 235 236 if (props->mclk_fs) { 237 snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN); 238 snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT); 239 } 240 241 for_each_prop_dai_cpu(props, i, dai) 242 asoc_simple_clk_disable(dai); 243 for_each_prop_dai_codec(props, i, dai) 244 asoc_simple_clk_disable(dai); 245 } 246 EXPORT_SYMBOL_GPL(asoc_simple_shutdown); 247 248 static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, 249 unsigned long rate) 250 { 251 if (!simple_dai) 252 return 0; 253 254 if (!simple_dai->clk) 255 return 0; 256 257 if (clk_get_rate(simple_dai->clk) == rate) 258 return 0; 259 260 return clk_set_rate(simple_dai->clk, rate); 261 } 262 263 int asoc_simple_hw_params(struct snd_pcm_substream *substream, 264 struct snd_pcm_hw_params *params) 265 { 266 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 267 struct asoc_simple_dai *pdai; 268 struct snd_soc_dai *sdai; 269 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 270 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); 271 unsigned int mclk, mclk_fs = 0; 272 int i, ret; 273 274 if (props->mclk_fs) 275 mclk_fs = props->mclk_fs; 276 277 if (mclk_fs) { 278 mclk = params_rate(params) * mclk_fs; 279 280 for_each_prop_dai_codec(props, i, pdai) { 281 ret = asoc_simple_set_clk_rate(pdai, mclk); 282 if (ret < 0) 283 return ret; 284 } 285 for_each_prop_dai_cpu(props, i, pdai) { 286 ret = asoc_simple_set_clk_rate(pdai, mclk); 287 if (ret < 0) 288 return ret; 289 } 290 for_each_rtd_codec_dais(rtd, i, sdai) { 291 ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN); 292 if (ret && ret != -ENOTSUPP) 293 return ret; 294 } 295 for_each_rtd_cpu_dais(rtd, i, sdai) { 296 ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT); 297 if (ret && ret != -ENOTSUPP) 298 return ret; 299 } 300 } 301 return 0; 302 } 303 EXPORT_SYMBOL_GPL(asoc_simple_hw_params); 304 305 int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 306 struct snd_pcm_hw_params *params) 307 { 308 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 309 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); 310 311 asoc_simple_convert_fixup(&dai_props->adata, params); 312 313 return 0; 314 } 315 EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup); 316 317 static int asoc_simple_init_dai(struct snd_soc_dai *dai, 318 struct asoc_simple_dai *simple_dai) 319 { 320 int ret; 321 322 if (!simple_dai) 323 return 0; 324 325 if (simple_dai->sysclk) { 326 ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, 327 simple_dai->clk_direction); 328 if (ret && ret != -ENOTSUPP) { 329 dev_err(dai->dev, "simple-card: set_sysclk error\n"); 330 return ret; 331 } 332 } 333 334 if (simple_dai->slots) { 335 ret = snd_soc_dai_set_tdm_slot(dai, 336 simple_dai->tx_slot_mask, 337 simple_dai->rx_slot_mask, 338 simple_dai->slots, 339 simple_dai->slot_width); 340 if (ret && ret != -ENOTSUPP) { 341 dev_err(dai->dev, "simple-card: set_tdm_slot error\n"); 342 return ret; 343 } 344 } 345 346 return 0; 347 } 348 349 static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, 350 struct simple_dai_props *dai_props) 351 { 352 struct snd_soc_dai_link *dai_link = rtd->dai_link; 353 struct snd_soc_component *component; 354 struct snd_soc_pcm_stream *params; 355 struct snd_pcm_hardware hw; 356 int i, ret, stream; 357 358 /* Only Codecs */ 359 for_each_rtd_components(rtd, i, component) { 360 if (!snd_soc_component_is_codec(component)) 361 return 0; 362 } 363 364 /* Assumes the capabilities are the same for all supported streams */ 365 for_each_pcm_streams(stream) { 366 ret = snd_soc_runtime_calc_hw(rtd, &hw, stream); 367 if (ret == 0) 368 break; 369 } 370 371 if (ret < 0) { 372 dev_err(rtd->dev, "simple-card: no valid dai_link params\n"); 373 return ret; 374 } 375 376 params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL); 377 if (!params) 378 return -ENOMEM; 379 380 params->formats = hw.formats; 381 params->rates = hw.rates; 382 params->rate_min = hw.rate_min; 383 params->rate_max = hw.rate_max; 384 params->channels_min = hw.channels_min; 385 params->channels_max = hw.channels_max; 386 387 dai_link->params = params; 388 dai_link->num_params = 1; 389 390 return 0; 391 } 392 393 int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd) 394 { 395 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 396 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); 397 struct asoc_simple_dai *dai; 398 int i, ret; 399 400 for_each_prop_dai_codec(props, i, dai) { 401 ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai); 402 if (ret < 0) 403 return ret; 404 } 405 for_each_prop_dai_cpu(props, i, dai) { 406 ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai); 407 if (ret < 0) 408 return ret; 409 } 410 411 ret = asoc_simple_init_dai_link_params(rtd, props); 412 if (ret < 0) 413 return ret; 414 415 return 0; 416 } 417 EXPORT_SYMBOL_GPL(asoc_simple_dai_init); 418 419 void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms, 420 struct snd_soc_dai_link_component *cpus) 421 { 422 /* Assumes platform == cpu */ 423 if (!platforms->of_node) 424 platforms->of_node = cpus->of_node; 425 } 426 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); 427 428 void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, 429 int is_single_links) 430 { 431 /* 432 * In soc_bind_dai_link() will check cpu name after 433 * of_node matching if dai_link has cpu_dai_name. 434 * but, it will never match if name was created by 435 * fmt_single_name() remove cpu_dai_name if cpu_args 436 * was 0. See: 437 * fmt_single_name() 438 * fmt_multiple_name() 439 */ 440 if (is_single_links) 441 cpus->dai_name = NULL; 442 } 443 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu); 444 445 int asoc_simple_clean_reference(struct snd_soc_card *card) 446 { 447 struct snd_soc_dai_link *dai_link; 448 struct snd_soc_dai_link_component *cpu; 449 struct snd_soc_dai_link_component *codec; 450 int i, j; 451 452 for_each_card_prelinks(card, i, dai_link) { 453 for_each_link_cpus(dai_link, j, cpu) 454 of_node_put(cpu->of_node); 455 for_each_link_codecs(dai_link, j, codec) 456 of_node_put(codec->of_node); 457 } 458 return 0; 459 } 460 EXPORT_SYMBOL_GPL(asoc_simple_clean_reference); 461 462 int asoc_simple_parse_routing(struct snd_soc_card *card, 463 char *prefix) 464 { 465 struct device_node *node = card->dev->of_node; 466 char prop[128]; 467 468 if (!prefix) 469 prefix = ""; 470 471 snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); 472 473 if (!of_property_read_bool(node, prop)) 474 return 0; 475 476 return snd_soc_of_parse_audio_routing(card, prop); 477 } 478 EXPORT_SYMBOL_GPL(asoc_simple_parse_routing); 479 480 int asoc_simple_parse_widgets(struct snd_soc_card *card, 481 char *prefix) 482 { 483 struct device_node *node = card->dev->of_node; 484 char prop[128]; 485 486 if (!prefix) 487 prefix = ""; 488 489 snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets"); 490 491 if (of_property_read_bool(node, prop)) 492 return snd_soc_of_parse_audio_simple_widgets(card, prop); 493 494 /* no widgets is not error */ 495 return 0; 496 } 497 EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets); 498 499 int asoc_simple_parse_pin_switches(struct snd_soc_card *card, 500 char *prefix) 501 { 502 char prop[128]; 503 504 if (!prefix) 505 prefix = ""; 506 507 snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches"); 508 509 return snd_soc_of_parse_pin_switches(card, prop); 510 } 511 EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches); 512 513 int asoc_simple_init_jack(struct snd_soc_card *card, 514 struct asoc_simple_jack *sjack, 515 int is_hp, char *prefix, 516 char *pin) 517 { 518 struct device *dev = card->dev; 519 enum of_gpio_flags flags; 520 char prop[128]; 521 char *pin_name; 522 char *gpio_name; 523 int mask; 524 int det; 525 526 if (!prefix) 527 prefix = ""; 528 529 sjack->gpio.gpio = -ENOENT; 530 531 if (is_hp) { 532 snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix); 533 pin_name = pin ? pin : "Headphones"; 534 gpio_name = "Headphone detection"; 535 mask = SND_JACK_HEADPHONE; 536 } else { 537 snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix); 538 pin_name = pin ? pin : "Mic Jack"; 539 gpio_name = "Mic detection"; 540 mask = SND_JACK_MICROPHONE; 541 } 542 543 det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags); 544 if (det == -EPROBE_DEFER) 545 return -EPROBE_DEFER; 546 547 if (gpio_is_valid(det)) { 548 sjack->pin.pin = pin_name; 549 sjack->pin.mask = mask; 550 551 sjack->gpio.name = gpio_name; 552 sjack->gpio.report = mask; 553 sjack->gpio.gpio = det; 554 sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW); 555 sjack->gpio.debounce_time = 150; 556 557 snd_soc_card_jack_new(card, pin_name, mask, 558 &sjack->jack, 559 &sjack->pin, 1); 560 561 snd_soc_jack_add_gpios(&sjack->jack, 1, 562 &sjack->gpio); 563 } 564 565 return 0; 566 } 567 EXPORT_SYMBOL_GPL(asoc_simple_init_jack); 568 569 int asoc_simple_init_priv(struct asoc_simple_priv *priv, 570 struct link_info *li) 571 { 572 struct snd_soc_card *card = simple_priv_to_card(priv); 573 struct device *dev = simple_priv_to_dev(priv); 574 struct snd_soc_dai_link *dai_link; 575 struct simple_dai_props *dai_props; 576 struct asoc_simple_dai *dais; 577 struct snd_soc_dai_link_component *dlcs; 578 struct snd_soc_codec_conf *cconf = NULL; 579 struct snd_soc_pcm_stream *c2c_conf = NULL; 580 int i, dai_num = 0, dlc_num = 0, cnf_num = 0, c2c_num = 0; 581 582 dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL); 583 dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL); 584 if (!dai_props || !dai_link) 585 return -ENOMEM; 586 587 /* 588 * dais (= CPU+Codec) 589 * dlcs (= CPU+Codec+Platform) 590 */ 591 for (i = 0; i < li->link; i++) { 592 int cc = li->num[i].cpus + li->num[i].codecs; 593 594 dai_num += cc; 595 dlc_num += cc + li->num[i].platforms; 596 597 if (!li->num[i].cpus) 598 cnf_num += li->num[i].codecs; 599 600 c2c_num += li->num[i].c2c; 601 } 602 603 dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL); 604 dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL); 605 if (!dais || !dlcs) 606 return -ENOMEM; 607 608 if (cnf_num) { 609 cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL); 610 if (!cconf) 611 return -ENOMEM; 612 } 613 614 if (c2c_num) { 615 c2c_conf = devm_kcalloc(dev, c2c_num, sizeof(*c2c_conf), GFP_KERNEL); 616 if (!c2c_conf) 617 return -ENOMEM; 618 } 619 620 dev_dbg(dev, "link %d, dais %d, ccnf %d\n", 621 li->link, dai_num, cnf_num); 622 623 /* dummy CPU/Codec */ 624 priv->dummy.of_node = NULL; 625 priv->dummy.dai_name = "snd-soc-dummy-dai"; 626 priv->dummy.name = "snd-soc-dummy"; 627 628 priv->dai_props = dai_props; 629 priv->dai_link = dai_link; 630 priv->dais = dais; 631 priv->dlcs = dlcs; 632 priv->codec_conf = cconf; 633 priv->c2c_conf = c2c_conf; 634 635 card->dai_link = priv->dai_link; 636 card->num_links = li->link; 637 card->codec_conf = cconf; 638 card->num_configs = cnf_num; 639 640 for (i = 0; i < li->link; i++) { 641 if (li->num[i].cpus) { 642 /* Normal CPU */ 643 dai_props[i].cpus = 644 dai_link[i].cpus = dlcs; 645 dai_props[i].num.cpus = 646 dai_link[i].num_cpus = li->num[i].cpus; 647 dai_props[i].cpu_dai = dais; 648 649 dlcs += li->num[i].cpus; 650 dais += li->num[i].cpus; 651 652 if (li->num[i].c2c) { 653 /* Codec2Codec */ 654 dai_props[i].c2c_conf = c2c_conf; 655 c2c_conf += li->num[i].c2c; 656 } 657 } else { 658 /* DPCM Be's CPU = dummy */ 659 dai_props[i].cpus = 660 dai_link[i].cpus = &priv->dummy; 661 dai_props[i].num.cpus = 662 dai_link[i].num_cpus = 1; 663 } 664 665 if (li->num[i].codecs) { 666 /* Normal Codec */ 667 dai_props[i].codecs = 668 dai_link[i].codecs = dlcs; 669 dai_props[i].num.codecs = 670 dai_link[i].num_codecs = li->num[i].codecs; 671 dai_props[i].codec_dai = dais; 672 673 dlcs += li->num[i].codecs; 674 dais += li->num[i].codecs; 675 676 if (!li->num[i].cpus) { 677 /* DPCM Be's Codec */ 678 dai_props[i].codec_conf = cconf; 679 cconf += li->num[i].codecs; 680 } 681 } else { 682 /* DPCM Fe's Codec = dummy */ 683 dai_props[i].codecs = 684 dai_link[i].codecs = &priv->dummy; 685 dai_props[i].num.codecs = 686 dai_link[i].num_codecs = 1; 687 } 688 689 if (li->num[i].platforms) { 690 /* Have Platform */ 691 dai_props[i].platforms = 692 dai_link[i].platforms = dlcs; 693 dai_props[i].num.platforms = 694 dai_link[i].num_platforms = li->num[i].platforms; 695 696 dlcs += li->num[i].platforms; 697 } else { 698 /* Doesn't have Platform */ 699 dai_props[i].platforms = 700 dai_link[i].platforms = NULL; 701 dai_props[i].num.platforms = 702 dai_link[i].num_platforms = 0; 703 } 704 } 705 706 return 0; 707 } 708 EXPORT_SYMBOL_GPL(asoc_simple_init_priv); 709 710 int asoc_simple_remove(struct platform_device *pdev) 711 { 712 struct snd_soc_card *card = platform_get_drvdata(pdev); 713 714 return asoc_simple_clean_reference(card); 715 } 716 EXPORT_SYMBOL_GPL(asoc_simple_remove); 717 718 int asoc_graph_card_probe(struct snd_soc_card *card) 719 { 720 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); 721 int ret; 722 723 ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL); 724 if (ret < 0) 725 return ret; 726 727 ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL); 728 if (ret < 0) 729 return ret; 730 731 return 0; 732 } 733 EXPORT_SYMBOL_GPL(asoc_graph_card_probe); 734 735 int asoc_graph_is_ports0(struct device_node *np) 736 { 737 struct device_node *port, *ports, *ports0, *top; 738 int ret; 739 740 /* np is "endpoint" or "port" */ 741 if (of_node_name_eq(np, "endpoint")) { 742 port = of_get_parent(np); 743 } else { 744 port = np; 745 of_node_get(port); 746 } 747 748 ports = of_get_parent(port); 749 top = of_get_parent(ports); 750 ports0 = of_get_child_by_name(top, "ports"); 751 752 ret = ports0 == ports; 753 754 of_node_put(port); 755 of_node_put(ports); 756 of_node_put(ports0); 757 of_node_put(top); 758 759 return ret; 760 } 761 EXPORT_SYMBOL_GPL(asoc_graph_is_ports0); 762 763 /* Module information */ 764 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 765 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); 766 MODULE_LICENSE("GPL v2"); 767