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