at v6.19 657 lines 17 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2// 3// test-component.c -- Test Audio Component driver 4// 5// Copyright (C) 2020 Renesas Electronics Corporation 6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7 8#include <linux/slab.h> 9#include <linux/of.h> 10#include <linux/of_graph.h> 11#include <linux/module.h> 12#include <linux/workqueue.h> 13#include <sound/pcm.h> 14#include <sound/soc.h> 15 16#define TEST_NAME_LEN 32 17struct test_dai_name { 18 char name[TEST_NAME_LEN]; 19 char name_playback[TEST_NAME_LEN]; 20 char name_capture[TEST_NAME_LEN]; 21}; 22 23struct test_priv { 24 struct device *dev; 25 struct snd_pcm_substream *substream; 26 struct delayed_work dwork; 27 struct snd_soc_component_driver *component_driver; 28 struct snd_soc_dai_driver *dai_driver; 29 struct test_dai_name *name; 30}; 31 32struct test_adata { 33 u32 is_cpu:1; 34 u32 cmp_v:1; 35 u32 dai_v:1; 36}; 37 38#define mile_stone(d) dev_info((d)->dev, "%s() : %s", __func__, (d)->driver->name) 39#define mile_stone_x(dev) dev_info(dev, "%s()", __func__) 40 41static int test_dai_set_sysclk(struct snd_soc_dai *dai, 42 int clk_id, unsigned int freq, int dir) 43{ 44 mile_stone(dai); 45 46 return 0; 47} 48 49static int test_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, 50 unsigned int freq_in, unsigned int freq_out) 51{ 52 mile_stone(dai); 53 54 return 0; 55} 56 57static int test_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) 58{ 59 mile_stone(dai); 60 61 return 0; 62} 63 64static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 65{ 66 unsigned int format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; 67 unsigned int clock = fmt & SND_SOC_DAIFMT_CLOCK_MASK; 68 unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK; 69 unsigned int master = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; 70 char *str; 71 72 dev_info(dai->dev, "name : %s", dai->name); 73 74 str = "unknown"; 75 switch (format) { 76 case SND_SOC_DAIFMT_I2S: 77 str = "i2s"; 78 break; 79 case SND_SOC_DAIFMT_RIGHT_J: 80 str = "right_j"; 81 break; 82 case SND_SOC_DAIFMT_LEFT_J: 83 str = "left_j"; 84 break; 85 case SND_SOC_DAIFMT_DSP_A: 86 str = "dsp_a"; 87 break; 88 case SND_SOC_DAIFMT_DSP_B: 89 str = "dsp_b"; 90 break; 91 case SND_SOC_DAIFMT_AC97: 92 str = "ac97"; 93 break; 94 case SND_SOC_DAIFMT_PDM: 95 str = "pdm"; 96 break; 97 } 98 dev_info(dai->dev, "format : %s", str); 99 100 if (clock == SND_SOC_DAIFMT_CONT) 101 str = "continuous"; 102 else 103 str = "gated"; 104 dev_info(dai->dev, "clock : %s", str); 105 106 str = "unknown"; 107 switch (master) { 108 case SND_SOC_DAIFMT_BP_FP: 109 str = "clk provider, frame provider"; 110 break; 111 case SND_SOC_DAIFMT_BC_FP: 112 str = "clk consumer, frame provider"; 113 break; 114 case SND_SOC_DAIFMT_BP_FC: 115 str = "clk provider, frame consumer"; 116 break; 117 case SND_SOC_DAIFMT_BC_FC: 118 str = "clk consumer, frame consumer"; 119 break; 120 } 121 dev_info(dai->dev, "clock : codec is %s", str); 122 123 str = "unknown"; 124 switch (inv) { 125 case SND_SOC_DAIFMT_NB_NF: 126 str = "normal bit, normal frame"; 127 break; 128 case SND_SOC_DAIFMT_NB_IF: 129 str = "normal bit, invert frame"; 130 break; 131 case SND_SOC_DAIFMT_IB_NF: 132 str = "invert bit, normal frame"; 133 break; 134 case SND_SOC_DAIFMT_IB_IF: 135 str = "invert bit, invert frame"; 136 break; 137 } 138 dev_info(dai->dev, "signal : %s", str); 139 140 return 0; 141} 142 143static int test_dai_set_tdm_slot(struct snd_soc_dai *dai, 144 unsigned int tx_mask, unsigned int rx_mask, 145 int slots, int slot_width) 146{ 147 dev_info(dai->dev, "set tdm slot: tx_mask=0x%08X, rx_mask=0x%08X, slots=%d, slot_width=%d\n", 148 tx_mask, rx_mask, slots, slot_width); 149 return 0; 150} 151 152static int test_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream) 153{ 154 mile_stone(dai); 155 156 return 0; 157} 158 159static int test_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 160{ 161 mile_stone(dai); 162 163 return 0; 164} 165 166static void test_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 167{ 168 mile_stone(dai); 169} 170 171static int test_dai_hw_params(struct snd_pcm_substream *substream, 172 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 173{ 174 mile_stone(dai); 175 176 return 0; 177} 178 179static int test_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 180{ 181 mile_stone(dai); 182 183 return 0; 184} 185 186static int test_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) 187{ 188 mile_stone(dai); 189 190 return 0; 191} 192 193static const u64 test_dai_formats = 194 /* 195 * Select below from Sound Card, not auto 196 * SND_SOC_POSSIBLE_DAIFMT_BP_FP 197 * SND_SOC_POSSIBLE_DAIFMT_BC_FP 198 * SND_SOC_POSSIBLE_DAIFMT_BP_FC 199 * SND_SOC_POSSIBLE_DAIFMT_BC_FC 200 */ 201 SND_SOC_POSSIBLE_DAIFMT_I2S | 202 SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | 203 SND_SOC_POSSIBLE_DAIFMT_LEFT_J | 204 SND_SOC_POSSIBLE_DAIFMT_DSP_A | 205 SND_SOC_POSSIBLE_DAIFMT_DSP_B | 206 SND_SOC_POSSIBLE_DAIFMT_AC97 | 207 SND_SOC_POSSIBLE_DAIFMT_PDM | 208 SND_SOC_POSSIBLE_DAIFMT_NB_NF | 209 SND_SOC_POSSIBLE_DAIFMT_NB_IF | 210 SND_SOC_POSSIBLE_DAIFMT_IB_NF | 211 SND_SOC_POSSIBLE_DAIFMT_IB_IF; 212 213static const struct snd_soc_dai_ops test_ops = { 214 .set_fmt = test_dai_set_fmt, 215 .set_tdm_slot = test_dai_set_tdm_slot, 216 .startup = test_dai_startup, 217 .shutdown = test_dai_shutdown, 218 .auto_selectable_formats = &test_dai_formats, 219 .num_auto_selectable_formats = 1, 220}; 221 222static const struct snd_soc_dai_ops test_verbose_ops = { 223 .set_sysclk = test_dai_set_sysclk, 224 .set_pll = test_dai_set_pll, 225 .set_clkdiv = test_dai_set_clkdiv, 226 .set_fmt = test_dai_set_fmt, 227 .set_tdm_slot = test_dai_set_tdm_slot, 228 .mute_stream = test_dai_mute_stream, 229 .startup = test_dai_startup, 230 .shutdown = test_dai_shutdown, 231 .hw_params = test_dai_hw_params, 232 .hw_free = test_dai_hw_free, 233 .trigger = test_dai_trigger, 234 .auto_selectable_formats = &test_dai_formats, 235 .num_auto_selectable_formats = 1, 236}; 237 238#define STUB_RATES SNDRV_PCM_RATE_CONTINUOUS 239#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 240 SNDRV_PCM_FMTBIT_U8 | \ 241 SNDRV_PCM_FMTBIT_S16_LE | \ 242 SNDRV_PCM_FMTBIT_U16_LE | \ 243 SNDRV_PCM_FMTBIT_S24_LE | \ 244 SNDRV_PCM_FMTBIT_S24_3LE | \ 245 SNDRV_PCM_FMTBIT_U24_LE | \ 246 SNDRV_PCM_FMTBIT_S32_LE | \ 247 SNDRV_PCM_FMTBIT_U32_LE) 248 249static int test_component_probe(struct snd_soc_component *component) 250{ 251 mile_stone(component); 252 253 return 0; 254} 255 256static void test_component_remove(struct snd_soc_component *component) 257{ 258 mile_stone(component); 259} 260 261static int test_component_suspend(struct snd_soc_component *component) 262{ 263 mile_stone(component); 264 265 return 0; 266} 267 268static int test_component_resume(struct snd_soc_component *component) 269{ 270 mile_stone(component); 271 272 return 0; 273} 274 275#define PREALLOC_BUFFER (32 * 1024) 276static int test_component_pcm_construct(struct snd_soc_component *component, 277 struct snd_soc_pcm_runtime *rtd) 278{ 279 mile_stone(component); 280 281 snd_pcm_set_managed_buffer_all( 282 rtd->pcm, 283 SNDRV_DMA_TYPE_DEV, 284 rtd->card->snd_card->dev, 285 PREALLOC_BUFFER, PREALLOC_BUFFER); 286 287 return 0; 288} 289 290static void test_component_pcm_destruct(struct snd_soc_component *component, 291 struct snd_pcm *pcm) 292{ 293 mile_stone(component); 294} 295 296static int test_component_set_sysclk(struct snd_soc_component *component, 297 int clk_id, int source, unsigned int freq, int dir) 298{ 299 mile_stone(component); 300 301 return 0; 302} 303 304static int test_component_set_pll(struct snd_soc_component *component, int pll_id, 305 int source, unsigned int freq_in, unsigned int freq_out) 306{ 307 mile_stone(component); 308 309 return 0; 310} 311 312static int test_component_set_jack(struct snd_soc_component *component, 313 struct snd_soc_jack *jack, void *data) 314{ 315 mile_stone(component); 316 317 return 0; 318} 319 320static void test_component_seq_notifier(struct snd_soc_component *component, 321 enum snd_soc_dapm_type type, int subseq) 322{ 323 mile_stone(component); 324} 325 326static int test_component_stream_event(struct snd_soc_component *component, int event) 327{ 328 mile_stone(component); 329 330 return 0; 331} 332 333static int test_component_set_bias_level(struct snd_soc_component *component, 334 enum snd_soc_bias_level level) 335{ 336 mile_stone(component); 337 338 return 0; 339} 340 341static const struct snd_pcm_hardware test_component_hardware = { 342 /* Random values to keep userspace happy when checking constraints */ 343 .info = SNDRV_PCM_INFO_INTERLEAVED | 344 SNDRV_PCM_INFO_MMAP | 345 SNDRV_PCM_INFO_MMAP_VALID, 346 .buffer_bytes_max = 32 * 1024, 347 .period_bytes_min = 32, 348 .period_bytes_max = 8192, 349 .periods_min = 1, 350 .periods_max = 128, 351 .fifo_size = 256, 352}; 353 354static int test_component_open(struct snd_soc_component *component, 355 struct snd_pcm_substream *substream) 356{ 357 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 358 359 mile_stone(component); 360 361 /* BE's dont need dummy params */ 362 if (!rtd->dai_link->no_pcm) 363 snd_soc_set_runtime_hwparams(substream, &test_component_hardware); 364 365 return 0; 366} 367 368static int test_component_close(struct snd_soc_component *component, 369 struct snd_pcm_substream *substream) 370{ 371 mile_stone(component); 372 373 return 0; 374} 375 376static int test_component_ioctl(struct snd_soc_component *component, 377 struct snd_pcm_substream *substream, 378 unsigned int cmd, void *arg) 379{ 380 mile_stone(component); 381 382 return 0; 383} 384 385static int test_component_hw_params(struct snd_soc_component *component, 386 struct snd_pcm_substream *substream, 387 struct snd_pcm_hw_params *params) 388{ 389 mile_stone(component); 390 391 return 0; 392} 393 394static int test_component_hw_free(struct snd_soc_component *component, 395 struct snd_pcm_substream *substream) 396{ 397 mile_stone(component); 398 399 return 0; 400} 401 402static int test_component_prepare(struct snd_soc_component *component, 403 struct snd_pcm_substream *substream) 404{ 405 mile_stone(component); 406 407 return 0; 408} 409 410static void test_component_timer_stop(struct test_priv *priv) 411{ 412 cancel_delayed_work(&priv->dwork); 413} 414 415static void test_component_timer_start(struct test_priv *priv) 416{ 417 schedule_delayed_work(&priv->dwork, msecs_to_jiffies(10)); 418} 419 420static void test_component_dwork(struct work_struct *work) 421{ 422 struct test_priv *priv = container_of(work, struct test_priv, dwork.work); 423 424 if (priv->substream) 425 snd_pcm_period_elapsed(priv->substream); 426 427 test_component_timer_start(priv); 428} 429 430static int test_component_trigger(struct snd_soc_component *component, 431 struct snd_pcm_substream *substream, int cmd) 432{ 433 struct test_priv *priv = dev_get_drvdata(component->dev); 434 435 mile_stone(component); 436 437 switch (cmd) { 438 case SNDRV_PCM_TRIGGER_START: 439 test_component_timer_start(priv); 440 priv->substream = substream; /* set substream later */ 441 break; 442 case SNDRV_PCM_TRIGGER_STOP: 443 priv->substream = NULL; 444 test_component_timer_stop(priv); 445 } 446 447 return 0; 448} 449 450static int test_component_sync_stop(struct snd_soc_component *component, 451 struct snd_pcm_substream *substream) 452{ 453 mile_stone(component); 454 455 return 0; 456} 457 458static snd_pcm_uframes_t test_component_pointer(struct snd_soc_component *component, 459 struct snd_pcm_substream *substream) 460{ 461 struct snd_pcm_runtime *runtime = substream->runtime; 462 static int pointer; 463 464 if (!runtime) 465 return 0; 466 467 pointer += 10; 468 if (pointer > PREALLOC_BUFFER) 469 pointer = 0; 470 471 /* mile_stone(component); */ 472 473 return bytes_to_frames(runtime, pointer); 474} 475 476static int test_component_get_time_info(struct snd_soc_component *component, 477 struct snd_pcm_substream *substream, 478 struct timespec64 *system_ts, 479 struct timespec64 *audio_ts, 480 struct snd_pcm_audio_tstamp_config *audio_tstamp_config, 481 struct snd_pcm_audio_tstamp_report *audio_tstamp_report) 482{ 483 mile_stone(component); 484 485 return 0; 486} 487 488static int test_component_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 489 struct snd_pcm_hw_params *params) 490{ 491 mile_stone_x(rtd->dev); 492 493 return 0; 494} 495 496/* CPU */ 497static const struct test_adata test_cpu = { .is_cpu = 1, .cmp_v = 0, .dai_v = 0, }; 498static const struct test_adata test_cpu_vv = { .is_cpu = 1, .cmp_v = 1, .dai_v = 1, }; 499static const struct test_adata test_cpu_nv = { .is_cpu = 1, .cmp_v = 0, .dai_v = 1, }; 500static const struct test_adata test_cpu_vn = { .is_cpu = 1, .cmp_v = 1, .dai_v = 0, }; 501/* Codec */ 502static const struct test_adata test_codec = { .is_cpu = 0, .cmp_v = 0, .dai_v = 0, }; 503static const struct test_adata test_codec_vv = { .is_cpu = 0, .cmp_v = 1, .dai_v = 1, }; 504static const struct test_adata test_codec_nv = { .is_cpu = 0, .cmp_v = 0, .dai_v = 1, }; 505static const struct test_adata test_codec_vn = { .is_cpu = 0, .cmp_v = 1, .dai_v = 0, }; 506 507static const struct of_device_id test_of_match[] = { 508 { .compatible = "test-cpu", .data = (void *)&test_cpu, }, 509 { .compatible = "test-cpu-verbose", .data = (void *)&test_cpu_vv, }, 510 { .compatible = "test-cpu-verbose-dai", .data = (void *)&test_cpu_nv, }, 511 { .compatible = "test-cpu-verbose-component", .data = (void *)&test_cpu_vn, }, 512 { .compatible = "test-codec", .data = (void *)&test_codec, }, 513 { .compatible = "test-codec-verbose", .data = (void *)&test_codec_vv, }, 514 { .compatible = "test-codec-verbose-dai", .data = (void *)&test_codec_nv, }, 515 { .compatible = "test-codec-verbose-component", .data = (void *)&test_codec_vn, }, 516 {}, 517}; 518MODULE_DEVICE_TABLE(of, test_of_match); 519 520static const struct snd_soc_dapm_widget widgets[] = { 521 /* 522 * FIXME 523 * 524 * Just IN/OUT is OK for now, 525 * but need to be updated ? 526 */ 527 SND_SOC_DAPM_INPUT("IN"), 528 SND_SOC_DAPM_OUTPUT("OUT"), 529}; 530 531static int test_driver_probe(struct platform_device *pdev) 532{ 533 struct device *dev = &pdev->dev; 534 struct device_node *node = dev->of_node; 535 const struct test_adata *adata = of_device_get_match_data(&pdev->dev); 536 struct snd_soc_component_driver *cdriv; 537 struct snd_soc_dai_driver *ddriv; 538 struct test_dai_name *dname; 539 struct test_priv *priv; 540 int num, ret, i; 541 542 num = of_graph_get_endpoint_count(node); 543 if (!num) { 544 dev_err(dev, "no port exits\n"); 545 return -EINVAL; 546 } 547 548 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 549 cdriv = devm_kzalloc(dev, sizeof(*cdriv), GFP_KERNEL); 550 ddriv = devm_kcalloc(dev, num, sizeof(*ddriv), GFP_KERNEL); 551 dname = devm_kcalloc(dev, num, sizeof(*dname), GFP_KERNEL); 552 if (!priv || !cdriv || !ddriv || !dname || !adata) 553 return -EINVAL; 554 555 priv->dev = dev; 556 priv->component_driver = cdriv; 557 priv->dai_driver = ddriv; 558 priv->name = dname; 559 560 INIT_DELAYED_WORK(&priv->dwork, test_component_dwork); 561 dev_set_drvdata(dev, priv); 562 563 if (adata->is_cpu) { 564 cdriv->name = "test_cpu"; 565 cdriv->pcm_construct = test_component_pcm_construct; 566 cdriv->pointer = test_component_pointer; 567 cdriv->trigger = test_component_trigger; 568 cdriv->legacy_dai_naming = 1; 569 } else { 570 cdriv->name = "test_codec"; 571 cdriv->idle_bias_on = 1; 572 cdriv->endianness = 1; 573 } 574 575 cdriv->open = test_component_open; 576 cdriv->dapm_widgets = widgets; 577 cdriv->num_dapm_widgets = ARRAY_SIZE(widgets); 578 579 if (adata->cmp_v) { 580 cdriv->probe = test_component_probe; 581 cdriv->remove = test_component_remove; 582 cdriv->suspend = test_component_suspend; 583 cdriv->resume = test_component_resume; 584 cdriv->set_sysclk = test_component_set_sysclk; 585 cdriv->set_pll = test_component_set_pll; 586 cdriv->set_jack = test_component_set_jack; 587 cdriv->seq_notifier = test_component_seq_notifier; 588 cdriv->stream_event = test_component_stream_event; 589 cdriv->set_bias_level = test_component_set_bias_level; 590 cdriv->close = test_component_close; 591 cdriv->ioctl = test_component_ioctl; 592 cdriv->hw_params = test_component_hw_params; 593 cdriv->hw_free = test_component_hw_free; 594 cdriv->prepare = test_component_prepare; 595 cdriv->sync_stop = test_component_sync_stop; 596 cdriv->get_time_info = test_component_get_time_info; 597 cdriv->be_hw_params_fixup = test_component_be_hw_params_fixup; 598 599 if (adata->is_cpu) 600 cdriv->pcm_destruct = test_component_pcm_destruct; 601 } 602 603 i = 0; 604 for_each_of_graph_port(node, port) { 605 snprintf(dname[i].name, TEST_NAME_LEN, "%s.%d", node->name, i); 606 ddriv[i].name = dname[i].name; 607 608 snprintf(dname[i].name_playback, TEST_NAME_LEN, "DAI%d Playback", i); 609 ddriv[i].playback.stream_name = dname[i].name_playback; 610 ddriv[i].playback.channels_min = 1; 611 ddriv[i].playback.channels_max = 384; 612 ddriv[i].playback.rates = STUB_RATES; 613 ddriv[i].playback.formats = STUB_FORMATS; 614 615 snprintf(dname[i].name_capture, TEST_NAME_LEN, "DAI%d Capture", i); 616 ddriv[i].capture.stream_name = dname[i].name_capture; 617 ddriv[i].capture.channels_min = 1; 618 ddriv[i].capture.channels_max = 384; 619 ddriv[i].capture.rates = STUB_RATES; 620 ddriv[i].capture.formats = STUB_FORMATS; 621 622 if (adata->dai_v) 623 ddriv[i].ops = &test_verbose_ops; 624 else 625 ddriv[i].ops = &test_ops; 626 627 i++; 628 } 629 630 ret = devm_snd_soc_register_component(dev, cdriv, ddriv, num); 631 if (ret < 0) 632 return ret; 633 634 mile_stone_x(dev); 635 636 return 0; 637} 638 639static void test_driver_remove(struct platform_device *pdev) 640{ 641 mile_stone_x(&pdev->dev); 642} 643 644static struct platform_driver test_driver = { 645 .driver = { 646 .name = "test-component", 647 .of_match_table = test_of_match, 648 }, 649 .probe = test_driver_probe, 650 .remove = test_driver_remove, 651}; 652module_platform_driver(test_driver); 653 654MODULE_ALIAS("platform:asoc-test-component"); 655MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 656MODULE_DESCRIPTION("ASoC Test Component"); 657MODULE_LICENSE("GPL v2");