0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/slab.h>
0009 #include <linux/of_device.h>
0010 #include <linux/of_graph.h>
0011 #include <linux/module.h>
0012 #include <linux/workqueue.h>
0013 #include <sound/pcm.h>
0014 #include <sound/soc.h>
0015
0016 #define TEST_NAME_LEN 32
0017 struct test_dai_name {
0018 char name[TEST_NAME_LEN];
0019 char name_playback[TEST_NAME_LEN];
0020 char name_capture[TEST_NAME_LEN];
0021 };
0022
0023 struct test_priv {
0024 struct device *dev;
0025 struct snd_pcm_substream *substream;
0026 struct delayed_work dwork;
0027 struct snd_soc_component_driver *component_driver;
0028 struct snd_soc_dai_driver *dai_driver;
0029 struct test_dai_name *name;
0030 };
0031
0032 struct test_adata {
0033 u32 is_cpu:1;
0034 u32 cmp_v:1;
0035 u32 dai_v:1;
0036 };
0037
0038 #define mile_stone(d) dev_info((d)->dev, "%s() : %s", __func__, (d)->driver->name)
0039 #define mile_stone_x(dev) dev_info(dev, "%s()", __func__)
0040
0041 static int test_dai_set_sysclk(struct snd_soc_dai *dai,
0042 int clk_id, unsigned int freq, int dir)
0043 {
0044 mile_stone(dai);
0045
0046 return 0;
0047 }
0048
0049 static int test_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
0050 unsigned int freq_in, unsigned int freq_out)
0051 {
0052 mile_stone(dai);
0053
0054 return 0;
0055 }
0056
0057 static int test_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
0058 {
0059 mile_stone(dai);
0060
0061 return 0;
0062 }
0063
0064 static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0065 {
0066 unsigned int format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
0067 unsigned int clock = fmt & SND_SOC_DAIFMT_CLOCK_MASK;
0068 unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK;
0069 unsigned int master = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
0070 char *str;
0071
0072 dev_info(dai->dev, "name : %s", dai->name);
0073
0074 str = "unknown";
0075 switch (format) {
0076 case SND_SOC_DAIFMT_I2S:
0077 str = "i2s";
0078 break;
0079 case SND_SOC_DAIFMT_RIGHT_J:
0080 str = "right_j";
0081 break;
0082 case SND_SOC_DAIFMT_LEFT_J:
0083 str = "left_j";
0084 break;
0085 case SND_SOC_DAIFMT_DSP_A:
0086 str = "dsp_a";
0087 break;
0088 case SND_SOC_DAIFMT_DSP_B:
0089 str = "dsp_b";
0090 break;
0091 case SND_SOC_DAIFMT_AC97:
0092 str = "ac97";
0093 break;
0094 case SND_SOC_DAIFMT_PDM:
0095 str = "pdm";
0096 break;
0097 }
0098 dev_info(dai->dev, "format : %s", str);
0099
0100 if (clock == SND_SOC_DAIFMT_CONT)
0101 str = "continuous";
0102 else
0103 str = "gated";
0104 dev_info(dai->dev, "clock : %s", str);
0105
0106 str = "unknown";
0107 switch (master) {
0108 case SND_SOC_DAIFMT_BP_FP:
0109 str = "clk provider, frame provider";
0110 break;
0111 case SND_SOC_DAIFMT_BC_FP:
0112 str = "clk consumer, frame provider";
0113 break;
0114 case SND_SOC_DAIFMT_BP_FC:
0115 str = "clk provider, frame consumer";
0116 break;
0117 case SND_SOC_DAIFMT_BC_FC:
0118 str = "clk consumer, frame consumer";
0119 break;
0120 }
0121 dev_info(dai->dev, "clock : codec is %s", str);
0122
0123 str = "unknown";
0124 switch (inv) {
0125 case SND_SOC_DAIFMT_NB_NF:
0126 str = "normal bit, normal frame";
0127 break;
0128 case SND_SOC_DAIFMT_NB_IF:
0129 str = "normal bit, invert frame";
0130 break;
0131 case SND_SOC_DAIFMT_IB_NF:
0132 str = "invert bit, normal frame";
0133 break;
0134 case SND_SOC_DAIFMT_IB_IF:
0135 str = "invert bit, invert frame";
0136 break;
0137 }
0138 dev_info(dai->dev, "signal : %s", str);
0139
0140 return 0;
0141 }
0142
0143 static int test_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
0144 {
0145 mile_stone(dai);
0146
0147 return 0;
0148 }
0149
0150 static int test_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
0151 {
0152 mile_stone(dai);
0153
0154 return 0;
0155 }
0156
0157 static void test_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
0158 {
0159 mile_stone(dai);
0160 }
0161
0162 static int test_dai_hw_params(struct snd_pcm_substream *substream,
0163 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
0164 {
0165 mile_stone(dai);
0166
0167 return 0;
0168 }
0169
0170 static int test_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
0171 {
0172 mile_stone(dai);
0173
0174 return 0;
0175 }
0176
0177 static int test_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
0178 {
0179 mile_stone(dai);
0180
0181 return 0;
0182 }
0183
0184 static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream,
0185 int cmd, struct snd_soc_dai *dai)
0186 {
0187 mile_stone(dai);
0188
0189 return 0;
0190 }
0191
0192 static u64 test_dai_formats =
0193
0194
0195
0196
0197
0198
0199
0200 SND_SOC_POSSIBLE_DAIFMT_I2S |
0201 SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
0202 SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
0203 SND_SOC_POSSIBLE_DAIFMT_DSP_A |
0204 SND_SOC_POSSIBLE_DAIFMT_DSP_B |
0205 SND_SOC_POSSIBLE_DAIFMT_AC97 |
0206 SND_SOC_POSSIBLE_DAIFMT_PDM |
0207 SND_SOC_POSSIBLE_DAIFMT_NB_NF |
0208 SND_SOC_POSSIBLE_DAIFMT_NB_IF |
0209 SND_SOC_POSSIBLE_DAIFMT_IB_NF |
0210 SND_SOC_POSSIBLE_DAIFMT_IB_IF;
0211
0212 static const struct snd_soc_dai_ops test_ops = {
0213 .set_fmt = test_dai_set_fmt,
0214 .startup = test_dai_startup,
0215 .shutdown = test_dai_shutdown,
0216 .auto_selectable_formats = &test_dai_formats,
0217 .num_auto_selectable_formats = 1,
0218 };
0219
0220 static const struct snd_soc_dai_ops test_verbose_ops = {
0221 .set_sysclk = test_dai_set_sysclk,
0222 .set_pll = test_dai_set_pll,
0223 .set_clkdiv = test_dai_set_clkdiv,
0224 .set_fmt = test_dai_set_fmt,
0225 .mute_stream = test_dai_mute_stream,
0226 .startup = test_dai_startup,
0227 .shutdown = test_dai_shutdown,
0228 .hw_params = test_dai_hw_params,
0229 .hw_free = test_dai_hw_free,
0230 .trigger = test_dai_trigger,
0231 .bespoke_trigger = test_dai_bespoke_trigger,
0232 .auto_selectable_formats = &test_dai_formats,
0233 .num_auto_selectable_formats = 1,
0234 };
0235
0236 #define STUB_RATES SNDRV_PCM_RATE_8000_384000
0237 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
0238 SNDRV_PCM_FMTBIT_U8 | \
0239 SNDRV_PCM_FMTBIT_S16_LE | \
0240 SNDRV_PCM_FMTBIT_U16_LE | \
0241 SNDRV_PCM_FMTBIT_S24_LE | \
0242 SNDRV_PCM_FMTBIT_S24_3LE | \
0243 SNDRV_PCM_FMTBIT_U24_LE | \
0244 SNDRV_PCM_FMTBIT_S32_LE | \
0245 SNDRV_PCM_FMTBIT_U32_LE)
0246
0247 static int test_component_probe(struct snd_soc_component *component)
0248 {
0249 mile_stone(component);
0250
0251 return 0;
0252 }
0253
0254 static void test_component_remove(struct snd_soc_component *component)
0255 {
0256 mile_stone(component);
0257 }
0258
0259 static int test_component_suspend(struct snd_soc_component *component)
0260 {
0261 mile_stone(component);
0262
0263 return 0;
0264 }
0265
0266 static int test_component_resume(struct snd_soc_component *component)
0267 {
0268 mile_stone(component);
0269
0270 return 0;
0271 }
0272
0273 #define PREALLOC_BUFFER (32 * 1024)
0274 static int test_component_pcm_construct(struct snd_soc_component *component,
0275 struct snd_soc_pcm_runtime *rtd)
0276 {
0277 mile_stone(component);
0278
0279 snd_pcm_set_managed_buffer_all(
0280 rtd->pcm,
0281 SNDRV_DMA_TYPE_DEV,
0282 rtd->card->snd_card->dev,
0283 PREALLOC_BUFFER, PREALLOC_BUFFER);
0284
0285 return 0;
0286 }
0287
0288 static void test_component_pcm_destruct(struct snd_soc_component *component,
0289 struct snd_pcm *pcm)
0290 {
0291 mile_stone(component);
0292 }
0293
0294 static int test_component_set_sysclk(struct snd_soc_component *component,
0295 int clk_id, int source, unsigned int freq, int dir)
0296 {
0297 mile_stone(component);
0298
0299 return 0;
0300 }
0301
0302 static int test_component_set_pll(struct snd_soc_component *component, int pll_id,
0303 int source, unsigned int freq_in, unsigned int freq_out)
0304 {
0305 mile_stone(component);
0306
0307 return 0;
0308 }
0309
0310 static int test_component_set_jack(struct snd_soc_component *component,
0311 struct snd_soc_jack *jack, void *data)
0312 {
0313 mile_stone(component);
0314
0315 return 0;
0316 }
0317
0318 static void test_component_seq_notifier(struct snd_soc_component *component,
0319 enum snd_soc_dapm_type type, int subseq)
0320 {
0321 mile_stone(component);
0322 }
0323
0324 static int test_component_stream_event(struct snd_soc_component *component, int event)
0325 {
0326 mile_stone(component);
0327
0328 return 0;
0329 }
0330
0331 static int test_component_set_bias_level(struct snd_soc_component *component,
0332 enum snd_soc_bias_level level)
0333 {
0334 mile_stone(component);
0335
0336 return 0;
0337 }
0338
0339 static const struct snd_pcm_hardware test_component_hardware = {
0340
0341 .info = SNDRV_PCM_INFO_INTERLEAVED |
0342 SNDRV_PCM_INFO_MMAP |
0343 SNDRV_PCM_INFO_MMAP_VALID,
0344 .buffer_bytes_max = 32 * 1024,
0345 .period_bytes_min = 32,
0346 .period_bytes_max = 8192,
0347 .periods_min = 1,
0348 .periods_max = 128,
0349 .fifo_size = 256,
0350 };
0351
0352 static int test_component_open(struct snd_soc_component *component,
0353 struct snd_pcm_substream *substream)
0354 {
0355 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0356
0357 mile_stone(component);
0358
0359
0360 if (!rtd->dai_link->no_pcm)
0361 snd_soc_set_runtime_hwparams(substream, &test_component_hardware);
0362
0363 return 0;
0364 }
0365
0366 static int test_component_close(struct snd_soc_component *component,
0367 struct snd_pcm_substream *substream)
0368 {
0369 mile_stone(component);
0370
0371 return 0;
0372 }
0373
0374 static int test_component_ioctl(struct snd_soc_component *component,
0375 struct snd_pcm_substream *substream,
0376 unsigned int cmd, void *arg)
0377 {
0378 mile_stone(component);
0379
0380 return 0;
0381 }
0382
0383 static int test_component_hw_params(struct snd_soc_component *component,
0384 struct snd_pcm_substream *substream,
0385 struct snd_pcm_hw_params *params)
0386 {
0387 mile_stone(component);
0388
0389 return 0;
0390 }
0391
0392 static int test_component_hw_free(struct snd_soc_component *component,
0393 struct snd_pcm_substream *substream)
0394 {
0395 mile_stone(component);
0396
0397 return 0;
0398 }
0399
0400 static int test_component_prepare(struct snd_soc_component *component,
0401 struct snd_pcm_substream *substream)
0402 {
0403 mile_stone(component);
0404
0405 return 0;
0406 }
0407
0408 static void test_component_timer_stop(struct test_priv *priv)
0409 {
0410 cancel_delayed_work(&priv->dwork);
0411 }
0412
0413 static void test_component_timer_start(struct test_priv *priv)
0414 {
0415 schedule_delayed_work(&priv->dwork, msecs_to_jiffies(10));
0416 }
0417
0418 static void test_component_dwork(struct work_struct *work)
0419 {
0420 struct test_priv *priv = container_of(work, struct test_priv, dwork.work);
0421
0422 if (priv->substream)
0423 snd_pcm_period_elapsed(priv->substream);
0424
0425 test_component_timer_start(priv);
0426 }
0427
0428 static int test_component_trigger(struct snd_soc_component *component,
0429 struct snd_pcm_substream *substream, int cmd)
0430 {
0431 struct test_priv *priv = dev_get_drvdata(component->dev);
0432
0433 mile_stone(component);
0434
0435 switch (cmd) {
0436 case SNDRV_PCM_TRIGGER_START:
0437 test_component_timer_start(priv);
0438 priv->substream = substream;
0439 break;
0440 case SNDRV_PCM_TRIGGER_STOP:
0441 priv->substream = NULL;
0442 test_component_timer_stop(priv);
0443 }
0444
0445 return 0;
0446 }
0447
0448 static int test_component_sync_stop(struct snd_soc_component *component,
0449 struct snd_pcm_substream *substream)
0450 {
0451 mile_stone(component);
0452
0453 return 0;
0454 }
0455
0456 static snd_pcm_uframes_t test_component_pointer(struct snd_soc_component *component,
0457 struct snd_pcm_substream *substream)
0458 {
0459 struct snd_pcm_runtime *runtime = substream->runtime;
0460 static int pointer;
0461
0462 if (!runtime)
0463 return 0;
0464
0465 pointer += 10;
0466 if (pointer > PREALLOC_BUFFER)
0467 pointer = 0;
0468
0469
0470
0471 return bytes_to_frames(runtime, pointer);
0472 }
0473
0474 static int test_component_get_time_info(struct snd_soc_component *component,
0475 struct snd_pcm_substream *substream,
0476 struct timespec64 *system_ts,
0477 struct timespec64 *audio_ts,
0478 struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
0479 struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
0480 {
0481 mile_stone(component);
0482
0483 return 0;
0484 }
0485
0486 static int test_component_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
0487 struct snd_pcm_hw_params *params)
0488 {
0489 mile_stone_x(rtd->dev);
0490
0491 return 0;
0492 }
0493
0494
0495 static const struct test_adata test_cpu = { .is_cpu = 1, .cmp_v = 0, .dai_v = 0, };
0496 static const struct test_adata test_cpu_vv = { .is_cpu = 1, .cmp_v = 1, .dai_v = 1, };
0497 static const struct test_adata test_cpu_nv = { .is_cpu = 1, .cmp_v = 0, .dai_v = 1, };
0498 static const struct test_adata test_cpu_vn = { .is_cpu = 1, .cmp_v = 1, .dai_v = 0, };
0499
0500 static const struct test_adata test_codec = { .is_cpu = 0, .cmp_v = 0, .dai_v = 0, };
0501 static const struct test_adata test_codec_vv = { .is_cpu = 0, .cmp_v = 1, .dai_v = 1, };
0502 static const struct test_adata test_codec_nv = { .is_cpu = 0, .cmp_v = 0, .dai_v = 1, };
0503 static const struct test_adata test_codec_vn = { .is_cpu = 0, .cmp_v = 1, .dai_v = 0, };
0504
0505 static const struct of_device_id test_of_match[] = {
0506 { .compatible = "test-cpu", .data = (void *)&test_cpu, },
0507 { .compatible = "test-cpu-verbose", .data = (void *)&test_cpu_vv, },
0508 { .compatible = "test-cpu-verbose-dai", .data = (void *)&test_cpu_nv, },
0509 { .compatible = "test-cpu-verbose-component", .data = (void *)&test_cpu_vn, },
0510 { .compatible = "test-codec", .data = (void *)&test_codec, },
0511 { .compatible = "test-codec-verbose", .data = (void *)&test_codec_vv, },
0512 { .compatible = "test-codec-verbose-dai", .data = (void *)&test_codec_nv, },
0513 { .compatible = "test-codec-verbose-component", .data = (void *)&test_codec_vn, },
0514 {},
0515 };
0516 MODULE_DEVICE_TABLE(of, test_of_match);
0517
0518 static const struct snd_soc_dapm_widget widgets[] = {
0519
0520
0521
0522
0523
0524
0525 SND_SOC_DAPM_INPUT("IN"),
0526 SND_SOC_DAPM_OUTPUT("OUT"),
0527 };
0528
0529 static int test_driver_probe(struct platform_device *pdev)
0530 {
0531 struct device *dev = &pdev->dev;
0532 struct device_node *node = dev->of_node;
0533 struct device_node *ep;
0534 const struct test_adata *adata = of_device_get_match_data(&pdev->dev);
0535 struct snd_soc_component_driver *cdriv;
0536 struct snd_soc_dai_driver *ddriv;
0537 struct test_dai_name *dname;
0538 struct test_priv *priv;
0539 int num, ret, i;
0540
0541 num = of_graph_get_endpoint_count(node);
0542 if (!num) {
0543 dev_err(dev, "no port exits\n");
0544 return -EINVAL;
0545 }
0546
0547 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0548 cdriv = devm_kzalloc(dev, sizeof(*cdriv), GFP_KERNEL);
0549 ddriv = devm_kzalloc(dev, sizeof(*ddriv) * num, GFP_KERNEL);
0550 dname = devm_kzalloc(dev, sizeof(*dname) * num, GFP_KERNEL);
0551 if (!priv || !cdriv || !ddriv || !dname || !adata)
0552 return -EINVAL;
0553
0554 priv->dev = dev;
0555 priv->component_driver = cdriv;
0556 priv->dai_driver = ddriv;
0557 priv->name = dname;
0558
0559 INIT_DELAYED_WORK(&priv->dwork, test_component_dwork);
0560 dev_set_drvdata(dev, priv);
0561
0562 if (adata->is_cpu) {
0563 cdriv->name = "test_cpu";
0564 cdriv->pcm_construct = test_component_pcm_construct;
0565 cdriv->pointer = test_component_pointer;
0566 cdriv->trigger = test_component_trigger;
0567 cdriv->legacy_dai_naming = 1;
0568 } else {
0569 cdriv->name = "test_codec";
0570 cdriv->idle_bias_on = 1;
0571 cdriv->endianness = 1;
0572 }
0573
0574 cdriv->open = test_component_open;
0575 cdriv->dapm_widgets = widgets;
0576 cdriv->num_dapm_widgets = ARRAY_SIZE(widgets);
0577
0578 if (adata->cmp_v) {
0579 cdriv->probe = test_component_probe;
0580 cdriv->remove = test_component_remove;
0581 cdriv->suspend = test_component_suspend;
0582 cdriv->resume = test_component_resume;
0583 cdriv->set_sysclk = test_component_set_sysclk;
0584 cdriv->set_pll = test_component_set_pll;
0585 cdriv->set_jack = test_component_set_jack;
0586 cdriv->seq_notifier = test_component_seq_notifier;
0587 cdriv->stream_event = test_component_stream_event;
0588 cdriv->set_bias_level = test_component_set_bias_level;
0589 cdriv->close = test_component_close;
0590 cdriv->ioctl = test_component_ioctl;
0591 cdriv->hw_params = test_component_hw_params;
0592 cdriv->hw_free = test_component_hw_free;
0593 cdriv->prepare = test_component_prepare;
0594 cdriv->sync_stop = test_component_sync_stop;
0595 cdriv->get_time_info = test_component_get_time_info;
0596 cdriv->be_hw_params_fixup = test_component_be_hw_params_fixup;
0597
0598 if (adata->is_cpu)
0599 cdriv->pcm_destruct = test_component_pcm_destruct;
0600 }
0601
0602 i = 0;
0603 for_each_endpoint_of_node(node, ep) {
0604 snprintf(dname[i].name, TEST_NAME_LEN, "%s.%d", node->name, i);
0605 ddriv[i].name = dname[i].name;
0606
0607 snprintf(dname[i].name_playback, TEST_NAME_LEN, "DAI%d Playback", i);
0608 ddriv[i].playback.stream_name = dname[i].name_playback;
0609 ddriv[i].playback.channels_min = 1;
0610 ddriv[i].playback.channels_max = 384;
0611 ddriv[i].playback.rates = STUB_RATES;
0612 ddriv[i].playback.formats = STUB_FORMATS;
0613
0614 snprintf(dname[i].name_capture, TEST_NAME_LEN, "DAI%d Capture", i);
0615 ddriv[i].capture.stream_name = dname[i].name_capture;
0616 ddriv[i].capture.channels_min = 1;
0617 ddriv[i].capture.channels_max = 384;
0618 ddriv[i].capture.rates = STUB_RATES;
0619 ddriv[i].capture.formats = STUB_FORMATS;
0620
0621 if (adata->dai_v)
0622 ddriv[i].ops = &test_verbose_ops;
0623 else
0624 ddriv[i].ops = &test_ops;
0625
0626 i++;
0627 }
0628
0629 ret = devm_snd_soc_register_component(dev, cdriv, ddriv, num);
0630 if (ret < 0)
0631 return ret;
0632
0633 mile_stone_x(dev);
0634
0635 return 0;
0636 }
0637
0638 static int test_driver_remove(struct platform_device *pdev)
0639 {
0640 mile_stone_x(&pdev->dev);
0641
0642 return 0;
0643 }
0644
0645 static struct platform_driver test_driver = {
0646 .driver = {
0647 .name = "test-component",
0648 .of_match_table = test_of_match,
0649 },
0650 .probe = test_driver_probe,
0651 .remove = test_driver_remove,
0652 };
0653 module_platform_driver(test_driver);
0654
0655 MODULE_ALIAS("platform:asoc-test-component");
0656 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
0657 MODULE_DESCRIPTION("ASoC Test Component");
0658 MODULE_LICENSE("GPL v2");