brintos

brintos / linux-shallow public Read only

0
0
Text · 16.1 KiB · 4072880 Raw
648 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// test-component.c  --  Test Audio Component driver4//5// Copyright (C) 2020 Renesas Electronics Corporation6// 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 3217struct 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	else103		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 const u64 test_dai_formats =185	/*186	 * Select below from Sound Card, not auto187	 *	SND_SOC_POSSIBLE_DAIFMT_BP_FP188	 *	SND_SOC_POSSIBLE_DAIFMT_BC_FP189	 *	SND_SOC_POSSIBLE_DAIFMT_BP_FC190	 *	SND_SOC_POSSIBLE_DAIFMT_BC_FC191	 */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 204static 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 212static 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_384000228#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 238static int test_component_probe(struct snd_soc_component *component)239{240	mile_stone(component);241 242	return 0;243}244 245static void test_component_remove(struct snd_soc_component *component)246{247	mile_stone(component);248}249 250static int test_component_suspend(struct snd_soc_component *component)251{252	mile_stone(component);253 254	return 0;255}256 257static 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)265static 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 279static void test_component_pcm_destruct(struct snd_soc_component *component,280					struct snd_pcm *pcm)281{282	mile_stone(component);283}284 285static 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 293static 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 301static 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 309static 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 315static int test_component_stream_event(struct snd_soc_component *component, int event)316{317	mile_stone(component);318 319	return 0;320}321 322static 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 330static 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 343static 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 357static 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 365static 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 374static 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 383static 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 391static 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 399static void test_component_timer_stop(struct test_priv *priv)400{401	cancel_delayed_work(&priv->dwork);402}403 404static void test_component_timer_start(struct test_priv *priv)405{406	schedule_delayed_work(&priv->dwork, msecs_to_jiffies(10));407}408 409static 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 419static 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 439static 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 447static 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 465static 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 477static 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 */486static const struct test_adata test_cpu		= { .is_cpu = 1, .cmp_v = 0, .dai_v = 0, };487static const struct test_adata test_cpu_vv	= { .is_cpu = 1, .cmp_v = 1, .dai_v = 1, };488static const struct test_adata test_cpu_nv	= { .is_cpu = 1, .cmp_v = 0, .dai_v = 1, };489static const struct test_adata test_cpu_vn	= { .is_cpu = 1, .cmp_v = 1, .dai_v = 0, };490/* Codec */491static const struct test_adata test_codec	= { .is_cpu = 0, .cmp_v = 0, .dai_v = 0, };492static const struct test_adata test_codec_vv	= { .is_cpu = 0, .cmp_v = 1, .dai_v = 1, };493static const struct test_adata test_codec_nv	= { .is_cpu = 0, .cmp_v = 0, .dai_v = 1, };494static const struct test_adata test_codec_vn	= { .is_cpu = 0, .cmp_v = 1, .dai_v = 0, };495 496static 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};507MODULE_DEVICE_TABLE(of, test_of_match);508 509static const struct snd_soc_dapm_widget widgets[] = {510	/*511	 * FIXME512	 *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 520static 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		else615			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 629static void test_driver_remove(struct platform_device *pdev)630{631	mile_stone_x(&pdev->dev);632}633 634static 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};642module_platform_driver(test_driver);643 644MODULE_ALIAS("platform:asoc-test-component");645MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");646MODULE_DESCRIPTION("ASoC Test Component");647MODULE_LICENSE("GPL v2");648