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_graph.h> 13 #include <sound/jack.h> 14 #include <sound/pcm_params.h> 15 #include <sound/simple_card_utils.h> 16 17 static void asoc_simple_fixup_sample_fmt(struct asoc_simple_data *data, 18 struct snd_pcm_hw_params *params) 19 { 20 int i; 21 struct snd_mask *mask = hw_param_mask(params, 22 SNDRV_PCM_HW_PARAM_FORMAT); 23 struct { 24 char *fmt; 25 u32 val; 26 } of_sample_fmt_table[] = { 27 { "s8", SNDRV_PCM_FORMAT_S8}, 28 { "s16_le", SNDRV_PCM_FORMAT_S16_LE}, 29 { "s24_le", SNDRV_PCM_FORMAT_S24_LE}, 30 { "s24_3le", SNDRV_PCM_FORMAT_S24_3LE}, 31 { "s32_le", SNDRV_PCM_FORMAT_S32_LE}, 32 }; 33 34 for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) { 35 if (!strcmp(data->convert_sample_format, 36 of_sample_fmt_table[i].fmt)) { 37 snd_mask_none(mask); 38 snd_mask_set(mask, of_sample_fmt_table[i].val); 39 break; 40 } 41 } 42 } 43 44 void asoc_simple_convert_fixup(struct asoc_simple_data *data, 45 struct snd_pcm_hw_params *params) 46 { 47 struct snd_interval *rate = hw_param_interval(params, 48 SNDRV_PCM_HW_PARAM_RATE); 49 struct snd_interval *channels = hw_param_interval(params, 50 SNDRV_PCM_HW_PARAM_CHANNELS); 51 52 if (data->convert_rate) 53 rate->min = 54 rate->max = data->convert_rate; 55 56 if (data->convert_channels) 57 channels->min = 58 channels->max = data->convert_channels; 59 60 if (data->convert_sample_format) 61 asoc_simple_fixup_sample_fmt(data, params); 62 } 63 EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup); 64 65 void asoc_simple_parse_convert(struct device_node *np, 66 char *prefix, 67 struct asoc_simple_data *data) 68 { 69 char prop[128]; 70 71 if (!prefix) 72 prefix = ""; 73 74 /* sampling rate convert */ 75 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate"); 76 of_property_read_u32(np, prop, &data->convert_rate); 77 78 /* channels transfer */ 79 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels"); 80 of_property_read_u32(np, prop, &data->convert_channels); 81 82 /* convert sample format */ 83 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-sample-format"); 84 of_property_read_string(np, prop, &data->convert_sample_format); 85 } 86 EXPORT_SYMBOL_GPL(asoc_simple_parse_convert); 87 88 /** 89 * asoc_simple_is_convert_required() - Query if HW param conversion was requested 90 * @data: Link data. 91 * 92 * Returns true if any HW param conversion was requested for this DAI link with 93 * any "convert-xxx" properties. 94 */ 95 bool asoc_simple_is_convert_required(const struct asoc_simple_data *data) 96 { 97 return data->convert_rate || 98 data->convert_channels || 99 data->convert_sample_format; 100 } 101 EXPORT_SYMBOL_GPL(asoc_simple_is_convert_required); 102 103 int asoc_simple_parse_daifmt(struct device *dev, 104 struct device_node *node, 105 struct device_node *codec, 106 char *prefix, 107 unsigned int *retfmt) 108 { 109 struct device_node *bitclkmaster = NULL; 110 struct device_node *framemaster = NULL; 111 unsigned int daifmt; 112 113 daifmt = snd_soc_daifmt_parse_format(node, prefix); 114 115 snd_soc_daifmt_parse_clock_provider_as_phandle(node, prefix, &bitclkmaster, &framemaster); 116 if (!bitclkmaster && !framemaster) { 117 /* 118 * No dai-link level and master setting was not found from 119 * sound node level, revert back to legacy DT parsing and 120 * take the settings from codec node. 121 */ 122 dev_dbg(dev, "Revert to legacy daifmt parsing\n"); 123 124 daifmt |= snd_soc_daifmt_parse_clock_provider_as_flag(codec, NULL); 125 } else { 126 daifmt |= snd_soc_daifmt_clock_provider_from_bitmap( 127 ((codec == bitclkmaster) << 4) | (codec == framemaster)); 128 } 129 130 of_node_put(bitclkmaster); 131 of_node_put(framemaster); 132 133 *retfmt = daifmt; 134 135 return 0; 136 } 137 EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt); 138 139 int asoc_simple_parse_tdm_width_map(struct device *dev, struct device_node *np, 140 struct asoc_simple_dai *dai) 141 { 142 u32 *array_values, *p; 143 int n, i, ret; 144 145 if (!of_property_read_bool(np, "dai-tdm-slot-width-map")) 146 return 0; 147 148 n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32)); 149 if (n % 3) { 150 dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n"); 151 return -EINVAL; 152 } 153 154 dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL); 155 if (!dai->tdm_width_map) 156 return -ENOMEM; 157 158 array_values = kcalloc(n, sizeof(*array_values), GFP_KERNEL); 159 if (!array_values) 160 return -ENOMEM; 161 162 ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n); 163 if (ret < 0) { 164 dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret); 165 goto out; 166 } 167 168 p = array_values; 169 for (i = 0; i < n / 3; ++i) { 170 dai->tdm_width_map[i].sample_bits = *p++; 171 dai->tdm_width_map[i].slot_width = *p++; 172 dai->tdm_width_map[i].slot_count = *p++; 173 } 174 175 dai->n_tdm_widths = i; 176 ret = 0; 177 out: 178 kfree(array_values); 179 180 return ret; 181 } 182 EXPORT_SYMBOL_GPL(asoc_simple_parse_tdm_width_map); 183 184 int asoc_simple_set_dailink_name(struct device *dev, 185 struct snd_soc_dai_link *dai_link, 186 const char *fmt, ...) 187 { 188 va_list ap; 189 char *name = NULL; 190 int ret = -ENOMEM; 191 192 va_start(ap, fmt); 193 name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap); 194 va_end(ap); 195 196 if (name) { 197 ret = 0; 198 199 dai_link->name = name; 200 dai_link->stream_name = name; 201 } 202 203 return ret; 204 } 205 EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name); 206 207 int asoc_simple_parse_card_name(struct snd_soc_card *card, 208 char *prefix) 209 { 210 int ret; 211 212 if (!prefix) 213 prefix = ""; 214 215 /* Parse the card name from DT */ 216 ret = snd_soc_of_parse_card_name(card, "label"); 217 if (ret < 0 || !card->name) { 218 char prop[128]; 219 220 snprintf(prop, sizeof(prop), "%sname", prefix); 221 ret = snd_soc_of_parse_card_name(card, prop); 222 if (ret < 0) 223 return ret; 224 } 225 226 if (!card->name && card->dai_link) 227 card->name = card->dai_link->name; 228 229 return 0; 230 } 231 EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name); 232 233 static int asoc_simple_clk_enable(struct asoc_simple_dai *dai) 234 { 235 if (dai) 236 return clk_prepare_enable(dai->clk); 237 238 return 0; 239 } 240 241 static void asoc_simple_clk_disable(struct asoc_simple_dai *dai) 242 { 243 if (dai) 244 clk_disable_unprepare(dai->clk); 245 } 246 247 int asoc_simple_parse_clk(struct device *dev, 248 struct device_node *node, 249 struct asoc_simple_dai *simple_dai, 250 struct snd_soc_dai_link_component *dlc) 251 { 252 struct clk *clk; 253 u32 val; 254 255 /* 256 * Parse dai->sysclk come from "clocks = <&xxx>" 257 * (if system has common clock) 258 * or "system-clock-frequency = <xxx>" 259 * or device's module clock. 260 */ 261 clk = devm_get_clk_from_child(dev, node, NULL); 262 simple_dai->clk_fixed = of_property_read_bool( 263 node, "system-clock-fixed"); 264 if (!IS_ERR(clk)) { 265 simple_dai->sysclk = clk_get_rate(clk); 266 267 simple_dai->clk = clk; 268 } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { 269 simple_dai->sysclk = val; 270 simple_dai->clk_fixed = true; 271 } else { 272 clk = devm_get_clk_from_child(dev, dlc->of_node, NULL); 273 if (!IS_ERR(clk)) 274 simple_dai->sysclk = clk_get_rate(clk); 275 } 276 277 if (of_property_read_bool(node, "system-clock-direction-out")) 278 simple_dai->clk_direction = SND_SOC_CLOCK_OUT; 279 280 return 0; 281 } 282 EXPORT_SYMBOL_GPL(asoc_simple_parse_clk); 283 284 static int asoc_simple_check_fixed_sysclk(struct device *dev, 285 struct asoc_simple_dai *dai, 286 unsigned int *fixed_sysclk) 287 { 288 if (dai->clk_fixed) { 289 if (*fixed_sysclk && *fixed_sysclk != dai->sysclk) { 290 dev_err(dev, "inconsistent fixed sysclk rates (%u vs %u)\n", 291 *fixed_sysclk, dai->sysclk); 292 return -EINVAL; 293 } 294 *fixed_sysclk = dai->sysclk; 295 } 296 297 return 0; 298 } 299 300 int asoc_simple_startup(struct snd_pcm_substream *substream) 301 { 302 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 303 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 304 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); 305 struct asoc_simple_dai *dai; 306 unsigned int fixed_sysclk = 0; 307 int i1, i2, i; 308 int ret; 309 310 for_each_prop_dai_cpu(props, i1, dai) { 311 ret = asoc_simple_clk_enable(dai); 312 if (ret) 313 goto cpu_err; 314 ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk); 315 if (ret) 316 goto cpu_err; 317 } 318 319 for_each_prop_dai_codec(props, i2, dai) { 320 ret = asoc_simple_clk_enable(dai); 321 if (ret) 322 goto codec_err; 323 ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk); 324 if (ret) 325 goto codec_err; 326 } 327 328 if (fixed_sysclk && props->mclk_fs) { 329 unsigned int fixed_rate = fixed_sysclk / props->mclk_fs; 330 331 if (fixed_sysclk % props->mclk_fs) { 332 dev_err(rtd->dev, "fixed sysclk %u not divisible by mclk_fs %u\n", 333 fixed_sysclk, props->mclk_fs); 334 return -EINVAL; 335 } 336 ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, 337 fixed_rate, fixed_rate); 338 if (ret) 339 goto codec_err; 340 } 341 342 return 0; 343 344 codec_err: 345 for_each_prop_dai_codec(props, i, dai) { 346 if (i >= i2) 347 break; 348 asoc_simple_clk_disable(dai); 349 } 350 cpu_err: 351 for_each_prop_dai_cpu(props, i, dai) { 352 if (i >= i1) 353 break; 354 asoc_simple_clk_disable(dai); 355 } 356 return ret; 357 } 358 EXPORT_SYMBOL_GPL(asoc_simple_startup); 359 360 void asoc_simple_shutdown(struct snd_pcm_substream *substream) 361 { 362 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 363 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 364 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); 365 struct asoc_simple_dai *dai; 366 int i; 367 368 for_each_prop_dai_cpu(props, i, dai) { 369 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, i); 370 371 if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(cpu_dai)) 372 snd_soc_dai_set_sysclk(cpu_dai, 373 0, 0, SND_SOC_CLOCK_OUT); 374 375 asoc_simple_clk_disable(dai); 376 } 377 for_each_prop_dai_codec(props, i, dai) { 378 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, i); 379 380 if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(codec_dai)) 381 snd_soc_dai_set_sysclk(codec_dai, 382 0, 0, SND_SOC_CLOCK_IN); 383 384 asoc_simple_clk_disable(dai); 385 } 386 } 387 EXPORT_SYMBOL_GPL(asoc_simple_shutdown); 388 389 static int asoc_simple_set_clk_rate(struct device *dev, 390 struct asoc_simple_dai *simple_dai, 391 unsigned long rate) 392 { 393 if (!simple_dai) 394 return 0; 395 396 if (simple_dai->clk_fixed && rate != simple_dai->sysclk) { 397 dev_err(dev, "dai %s invalid clock rate %lu\n", simple_dai->name, rate); 398 return -EINVAL; 399 } 400 401 if (!simple_dai->clk) 402 return 0; 403 404 if (clk_get_rate(simple_dai->clk) == rate) 405 return 0; 406 407 return clk_set_rate(simple_dai->clk, rate); 408 } 409 410 static int asoc_simple_set_tdm(struct snd_soc_dai *dai, 411 struct asoc_simple_dai *simple_dai, 412 struct snd_pcm_hw_params *params) 413 { 414 int sample_bits = params_width(params); 415 int slot_width, slot_count; 416 int i, ret; 417 418 if (!simple_dai || !simple_dai->tdm_width_map) 419 return 0; 420 421 slot_width = simple_dai->slot_width; 422 slot_count = simple_dai->slots; 423 424 if (slot_width == 0) 425 slot_width = sample_bits; 426 427 for (i = 0; i < simple_dai->n_tdm_widths; ++i) { 428 if (simple_dai->tdm_width_map[i].sample_bits == sample_bits) { 429 slot_width = simple_dai->tdm_width_map[i].slot_width; 430 slot_count = simple_dai->tdm_width_map[i].slot_count; 431 break; 432 } 433 } 434 435 ret = snd_soc_dai_set_tdm_slot(dai, 436 simple_dai->tx_slot_mask, 437 simple_dai->rx_slot_mask, 438 slot_count, 439 slot_width); 440 if (ret && ret != -ENOTSUPP) { 441 dev_err(dai->dev, "simple-card: set_tdm_slot error: %d\n", ret); 442 return ret; 443 } 444 445 return 0; 446 } 447 448 int asoc_simple_hw_params(struct snd_pcm_substream *substream, 449 struct snd_pcm_hw_params *params) 450 { 451 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 452 struct asoc_simple_dai *pdai; 453 struct snd_soc_dai *sdai; 454 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 455 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); 456 unsigned int mclk, mclk_fs = 0; 457 int i, ret; 458 459 if (props->mclk_fs) 460 mclk_fs = props->mclk_fs; 461 462 if (mclk_fs) { 463 struct snd_soc_component *component; 464 mclk = params_rate(params) * mclk_fs; 465 466 for_each_prop_dai_codec(props, i, pdai) { 467 ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk); 468 if (ret < 0) 469 return ret; 470 } 471 472 for_each_prop_dai_cpu(props, i, pdai) { 473 ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk); 474 if (ret < 0) 475 return ret; 476 } 477 478 /* Ensure sysclk is set on all components in case any 479 * (such as platform components) are missed by calls to 480 * snd_soc_dai_set_sysclk. 481 */ 482 for_each_rtd_components(rtd, i, component) { 483 ret = snd_soc_component_set_sysclk(component, 0, 0, 484 mclk, SND_SOC_CLOCK_IN); 485 if (ret && ret != -ENOTSUPP) 486 return ret; 487 } 488 489 for_each_rtd_codec_dais(rtd, i, sdai) { 490 ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN); 491 if (ret && ret != -ENOTSUPP) 492 return ret; 493 } 494 495 for_each_rtd_cpu_dais(rtd, i, sdai) { 496 ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT); 497 if (ret && ret != -ENOTSUPP) 498 return ret; 499 } 500 } 501 502 for_each_prop_dai_codec(props, i, pdai) { 503 sdai = asoc_rtd_to_codec(rtd, i); 504 ret = asoc_simple_set_tdm(sdai, pdai, params); 505 if (ret < 0) 506 return ret; 507 } 508 509 for_each_prop_dai_cpu(props, i, pdai) { 510 sdai = asoc_rtd_to_cpu(rtd, i); 511 ret = asoc_simple_set_tdm(sdai, pdai, params); 512 if (ret < 0) 513 return ret; 514 } 515 516 return 0; 517 } 518 EXPORT_SYMBOL_GPL(asoc_simple_hw_params); 519 520 int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 521 struct snd_pcm_hw_params *params) 522 { 523 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 524 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); 525 526 asoc_simple_convert_fixup(&dai_props->adata, params); 527 528 return 0; 529 } 530 EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup); 531 532 static int asoc_simple_init_dai(struct snd_soc_dai *dai, 533 struct asoc_simple_dai *simple_dai) 534 { 535 int ret; 536 537 if (!simple_dai) 538 return 0; 539 540 if (simple_dai->sysclk) { 541 ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, 542 simple_dai->clk_direction); 543 if (ret && ret != -ENOTSUPP) { 544 dev_err(dai->dev, "simple-card: set_sysclk error\n"); 545 return ret; 546 } 547 } 548 549 if (simple_dai->slots) { 550 ret = snd_soc_dai_set_tdm_slot(dai, 551 simple_dai->tx_slot_mask, 552 simple_dai->rx_slot_mask, 553 simple_dai->slots, 554 simple_dai->slot_width); 555 if (ret && ret != -ENOTSUPP) { 556 dev_err(dai->dev, "simple-card: set_tdm_slot error\n"); 557 return ret; 558 } 559 } 560 561 return 0; 562 } 563 564 static inline int asoc_simple_component_is_codec(struct snd_soc_component *component) 565 { 566 return component->driver->endianness; 567 } 568 569 static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, 570 struct simple_dai_props *dai_props) 571 { 572 struct snd_soc_dai_link *dai_link = rtd->dai_link; 573 struct snd_soc_component *component; 574 struct snd_soc_pcm_stream *params; 575 struct snd_pcm_hardware hw; 576 int i, ret, stream; 577 578 /* Do nothing if it already has Codec2Codec settings */ 579 if (dai_link->params) 580 return 0; 581 582 /* Do nothing if it was DPCM :: BE */ 583 if (dai_link->no_pcm) 584 return 0; 585 586 /* Only Codecs */ 587 for_each_rtd_components(rtd, i, component) { 588 if (!asoc_simple_component_is_codec(component)) 589 return 0; 590 } 591 592 /* Assumes the capabilities are the same for all supported streams */ 593 for_each_pcm_streams(stream) { 594 ret = snd_soc_runtime_calc_hw(rtd, &hw, stream); 595 if (ret == 0) 596 break; 597 } 598 599 if (ret < 0) { 600 dev_err(rtd->dev, "simple-card: no valid dai_link params\n"); 601 return ret; 602 } 603 604 params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL); 605 if (!params) 606 return -ENOMEM; 607 608 params->formats = hw.formats; 609 params->rates = hw.rates; 610 params->rate_min = hw.rate_min; 611 params->rate_max = hw.rate_max; 612 params->channels_min = hw.channels_min; 613 params->channels_max = hw.channels_max; 614 615 dai_link->params = params; 616 dai_link->num_params = 1; 617 618 return 0; 619 } 620 621 int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd) 622 { 623 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 624 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); 625 struct asoc_simple_dai *dai; 626 int i, ret; 627 628 for_each_prop_dai_codec(props, i, dai) { 629 ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai); 630 if (ret < 0) 631 return ret; 632 } 633 for_each_prop_dai_cpu(props, i, dai) { 634 ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai); 635 if (ret < 0) 636 return ret; 637 } 638 639 ret = asoc_simple_init_for_codec2codec(rtd, props); 640 if (ret < 0) 641 return ret; 642 643 return 0; 644 } 645 EXPORT_SYMBOL_GPL(asoc_simple_dai_init); 646 647 void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms, 648 struct snd_soc_dai_link_component *cpus) 649 { 650 /* Assumes platform == cpu */ 651 if (!platforms->of_node) 652 platforms->of_node = cpus->of_node; 653 } 654 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); 655 656 void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, 657 int is_single_links) 658 { 659 /* 660 * In soc_bind_dai_link() will check cpu name after 661 * of_node matching if dai_link has cpu_dai_name. 662 * but, it will never match if name was created by 663 * fmt_single_name() remove cpu_dai_name if cpu_args 664 * was 0. See: 665 * fmt_single_name() 666 * fmt_multiple_name() 667 */ 668 if (is_single_links) 669 cpus->dai_name = NULL; 670 } 671 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu); 672 673 void asoc_simple_clean_reference(struct snd_soc_card *card) 674 { 675 struct snd_soc_dai_link *dai_link; 676 struct snd_soc_dai_link_component *cpu; 677 struct snd_soc_dai_link_component *codec; 678 int i, j; 679 680 for_each_card_prelinks(card, i, dai_link) { 681 for_each_link_cpus(dai_link, j, cpu) 682 of_node_put(cpu->of_node); 683 for_each_link_codecs(dai_link, j, codec) 684 of_node_put(codec->of_node); 685 } 686 } 687 EXPORT_SYMBOL_GPL(asoc_simple_clean_reference); 688 689 int asoc_simple_parse_routing(struct snd_soc_card *card, 690 char *prefix) 691 { 692 struct device_node *node = card->dev->of_node; 693 char prop[128]; 694 695 if (!prefix) 696 prefix = ""; 697 698 snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); 699 700 if (!of_property_read_bool(node, prop)) 701 return 0; 702 703 return snd_soc_of_parse_audio_routing(card, prop); 704 } 705 EXPORT_SYMBOL_GPL(asoc_simple_parse_routing); 706 707 int asoc_simple_parse_widgets(struct snd_soc_card *card, 708 char *prefix) 709 { 710 struct device_node *node = card->dev->of_node; 711 char prop[128]; 712 713 if (!prefix) 714 prefix = ""; 715 716 snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets"); 717 718 if (of_property_read_bool(node, prop)) 719 return snd_soc_of_parse_audio_simple_widgets(card, prop); 720 721 /* no widgets is not error */ 722 return 0; 723 } 724 EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets); 725 726 int asoc_simple_parse_pin_switches(struct snd_soc_card *card, 727 char *prefix) 728 { 729 char prop[128]; 730 731 if (!prefix) 732 prefix = ""; 733 734 snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches"); 735 736 return snd_soc_of_parse_pin_switches(card, prop); 737 } 738 EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches); 739 740 int asoc_simple_init_jack(struct snd_soc_card *card, 741 struct asoc_simple_jack *sjack, 742 int is_hp, char *prefix, 743 char *pin) 744 { 745 struct device *dev = card->dev; 746 struct gpio_desc *desc; 747 char prop[128]; 748 char *pin_name; 749 char *gpio_name; 750 int mask; 751 int error; 752 753 if (!prefix) 754 prefix = ""; 755 756 sjack->gpio.gpio = -ENOENT; 757 758 if (is_hp) { 759 snprintf(prop, sizeof(prop), "%shp-det", prefix); 760 pin_name = pin ? pin : "Headphones"; 761 gpio_name = "Headphone detection"; 762 mask = SND_JACK_HEADPHONE; 763 } else { 764 snprintf(prop, sizeof(prop), "%smic-det", prefix); 765 pin_name = pin ? pin : "Mic Jack"; 766 gpio_name = "Mic detection"; 767 mask = SND_JACK_MICROPHONE; 768 } 769 770 desc = gpiod_get_optional(dev, prop, GPIOD_IN); 771 error = PTR_ERR_OR_ZERO(desc); 772 if (error) 773 return error; 774 775 if (desc) { 776 error = gpiod_set_consumer_name(desc, gpio_name); 777 if (error) 778 return error; 779 780 sjack->pin.pin = pin_name; 781 sjack->pin.mask = mask; 782 783 sjack->gpio.name = gpio_name; 784 sjack->gpio.report = mask; 785 sjack->gpio.desc = desc; 786 sjack->gpio.debounce_time = 150; 787 788 snd_soc_card_jack_new_pins(card, pin_name, mask, &sjack->jack, 789 &sjack->pin, 1); 790 791 snd_soc_jack_add_gpios(&sjack->jack, 1, &sjack->gpio); 792 } 793 794 return 0; 795 } 796 EXPORT_SYMBOL_GPL(asoc_simple_init_jack); 797 798 int asoc_simple_init_priv(struct asoc_simple_priv *priv, 799 struct link_info *li) 800 { 801 struct snd_soc_card *card = simple_priv_to_card(priv); 802 struct device *dev = simple_priv_to_dev(priv); 803 struct snd_soc_dai_link *dai_link; 804 struct simple_dai_props *dai_props; 805 struct asoc_simple_dai *dais; 806 struct snd_soc_dai_link_component *dlcs; 807 struct snd_soc_codec_conf *cconf = NULL; 808 int i, dai_num = 0, dlc_num = 0, cnf_num = 0; 809 810 dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL); 811 dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL); 812 if (!dai_props || !dai_link) 813 return -ENOMEM; 814 815 /* 816 * dais (= CPU+Codec) 817 * dlcs (= CPU+Codec+Platform) 818 */ 819 for (i = 0; i < li->link; i++) { 820 int cc = li->num[i].cpus + li->num[i].codecs; 821 822 dai_num += cc; 823 dlc_num += cc + li->num[i].platforms; 824 825 if (!li->num[i].cpus) 826 cnf_num += li->num[i].codecs; 827 } 828 829 dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL); 830 dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL); 831 if (!dais || !dlcs) 832 return -ENOMEM; 833 834 if (cnf_num) { 835 cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL); 836 if (!cconf) 837 return -ENOMEM; 838 } 839 840 dev_dbg(dev, "link %d, dais %d, ccnf %d\n", 841 li->link, dai_num, cnf_num); 842 843 /* dummy CPU/Codec */ 844 priv->dummy.of_node = NULL; 845 priv->dummy.dai_name = "snd-soc-dummy-dai"; 846 priv->dummy.name = "snd-soc-dummy"; 847 848 priv->dai_props = dai_props; 849 priv->dai_link = dai_link; 850 priv->dais = dais; 851 priv->dlcs = dlcs; 852 priv->codec_conf = cconf; 853 854 card->dai_link = priv->dai_link; 855 card->num_links = li->link; 856 card->codec_conf = cconf; 857 card->num_configs = cnf_num; 858 859 for (i = 0; i < li->link; i++) { 860 if (li->num[i].cpus) { 861 /* Normal CPU */ 862 dai_props[i].cpus = 863 dai_link[i].cpus = dlcs; 864 dai_props[i].num.cpus = 865 dai_link[i].num_cpus = li->num[i].cpus; 866 dai_props[i].cpu_dai = dais; 867 868 dlcs += li->num[i].cpus; 869 dais += li->num[i].cpus; 870 } else { 871 /* DPCM Be's CPU = dummy */ 872 dai_props[i].cpus = 873 dai_link[i].cpus = &priv->dummy; 874 dai_props[i].num.cpus = 875 dai_link[i].num_cpus = 1; 876 } 877 878 if (li->num[i].codecs) { 879 /* Normal Codec */ 880 dai_props[i].codecs = 881 dai_link[i].codecs = dlcs; 882 dai_props[i].num.codecs = 883 dai_link[i].num_codecs = li->num[i].codecs; 884 dai_props[i].codec_dai = dais; 885 886 dlcs += li->num[i].codecs; 887 dais += li->num[i].codecs; 888 889 if (!li->num[i].cpus) { 890 /* DPCM Be's Codec */ 891 dai_props[i].codec_conf = cconf; 892 cconf += li->num[i].codecs; 893 } 894 } else { 895 /* DPCM Fe's Codec = dummy */ 896 dai_props[i].codecs = 897 dai_link[i].codecs = &priv->dummy; 898 dai_props[i].num.codecs = 899 dai_link[i].num_codecs = 1; 900 } 901 902 if (li->num[i].platforms) { 903 /* Have Platform */ 904 dai_props[i].platforms = 905 dai_link[i].platforms = dlcs; 906 dai_props[i].num.platforms = 907 dai_link[i].num_platforms = li->num[i].platforms; 908 909 dlcs += li->num[i].platforms; 910 } else { 911 /* Doesn't have Platform */ 912 dai_props[i].platforms = 913 dai_link[i].platforms = NULL; 914 dai_props[i].num.platforms = 915 dai_link[i].num_platforms = 0; 916 } 917 } 918 919 return 0; 920 } 921 EXPORT_SYMBOL_GPL(asoc_simple_init_priv); 922 923 int asoc_simple_remove(struct platform_device *pdev) 924 { 925 struct snd_soc_card *card = platform_get_drvdata(pdev); 926 927 asoc_simple_clean_reference(card); 928 929 return 0; 930 } 931 EXPORT_SYMBOL_GPL(asoc_simple_remove); 932 933 int asoc_graph_card_probe(struct snd_soc_card *card) 934 { 935 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); 936 int ret; 937 938 ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL); 939 if (ret < 0) 940 return ret; 941 942 ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL); 943 if (ret < 0) 944 return ret; 945 946 return 0; 947 } 948 EXPORT_SYMBOL_GPL(asoc_graph_card_probe); 949 950 int asoc_graph_is_ports0(struct device_node *np) 951 { 952 struct device_node *port, *ports, *ports0, *top; 953 int ret; 954 955 /* np is "endpoint" or "port" */ 956 if (of_node_name_eq(np, "endpoint")) { 957 port = of_get_parent(np); 958 } else { 959 port = np; 960 of_node_get(port); 961 } 962 963 ports = of_get_parent(port); 964 top = of_get_parent(ports); 965 ports0 = of_get_child_by_name(top, "ports"); 966 967 ret = ports0 == ports; 968 969 of_node_put(port); 970 of_node_put(ports); 971 of_node_put(ports0); 972 of_node_put(top); 973 974 return ret; 975 } 976 EXPORT_SYMBOL_GPL(asoc_graph_is_ports0); 977 978 /* Module information */ 979 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 980 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); 981 MODULE_LICENSE("GPL v2"); 982