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 |
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_mute_stream(struct snd_soc_dai *dai, int mute, int stream) |
144 | { |
145 | mile_stone(dai); |
146 | |
147 | return 0; |
148 | } |
149 | |
150 | static int test_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) |
151 | { |
152 | mile_stone(dai); |
153 | |
154 | return 0; |
155 | } |
156 | |
157 | static void test_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) |
158 | { |
159 | mile_stone(dai); |
160 | } |
161 | |
162 | static int test_dai_hw_params(struct snd_pcm_substream *substream, |
163 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
164 | { |
165 | mile_stone(dai); |
166 | |
167 | return 0; |
168 | } |
169 | |
170 | static int test_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) |
171 | { |
172 | mile_stone(dai); |
173 | |
174 | return 0; |
175 | } |
176 | |
177 | static int test_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) |
178 | { |
179 | mile_stone(dai); |
180 | |
181 | return 0; |
182 | } |
183 | |
184 | static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream, |
185 | int cmd, struct snd_soc_dai *dai) |
186 | { |
187 | mile_stone(dai); |
188 | |
189 | return 0; |
190 | } |
191 | |
192 | static u64 test_dai_formats = |
193 | /* |
194 | * Select below from Sound Card, not auto |
195 | * SND_SOC_POSSIBLE_DAIFMT_BP_FP |
196 | * SND_SOC_POSSIBLE_DAIFMT_BC_FP |
197 | * SND_SOC_POSSIBLE_DAIFMT_BP_FC |
198 | * SND_SOC_POSSIBLE_DAIFMT_BC_FC |
199 | */ |
200 | SND_SOC_POSSIBLE_DAIFMT_I2S | |
201 | SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | |
202 | SND_SOC_POSSIBLE_DAIFMT_LEFT_J | |
203 | SND_SOC_POSSIBLE_DAIFMT_DSP_A | |
204 | SND_SOC_POSSIBLE_DAIFMT_DSP_B | |
205 | SND_SOC_POSSIBLE_DAIFMT_AC97 | |
206 | SND_SOC_POSSIBLE_DAIFMT_PDM | |
207 | SND_SOC_POSSIBLE_DAIFMT_NB_NF | |
208 | SND_SOC_POSSIBLE_DAIFMT_NB_IF | |
209 | SND_SOC_POSSIBLE_DAIFMT_IB_NF | |
210 | SND_SOC_POSSIBLE_DAIFMT_IB_IF; |
211 | |
212 | static const struct snd_soc_dai_ops test_ops = { |
213 | .set_fmt = test_dai_set_fmt, |
214 | .startup = test_dai_startup, |
215 | .shutdown = test_dai_shutdown, |
216 | .auto_selectable_formats = &test_dai_formats, |
217 | .num_auto_selectable_formats = 1, |
218 | }; |
219 | |
220 | static const struct snd_soc_dai_ops test_verbose_ops = { |
221 | .set_sysclk = test_dai_set_sysclk, |
222 | .set_pll = test_dai_set_pll, |
223 | .set_clkdiv = test_dai_set_clkdiv, |
224 | .set_fmt = test_dai_set_fmt, |
225 | .mute_stream = test_dai_mute_stream, |
226 | .startup = test_dai_startup, |
227 | .shutdown = test_dai_shutdown, |
228 | .hw_params = test_dai_hw_params, |
229 | .hw_free = test_dai_hw_free, |
230 | .trigger = test_dai_trigger, |
231 | .bespoke_trigger = test_dai_bespoke_trigger, |
232 | .auto_selectable_formats = &test_dai_formats, |
233 | .num_auto_selectable_formats = 1, |
234 | }; |
235 | |
236 | #define STUB_RATES SNDRV_PCM_RATE_8000_384000 |
237 | #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ |
238 | SNDRV_PCM_FMTBIT_U8 | \ |
239 | SNDRV_PCM_FMTBIT_S16_LE | \ |
240 | SNDRV_PCM_FMTBIT_U16_LE | \ |
241 | SNDRV_PCM_FMTBIT_S24_LE | \ |
242 | SNDRV_PCM_FMTBIT_S24_3LE | \ |
243 | SNDRV_PCM_FMTBIT_U24_LE | \ |
244 | SNDRV_PCM_FMTBIT_S32_LE | \ |
245 | SNDRV_PCM_FMTBIT_U32_LE) |
246 | |
247 | static int test_component_probe(struct snd_soc_component *component) |
248 | { |
249 | mile_stone(component); |
250 | |
251 | return 0; |
252 | } |
253 | |
254 | static void test_component_remove(struct snd_soc_component *component) |
255 | { |
256 | mile_stone(component); |
257 | } |
258 | |
259 | static int test_component_suspend(struct snd_soc_component *component) |
260 | { |
261 | mile_stone(component); |
262 | |
263 | return 0; |
264 | } |
265 | |
266 | static int test_component_resume(struct snd_soc_component *component) |
267 | { |
268 | mile_stone(component); |
269 | |
270 | return 0; |
271 | } |
272 | |
273 | #define PREALLOC_BUFFER (32 * 1024) |
274 | static int test_component_pcm_construct(struct snd_soc_component *component, |
275 | struct snd_soc_pcm_runtime *rtd) |
276 | { |
277 | mile_stone(component); |
278 | |
279 | snd_pcm_set_managed_buffer_all( |
280 | pcm: rtd->pcm, |
281 | SNDRV_DMA_TYPE_DEV, |
282 | data: rtd->card->snd_card->dev, |
283 | PREALLOC_BUFFER, PREALLOC_BUFFER); |
284 | |
285 | return 0; |
286 | } |
287 | |
288 | static void test_component_pcm_destruct(struct snd_soc_component *component, |
289 | struct snd_pcm *pcm) |
290 | { |
291 | mile_stone(component); |
292 | } |
293 | |
294 | static int test_component_set_sysclk(struct snd_soc_component *component, |
295 | int clk_id, int source, unsigned int freq, int dir) |
296 | { |
297 | mile_stone(component); |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | static int test_component_set_pll(struct snd_soc_component *component, int pll_id, |
303 | int source, unsigned int freq_in, unsigned int freq_out) |
304 | { |
305 | mile_stone(component); |
306 | |
307 | return 0; |
308 | } |
309 | |
310 | static int test_component_set_jack(struct snd_soc_component *component, |
311 | struct snd_soc_jack *jack, void *data) |
312 | { |
313 | mile_stone(component); |
314 | |
315 | return 0; |
316 | } |
317 | |
318 | static void test_component_seq_notifier(struct snd_soc_component *component, |
319 | enum snd_soc_dapm_type type, int subseq) |
320 | { |
321 | mile_stone(component); |
322 | } |
323 | |
324 | static int test_component_stream_event(struct snd_soc_component *component, int event) |
325 | { |
326 | mile_stone(component); |
327 | |
328 | return 0; |
329 | } |
330 | |
331 | static int test_component_set_bias_level(struct snd_soc_component *component, |
332 | enum snd_soc_bias_level level) |
333 | { |
334 | mile_stone(component); |
335 | |
336 | return 0; |
337 | } |
338 | |
339 | static const struct snd_pcm_hardware test_component_hardware = { |
340 | /* Random values to keep userspace happy when checking constraints */ |
341 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
342 | SNDRV_PCM_INFO_MMAP | |
343 | SNDRV_PCM_INFO_MMAP_VALID, |
344 | .buffer_bytes_max = 32 * 1024, |
345 | .period_bytes_min = 32, |
346 | .period_bytes_max = 8192, |
347 | .periods_min = 1, |
348 | .periods_max = 128, |
349 | .fifo_size = 256, |
350 | }; |
351 | |
352 | static int test_component_open(struct snd_soc_component *component, |
353 | struct snd_pcm_substream *substream) |
354 | { |
355 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
356 | |
357 | mile_stone(component); |
358 | |
359 | /* BE's dont need dummy params */ |
360 | if (!rtd->dai_link->no_pcm) |
361 | snd_soc_set_runtime_hwparams(substream, hw: &test_component_hardware); |
362 | |
363 | return 0; |
364 | } |
365 | |
366 | static int test_component_close(struct snd_soc_component *component, |
367 | struct snd_pcm_substream *substream) |
368 | { |
369 | mile_stone(component); |
370 | |
371 | return 0; |
372 | } |
373 | |
374 | static int test_component_ioctl(struct snd_soc_component *component, |
375 | struct snd_pcm_substream *substream, |
376 | unsigned int cmd, void *arg) |
377 | { |
378 | mile_stone(component); |
379 | |
380 | return 0; |
381 | } |
382 | |
383 | static int test_component_hw_params(struct snd_soc_component *component, |
384 | struct snd_pcm_substream *substream, |
385 | struct snd_pcm_hw_params *params) |
386 | { |
387 | mile_stone(component); |
388 | |
389 | return 0; |
390 | } |
391 | |
392 | static int test_component_hw_free(struct snd_soc_component *component, |
393 | struct snd_pcm_substream *substream) |
394 | { |
395 | mile_stone(component); |
396 | |
397 | return 0; |
398 | } |
399 | |
400 | static int test_component_prepare(struct snd_soc_component *component, |
401 | struct snd_pcm_substream *substream) |
402 | { |
403 | mile_stone(component); |
404 | |
405 | return 0; |
406 | } |
407 | |
408 | static void test_component_timer_stop(struct test_priv *priv) |
409 | { |
410 | cancel_delayed_work(dwork: &priv->dwork); |
411 | } |
412 | |
413 | static void test_component_timer_start(struct test_priv *priv) |
414 | { |
415 | schedule_delayed_work(dwork: &priv->dwork, delay: msecs_to_jiffies(m: 10)); |
416 | } |
417 | |
418 | static void test_component_dwork(struct work_struct *work) |
419 | { |
420 | struct test_priv *priv = container_of(work, struct test_priv, dwork.work); |
421 | |
422 | if (priv->substream) |
423 | snd_pcm_period_elapsed(substream: priv->substream); |
424 | |
425 | test_component_timer_start(priv); |
426 | } |
427 | |
428 | static int test_component_trigger(struct snd_soc_component *component, |
429 | struct snd_pcm_substream *substream, int cmd) |
430 | { |
431 | struct test_priv *priv = dev_get_drvdata(dev: component->dev); |
432 | |
433 | mile_stone(component); |
434 | |
435 | switch (cmd) { |
436 | case SNDRV_PCM_TRIGGER_START: |
437 | test_component_timer_start(priv); |
438 | priv->substream = substream; /* set substream later */ |
439 | break; |
440 | case SNDRV_PCM_TRIGGER_STOP: |
441 | priv->substream = NULL; |
442 | test_component_timer_stop(priv); |
443 | } |
444 | |
445 | return 0; |
446 | } |
447 | |
448 | static int test_component_sync_stop(struct snd_soc_component *component, |
449 | struct snd_pcm_substream *substream) |
450 | { |
451 | mile_stone(component); |
452 | |
453 | return 0; |
454 | } |
455 | |
456 | static snd_pcm_uframes_t test_component_pointer(struct snd_soc_component *component, |
457 | struct snd_pcm_substream *substream) |
458 | { |
459 | struct snd_pcm_runtime *runtime = substream->runtime; |
460 | static int pointer; |
461 | |
462 | if (!runtime) |
463 | return 0; |
464 | |
465 | pointer += 10; |
466 | if (pointer > PREALLOC_BUFFER) |
467 | pointer = 0; |
468 | |
469 | /* mile_stone(component); */ |
470 | |
471 | return bytes_to_frames(runtime, size: pointer); |
472 | } |
473 | |
474 | static int test_component_get_time_info(struct snd_soc_component *component, |
475 | struct snd_pcm_substream *substream, |
476 | struct timespec64 *system_ts, |
477 | struct timespec64 *audio_ts, |
478 | struct snd_pcm_audio_tstamp_config *audio_tstamp_config, |
479 | struct snd_pcm_audio_tstamp_report *audio_tstamp_report) |
480 | { |
481 | mile_stone(component); |
482 | |
483 | return 0; |
484 | } |
485 | |
486 | static int test_component_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, |
487 | struct snd_pcm_hw_params *params) |
488 | { |
489 | mile_stone_x(rtd->dev); |
490 | |
491 | return 0; |
492 | } |
493 | |
494 | /* CPU */ |
495 | static const struct test_adata test_cpu = { .is_cpu = 1, .cmp_v = 0, .dai_v = 0, }; |
496 | static const struct test_adata test_cpu_vv = { .is_cpu = 1, .cmp_v = 1, .dai_v = 1, }; |
497 | static const struct test_adata test_cpu_nv = { .is_cpu = 1, .cmp_v = 0, .dai_v = 1, }; |
498 | static const struct test_adata test_cpu_vn = { .is_cpu = 1, .cmp_v = 1, .dai_v = 0, }; |
499 | /* Codec */ |
500 | static const struct test_adata test_codec = { .is_cpu = 0, .cmp_v = 0, .dai_v = 0, }; |
501 | static const struct test_adata test_codec_vv = { .is_cpu = 0, .cmp_v = 1, .dai_v = 1, }; |
502 | static const struct test_adata test_codec_nv = { .is_cpu = 0, .cmp_v = 0, .dai_v = 1, }; |
503 | static const struct test_adata test_codec_vn = { .is_cpu = 0, .cmp_v = 1, .dai_v = 0, }; |
504 | |
505 | static const struct of_device_id test_of_match[] = { |
506 | { .compatible = "test-cpu" , .data = (void *)&test_cpu, }, |
507 | { .compatible = "test-cpu-verbose" , .data = (void *)&test_cpu_vv, }, |
508 | { .compatible = "test-cpu-verbose-dai" , .data = (void *)&test_cpu_nv, }, |
509 | { .compatible = "test-cpu-verbose-component" , .data = (void *)&test_cpu_vn, }, |
510 | { .compatible = "test-codec" , .data = (void *)&test_codec, }, |
511 | { .compatible = "test-codec-verbose" , .data = (void *)&test_codec_vv, }, |
512 | { .compatible = "test-codec-verbose-dai" , .data = (void *)&test_codec_nv, }, |
513 | { .compatible = "test-codec-verbose-component" , .data = (void *)&test_codec_vn, }, |
514 | {}, |
515 | }; |
516 | MODULE_DEVICE_TABLE(of, test_of_match); |
517 | |
518 | static const struct snd_soc_dapm_widget widgets[] = { |
519 | /* |
520 | * FIXME |
521 | * |
522 | * Just IN/OUT is OK for now, |
523 | * but need to be updated ? |
524 | */ |
525 | SND_SOC_DAPM_INPUT("IN" ), |
526 | SND_SOC_DAPM_OUTPUT("OUT" ), |
527 | }; |
528 | |
529 | static int test_driver_probe(struct platform_device *pdev) |
530 | { |
531 | struct device *dev = &pdev->dev; |
532 | struct device_node *node = dev->of_node; |
533 | struct device_node *ep; |
534 | const struct test_adata *adata = of_device_get_match_data(dev: &pdev->dev); |
535 | struct snd_soc_component_driver *cdriv; |
536 | struct snd_soc_dai_driver *ddriv; |
537 | struct test_dai_name *dname; |
538 | struct test_priv *priv; |
539 | int num, ret, i; |
540 | |
541 | num = of_graph_get_endpoint_count(np: node); |
542 | if (!num) { |
543 | dev_err(dev, "no port exits\n" ); |
544 | return -EINVAL; |
545 | } |
546 | |
547 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
548 | cdriv = devm_kzalloc(dev, size: sizeof(*cdriv), GFP_KERNEL); |
549 | ddriv = devm_kzalloc(dev, size: sizeof(*ddriv) * num, GFP_KERNEL); |
550 | dname = devm_kzalloc(dev, size: sizeof(*dname) * num, GFP_KERNEL); |
551 | if (!priv || !cdriv || !ddriv || !dname || !adata) |
552 | return -EINVAL; |
553 | |
554 | priv->dev = dev; |
555 | priv->component_driver = cdriv; |
556 | priv->dai_driver = ddriv; |
557 | priv->name = dname; |
558 | |
559 | INIT_DELAYED_WORK(&priv->dwork, test_component_dwork); |
560 | dev_set_drvdata(dev, data: priv); |
561 | |
562 | if (adata->is_cpu) { |
563 | cdriv->name = "test_cpu" ; |
564 | cdriv->pcm_construct = test_component_pcm_construct; |
565 | cdriv->pointer = test_component_pointer; |
566 | cdriv->trigger = test_component_trigger; |
567 | cdriv->legacy_dai_naming = 1; |
568 | } else { |
569 | cdriv->name = "test_codec" ; |
570 | cdriv->idle_bias_on = 1; |
571 | cdriv->endianness = 1; |
572 | } |
573 | |
574 | cdriv->open = test_component_open; |
575 | cdriv->dapm_widgets = widgets; |
576 | cdriv->num_dapm_widgets = ARRAY_SIZE(widgets); |
577 | |
578 | if (adata->cmp_v) { |
579 | cdriv->probe = test_component_probe; |
580 | cdriv->remove = test_component_remove; |
581 | cdriv->suspend = test_component_suspend; |
582 | cdriv->resume = test_component_resume; |
583 | cdriv->set_sysclk = test_component_set_sysclk; |
584 | cdriv->set_pll = test_component_set_pll; |
585 | cdriv->set_jack = test_component_set_jack; |
586 | cdriv->seq_notifier = test_component_seq_notifier; |
587 | cdriv->stream_event = test_component_stream_event; |
588 | cdriv->set_bias_level = test_component_set_bias_level; |
589 | cdriv->close = test_component_close; |
590 | cdriv->ioctl = test_component_ioctl; |
591 | cdriv->hw_params = test_component_hw_params; |
592 | cdriv->hw_free = test_component_hw_free; |
593 | cdriv->prepare = test_component_prepare; |
594 | cdriv->sync_stop = test_component_sync_stop; |
595 | cdriv->get_time_info = test_component_get_time_info; |
596 | cdriv->be_hw_params_fixup = test_component_be_hw_params_fixup; |
597 | |
598 | if (adata->is_cpu) |
599 | cdriv->pcm_destruct = test_component_pcm_destruct; |
600 | } |
601 | |
602 | i = 0; |
603 | for_each_endpoint_of_node(node, ep) { |
604 | snprintf(buf: dname[i].name, TEST_NAME_LEN, fmt: "%s.%d" , node->name, i); |
605 | ddriv[i].name = dname[i].name; |
606 | |
607 | snprintf(buf: dname[i].name_playback, TEST_NAME_LEN, fmt: "DAI%d Playback" , i); |
608 | ddriv[i].playback.stream_name = dname[i].name_playback; |
609 | ddriv[i].playback.channels_min = 1; |
610 | ddriv[i].playback.channels_max = 384; |
611 | ddriv[i].playback.rates = STUB_RATES; |
612 | ddriv[i].playback.formats = STUB_FORMATS; |
613 | |
614 | snprintf(buf: dname[i].name_capture, TEST_NAME_LEN, fmt: "DAI%d Capture" , i); |
615 | ddriv[i].capture.stream_name = dname[i].name_capture; |
616 | ddriv[i].capture.channels_min = 1; |
617 | ddriv[i].capture.channels_max = 384; |
618 | ddriv[i].capture.rates = STUB_RATES; |
619 | ddriv[i].capture.formats = STUB_FORMATS; |
620 | |
621 | if (adata->dai_v) |
622 | ddriv[i].ops = &test_verbose_ops; |
623 | else |
624 | ddriv[i].ops = &test_ops; |
625 | |
626 | i++; |
627 | } |
628 | |
629 | ret = devm_snd_soc_register_component(dev, component_driver: cdriv, dai_drv: ddriv, num_dai: num); |
630 | if (ret < 0) |
631 | return ret; |
632 | |
633 | mile_stone_x(dev); |
634 | |
635 | return 0; |
636 | } |
637 | |
638 | static void test_driver_remove(struct platform_device *pdev) |
639 | { |
640 | mile_stone_x(&pdev->dev); |
641 | } |
642 | |
643 | static struct platform_driver test_driver = { |
644 | .driver = { |
645 | .name = "test-component" , |
646 | .of_match_table = test_of_match, |
647 | }, |
648 | .probe = test_driver_probe, |
649 | .remove_new = test_driver_remove, |
650 | }; |
651 | module_platform_driver(test_driver); |
652 | |
653 | MODULE_ALIAS("platform:asoc-test-component" ); |
654 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>" ); |
655 | MODULE_DESCRIPTION("ASoC Test Component" ); |
656 | MODULE_LICENSE("GPL v2" ); |
657 | |