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 should have non_legacy_dai_naming set. */ 359 for_each_rtd_components(rtd, i, component) { 360 if (!component->driver->non_legacy_dai_naming) 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 const unsigned int nb_controls_max = 16; 503 const char **strings, *control_name; 504 struct snd_kcontrol_new *controls; 505 struct device *dev = card->dev; 506 unsigned int i, nb_controls; 507 char prop[128]; 508 int ret; 509 510 if (!prefix) 511 prefix = ""; 512 513 snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches"); 514 515 if (!of_property_read_bool(dev->of_node, prop)) 516 return 0; 517 518 strings = devm_kcalloc(dev, nb_controls_max, 519 sizeof(*strings), GFP_KERNEL); 520 if (!strings) 521 return -ENOMEM; 522 523 ret = of_property_read_string_array(dev->of_node, prop, 524 strings, nb_controls_max); 525 if (ret < 0) 526 return ret; 527 528 nb_controls = (unsigned int)ret; 529 530 controls = devm_kcalloc(dev, nb_controls, 531 sizeof(*controls), GFP_KERNEL); 532 if (!controls) 533 return -ENOMEM; 534 535 for (i = 0; i < nb_controls; i++) { 536 control_name = devm_kasprintf(dev, GFP_KERNEL, 537 "%s Switch", strings[i]); 538 if (!control_name) 539 return -ENOMEM; 540 541 controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; 542 controls[i].name = control_name; 543 controls[i].info = snd_soc_dapm_info_pin_switch; 544 controls[i].get = snd_soc_dapm_get_pin_switch; 545 controls[i].put = snd_soc_dapm_put_pin_switch; 546 controls[i].private_value = (unsigned long)strings[i]; 547 } 548 549 card->controls = controls; 550 card->num_controls = nb_controls; 551 552 return 0; 553 } 554 EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches); 555 556 int asoc_simple_init_jack(struct snd_soc_card *card, 557 struct asoc_simple_jack *sjack, 558 int is_hp, char *prefix, 559 char *pin) 560 { 561 struct device *dev = card->dev; 562 enum of_gpio_flags flags; 563 char prop[128]; 564 char *pin_name; 565 char *gpio_name; 566 int mask; 567 int det; 568 569 if (!prefix) 570 prefix = ""; 571 572 sjack->gpio.gpio = -ENOENT; 573 574 if (is_hp) { 575 snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix); 576 pin_name = pin ? pin : "Headphones"; 577 gpio_name = "Headphone detection"; 578 mask = SND_JACK_HEADPHONE; 579 } else { 580 snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix); 581 pin_name = pin ? pin : "Mic Jack"; 582 gpio_name = "Mic detection"; 583 mask = SND_JACK_MICROPHONE; 584 } 585 586 det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags); 587 if (det == -EPROBE_DEFER) 588 return -EPROBE_DEFER; 589 590 if (gpio_is_valid(det)) { 591 sjack->pin.pin = pin_name; 592 sjack->pin.mask = mask; 593 594 sjack->gpio.name = gpio_name; 595 sjack->gpio.report = mask; 596 sjack->gpio.gpio = det; 597 sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW); 598 sjack->gpio.debounce_time = 150; 599 600 snd_soc_card_jack_new(card, pin_name, mask, 601 &sjack->jack, 602 &sjack->pin, 1); 603 604 snd_soc_jack_add_gpios(&sjack->jack, 1, 605 &sjack->gpio); 606 } 607 608 return 0; 609 } 610 EXPORT_SYMBOL_GPL(asoc_simple_init_jack); 611 612 int asoc_simple_init_priv(struct asoc_simple_priv *priv, 613 struct link_info *li) 614 { 615 struct snd_soc_card *card = simple_priv_to_card(priv); 616 struct device *dev = simple_priv_to_dev(priv); 617 struct snd_soc_dai_link *dai_link; 618 struct simple_dai_props *dai_props; 619 struct asoc_simple_dai *dais; 620 struct snd_soc_dai_link_component *dlcs; 621 struct snd_soc_codec_conf *cconf = NULL; 622 int i, dai_num = 0, dlc_num = 0, cnf_num = 0; 623 624 dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL); 625 dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL); 626 if (!dai_props || !dai_link) 627 return -ENOMEM; 628 629 /* 630 * dais (= CPU+Codec) 631 * dlcs (= CPU+Codec+Platform) 632 */ 633 for (i = 0; i < li->link; i++) { 634 int cc = li->num[i].cpus + li->num[i].codecs; 635 636 dai_num += cc; 637 dlc_num += cc + li->num[i].platforms; 638 639 if (!li->num[i].cpus) 640 cnf_num += li->num[i].codecs; 641 } 642 643 dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL); 644 dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL); 645 if (!dais || !dlcs) 646 return -ENOMEM; 647 648 if (cnf_num) { 649 cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL); 650 if (!cconf) 651 return -ENOMEM; 652 } 653 654 dev_dbg(dev, "link %d, dais %d, ccnf %d\n", 655 li->link, dai_num, cnf_num); 656 657 /* dummy CPU/Codec */ 658 priv->dummy.of_node = NULL; 659 priv->dummy.dai_name = "snd-soc-dummy-dai"; 660 priv->dummy.name = "snd-soc-dummy"; 661 662 priv->dai_props = dai_props; 663 priv->dai_link = dai_link; 664 priv->dais = dais; 665 priv->dlcs = dlcs; 666 priv->codec_conf = cconf; 667 668 card->dai_link = priv->dai_link; 669 card->num_links = li->link; 670 card->codec_conf = cconf; 671 card->num_configs = cnf_num; 672 673 for (i = 0; i < li->link; i++) { 674 if (li->num[i].cpus) { 675 /* Normal CPU */ 676 dai_props[i].cpus = 677 dai_link[i].cpus = dlcs; 678 dai_props[i].num.cpus = 679 dai_link[i].num_cpus = li->num[i].cpus; 680 dai_props[i].cpu_dai = dais; 681 682 dlcs += li->num[i].cpus; 683 dais += li->num[i].cpus; 684 } else { 685 /* DPCM Be's CPU = dummy */ 686 dai_props[i].cpus = 687 dai_link[i].cpus = &priv->dummy; 688 dai_props[i].num.cpus = 689 dai_link[i].num_cpus = 1; 690 } 691 692 if (li->num[i].codecs) { 693 /* Normal Codec */ 694 dai_props[i].codecs = 695 dai_link[i].codecs = dlcs; 696 dai_props[i].num.codecs = 697 dai_link[i].num_codecs = li->num[i].codecs; 698 dai_props[i].codec_dai = dais; 699 700 dlcs += li->num[i].codecs; 701 dais += li->num[i].codecs; 702 703 if (!li->num[i].cpus) { 704 /* DPCM Be's Codec */ 705 dai_props[i].codec_conf = cconf; 706 cconf += li->num[i].codecs; 707 } 708 } else { 709 /* DPCM Fe's Codec = dummy */ 710 dai_props[i].codecs = 711 dai_link[i].codecs = &priv->dummy; 712 dai_props[i].num.codecs = 713 dai_link[i].num_codecs = 1; 714 } 715 716 if (li->num[i].platforms) { 717 /* Have Platform */ 718 dai_props[i].platforms = 719 dai_link[i].platforms = dlcs; 720 dai_props[i].num.platforms = 721 dai_link[i].num_platforms = li->num[i].platforms; 722 723 dlcs += li->num[i].platforms; 724 } else { 725 /* Doesn't have Platform */ 726 dai_props[i].platforms = 727 dai_link[i].platforms = NULL; 728 dai_props[i].num.platforms = 729 dai_link[i].num_platforms = 0; 730 } 731 } 732 733 return 0; 734 } 735 EXPORT_SYMBOL_GPL(asoc_simple_init_priv); 736 737 int asoc_simple_remove(struct platform_device *pdev) 738 { 739 struct snd_soc_card *card = platform_get_drvdata(pdev); 740 741 return asoc_simple_clean_reference(card); 742 } 743 EXPORT_SYMBOL_GPL(asoc_simple_remove); 744 745 int asoc_graph_card_probe(struct snd_soc_card *card) 746 { 747 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); 748 int ret; 749 750 ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL); 751 if (ret < 0) 752 return ret; 753 754 ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL); 755 if (ret < 0) 756 return ret; 757 758 return 0; 759 } 760 EXPORT_SYMBOL_GPL(asoc_graph_card_probe); 761 762 /* Module information */ 763 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 764 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); 765 MODULE_LICENSE("GPL v2"); 766