Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/generic/test-component.c
26439 views
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 <[email protected]>
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
17
struct 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
23
struct 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
32
struct 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
41
static 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
49
static 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
57
static 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
64
static 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
143
static 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
152
static 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
159
static 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
166
static void test_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
167
{
168
mile_stone(dai);
169
}
170
171
static 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
179
static 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
186
static 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
193
static 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
213
static 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
222
static 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
249
static int test_component_probe(struct snd_soc_component *component)
250
{
251
mile_stone(component);
252
253
return 0;
254
}
255
256
static void test_component_remove(struct snd_soc_component *component)
257
{
258
mile_stone(component);
259
}
260
261
static int test_component_suspend(struct snd_soc_component *component)
262
{
263
mile_stone(component);
264
265
return 0;
266
}
267
268
static 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)
276
static 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
290
static void test_component_pcm_destruct(struct snd_soc_component *component,
291
struct snd_pcm *pcm)
292
{
293
mile_stone(component);
294
}
295
296
static 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
304
static 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
312
static 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
320
static 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
326
static int test_component_stream_event(struct snd_soc_component *component, int event)
327
{
328
mile_stone(component);
329
330
return 0;
331
}
332
333
static 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
341
static 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
354
static 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
368
static 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
376
static 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
385
static 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
394
static 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
402
static 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
410
static void test_component_timer_stop(struct test_priv *priv)
411
{
412
cancel_delayed_work(&priv->dwork);
413
}
414
415
static void test_component_timer_start(struct test_priv *priv)
416
{
417
schedule_delayed_work(&priv->dwork, msecs_to_jiffies(10));
418
}
419
420
static 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
430
static 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
450
static 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
458
static 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
476
static 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
488
static 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 */
497
static const struct test_adata test_cpu = { .is_cpu = 1, .cmp_v = 0, .dai_v = 0, };
498
static const struct test_adata test_cpu_vv = { .is_cpu = 1, .cmp_v = 1, .dai_v = 1, };
499
static const struct test_adata test_cpu_nv = { .is_cpu = 1, .cmp_v = 0, .dai_v = 1, };
500
static const struct test_adata test_cpu_vn = { .is_cpu = 1, .cmp_v = 1, .dai_v = 0, };
501
/* Codec */
502
static const struct test_adata test_codec = { .is_cpu = 0, .cmp_v = 0, .dai_v = 0, };
503
static const struct test_adata test_codec_vv = { .is_cpu = 0, .cmp_v = 1, .dai_v = 1, };
504
static const struct test_adata test_codec_nv = { .is_cpu = 0, .cmp_v = 0, .dai_v = 1, };
505
static const struct test_adata test_codec_vn = { .is_cpu = 0, .cmp_v = 1, .dai_v = 0, };
506
507
static 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
};
518
MODULE_DEVICE_TABLE(of, test_of_match);
519
520
static 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
531
static 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_kzalloc(dev, sizeof(*ddriv) * num, GFP_KERNEL);
551
dname = devm_kzalloc(dev, sizeof(*dname) * num, 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
639
static void test_driver_remove(struct platform_device *pdev)
640
{
641
mile_stone_x(&pdev->dev);
642
}
643
644
static 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
};
652
module_platform_driver(test_driver);
653
654
MODULE_ALIAS("platform:asoc-test-component");
655
MODULE_AUTHOR("Kuninori Morimoto <[email protected]>");
656
MODULE_DESCRIPTION("ASoC Test Component");
657
MODULE_LICENSE("GPL v2");
658
659