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
17struct 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
23struct 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
32struct 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
41static 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
49static 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
57static 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
64static 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
143static 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
150static 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
157static void test_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
158{
159	mile_stone(dai);
160}
161
162static 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
170static 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
177static 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
184static 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
192static 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
212static 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
220static 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
247static int test_component_probe(struct snd_soc_component *component)
248{
249	mile_stone(component);
250
251	return 0;
252}
253
254static void test_component_remove(struct snd_soc_component *component)
255{
256	mile_stone(component);
257}
258
259static int test_component_suspend(struct snd_soc_component *component)
260{
261	mile_stone(component);
262
263	return 0;
264}
265
266static 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)
274static 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
288static void test_component_pcm_destruct(struct snd_soc_component *component,
289					struct snd_pcm *pcm)
290{
291	mile_stone(component);
292}
293
294static 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
302static 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
310static 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
318static 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
324static int test_component_stream_event(struct snd_soc_component *component, int event)
325{
326	mile_stone(component);
327
328	return 0;
329}
330
331static 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
339static 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
352static 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, &test_component_hardware);
362
363	return 0;
364}
365
366static 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
374static 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
383static 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
392static 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
400static 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
408static void test_component_timer_stop(struct test_priv *priv)
409{
410	cancel_delayed_work(&priv->dwork);
411}
412
413static void test_component_timer_start(struct test_priv *priv)
414{
415	schedule_delayed_work(&priv->dwork, msecs_to_jiffies(10));
416}
417
418static 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
428static 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
448static 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
456static 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
474static 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
486static 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 */
495static const struct test_adata test_cpu		= { .is_cpu = 1, .cmp_v = 0, .dai_v = 0, };
496static const struct test_adata test_cpu_vv	= { .is_cpu = 1, .cmp_v = 1, .dai_v = 1, };
497static const struct test_adata test_cpu_nv	= { .is_cpu = 1, .cmp_v = 0, .dai_v = 1, };
498static const struct test_adata test_cpu_vn	= { .is_cpu = 1, .cmp_v = 1, .dai_v = 0, };
499/* Codec */
500static const struct test_adata test_codec	= { .is_cpu = 0, .cmp_v = 0, .dai_v = 0, };
501static const struct test_adata test_codec_vv	= { .is_cpu = 0, .cmp_v = 1, .dai_v = 1, };
502static const struct test_adata test_codec_nv	= { .is_cpu = 0, .cmp_v = 0, .dai_v = 1, };
503static const struct test_adata test_codec_vn	= { .is_cpu = 0, .cmp_v = 1, .dai_v = 0, };
504
505static 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};
516MODULE_DEVICE_TABLE(of, test_of_match);
517
518static 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
529static 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		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(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
638static void test_driver_remove(struct platform_device *pdev)
639{
640	mile_stone_x(&pdev->dev);
641}
642
643static 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};
651module_platform_driver(test_driver);
652
653MODULE_ALIAS("platform:asoc-test-component");
654MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
655MODULE_DESCRIPTION("ASoC Test Component");
656MODULE_LICENSE("GPL v2");
657