xref: /linux/sound/soc/generic/test-component.c (revision 64b14a184e83eb62ea0615e31a409956049d40e7)
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_device.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_MASTER_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_CBP_CFP:
109 		str = "clk provider, frame provider";
110 		break;
111 	case SND_SOC_DAIFMT_CBC_CFP:
112 		str = "clk consumer, frame provider";
113 		break;
114 	case SND_SOC_DAIFMT_CBP_CFC:
115 		str = "clk provider, frame consumer";
116 		break;
117 	case SND_SOC_DAIFMT_CBC_CFC:
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_CBP_CFP
196 	 *	SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
197 	 *	SND_SOC_POSSIBLE_DAIFMT_CBP_CFC
198 	 *	SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
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 		rtd->pcm,
281 		SNDRV_DMA_TYPE_DEV,
282 		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 = asoc_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, &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(&priv->dwork);
411 }
412 
413 static void test_component_timer_start(struct test_priv *priv)
414 {
415 	schedule_delayed_work(&priv->dwork, msecs_to_jiffies(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(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(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, 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(&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(node);
542 	if (!num) {
543 		dev_err(dev, "no port exits\n");
544 		return -EINVAL;
545 	}
546 
547 	priv	= devm_kzalloc(dev, sizeof(*priv),		GFP_KERNEL);
548 	cdriv	= devm_kzalloc(dev, sizeof(*cdriv),		GFP_KERNEL);
549 	ddriv	= devm_kzalloc(dev, sizeof(*ddriv) * num,	GFP_KERNEL);
550 	dname	= devm_kzalloc(dev, 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, 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 	} else {
568 		cdriv->name			= "test_codec";
569 		cdriv->idle_bias_on		= 1;
570 		cdriv->endianness		= 1;
571 		cdriv->non_legacy_dai_naming	= 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(dname[i].name, TEST_NAME_LEN, "%s.%d", node->name, i);
605 		ddriv[i].name = dname[i].name;
606 
607 		snprintf(dname[i].name_playback, TEST_NAME_LEN, "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(dname[i].name_capture, TEST_NAME_LEN, "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, cdriv, ddriv, num);
630 	if (ret < 0)
631 		return ret;
632 
633 	mile_stone_x(dev);
634 
635 	return 0;
636 }
637 
638 static int test_driver_remove(struct platform_device *pdev)
639 {
640 	mile_stone_x(&pdev->dev);
641 
642 	return 0;
643 }
644 
645 static struct platform_driver test_driver = {
646 	.driver = {
647 		.name = "test-component",
648 		.of_match_table = test_of_match,
649 	},
650 	.probe  = test_driver_probe,
651 	.remove = test_driver_remove,
652 };
653 module_platform_driver(test_driver);
654 
655 MODULE_ALIAS("platform:asoc-test-component");
656 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
657 MODULE_DESCRIPTION("ASoC Test Component");
658 MODULE_LICENSE("GPL v2");
659