mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
ASoC: test-component: add Test Component for Sound debug/test
We already have dummy-codec, dummy-platform. But its issues are 1) we don't have dummy-cpu, 2) we can't select it via DeviceTree 3) It do nothing Sometimes we want to have Dummy Sound Component for debugging, for testing, for learning Framework behavior, etc, etc... This patch adds Test-Component driver for it. User can select CPU Component by using "test-cpu" compatible, and can select Codec Component by using "test-codec" compatible. It doesn't support Platform so far, but is easy to add. We can verbose print to know its progress if user selected xxx-verbose compatible driver. for example, test-cpu : silent Component, silent DAI test-cpu-verbose-component : verbose Component, silent DAI test-cpu-verbose-dai : silent Component, verbose DAI test-cpu-verbose : verbose Component, verbose DAI Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Link: https://lore.kernel.org/r/877dein8rx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
5dd7e163e7
commit
d293abc0c8
@ -17,3 +17,9 @@ config SND_AUDIO_GRAPH_CARD
|
||||
This option enables generic simple sound card support
|
||||
with OF-graph DT bindings.
|
||||
It also support DPCM of multi CPU single Codec ststem.
|
||||
|
||||
config SND_TEST_COMPONENT
|
||||
tristate "ASoC Test component sound support"
|
||||
depends on OF
|
||||
help
|
||||
This option enables test component sound driver support.
|
||||
|
@ -2,7 +2,9 @@
|
||||
snd-soc-simple-card-utils-objs := simple-card-utils.o
|
||||
snd-soc-simple-card-objs := simple-card.o
|
||||
snd-soc-audio-graph-card-objs := audio-graph-card.o
|
||||
snd-soc-test-component-objs := test-component.o
|
||||
|
||||
obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o
|
||||
obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o
|
||||
obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o
|
||||
obj-$(CONFIG_SND_TEST_COMPONENT) += snd-soc-test-component.o
|
||||
|
659
sound/soc/generic/test-component.c
Normal file
659
sound/soc/generic/test-component.c
Normal file
@ -0,0 +1,659 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// test-component.c -- Test Audio Component driver
|
||||
//
|
||||
// Copyright (C) 2020 Renesas Electronics Corporation
|
||||
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#define TEST_NAME_LEN 32
|
||||
struct test_dai_name {
|
||||
char name[TEST_NAME_LEN];
|
||||
char name_playback[TEST_NAME_LEN];
|
||||
char name_capture[TEST_NAME_LEN];
|
||||
};
|
||||
|
||||
struct test_priv {
|
||||
struct device *dev;
|
||||
struct snd_pcm_substream *substream;
|
||||
struct delayed_work dwork;
|
||||
struct snd_soc_component_driver *component_driver;
|
||||
struct snd_soc_dai_driver *dai_driver;
|
||||
struct test_dai_name *name;
|
||||
};
|
||||
|
||||
struct test_adata {
|
||||
u32 is_cpu:1;
|
||||
u32 cmp_v:1;
|
||||
u32 dai_v:1;
|
||||
};
|
||||
|
||||
#define mile_stone(d) dev_info((d)->dev, "%s() : %s", __func__, (d)->driver->name)
|
||||
#define mile_stone_x(dev) dev_info(dev, "%s()", __func__)
|
||||
|
||||
static int test_dai_set_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
unsigned int format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
unsigned int clock = fmt & SND_SOC_DAIFMT_CLOCK_MASK;
|
||||
unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK;
|
||||
unsigned int master = fmt & SND_SOC_DAIFMT_MASTER_MASK;
|
||||
char *str;
|
||||
|
||||
dev_info(dai->dev, "name : %s", dai->name);
|
||||
|
||||
str = "unknown";
|
||||
switch (format) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
str = "i2s";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
str = "right_j";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
str = "left_j";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
str = "dsp_a";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
str = "dsp_b";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_AC97:
|
||||
str = "ac97";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_PDM:
|
||||
str = "pdm";
|
||||
break;
|
||||
}
|
||||
dev_info(dai->dev, "format : %s", str);
|
||||
|
||||
if (clock == SND_SOC_DAIFMT_CONT)
|
||||
str = "continuous";
|
||||
else
|
||||
str = "gated";
|
||||
dev_info(dai->dev, "clock : %s", str);
|
||||
|
||||
str = "unknown";
|
||||
switch (master) {
|
||||
case SND_SOC_DAIFMT_CBP_CFP:
|
||||
str = "clk provider, frame provider";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBC_CFP:
|
||||
str = "clk consumer, frame provider";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBP_CFC:
|
||||
str = "clk provider, frame consumer";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBC_CFC:
|
||||
str = "clk consumer, frame consumer";
|
||||
break;
|
||||
}
|
||||
dev_info(dai->dev, "clock : codec is %s", str);
|
||||
|
||||
str = "unknown";
|
||||
switch (inv) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
str = "normal bit, normal frame";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
str = "normal bit, invert frame";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
str = "invert bit, normal frame";
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
str = "invert bit, invert frame";
|
||||
break;
|
||||
}
|
||||
dev_info(dai->dev, "signal : %s", str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||
{
|
||||
mile_stone(dai);
|
||||
}
|
||||
|
||||
static int test_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
mile_stone(dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 test_dai_formats =
|
||||
/*
|
||||
* Select below from Sound Card, not auto
|
||||
* SND_SOC_POSSIBLE_DAIFMT_CBP_CFP
|
||||
* SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
|
||||
* SND_SOC_POSSIBLE_DAIFMT_CBP_CFC
|
||||
* SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
|
||||
*/
|
||||
SND_SOC_POSSIBLE_DAIFMT_I2S |
|
||||
SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
|
||||
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
|
||||
SND_SOC_POSSIBLE_DAIFMT_DSP_A |
|
||||
SND_SOC_POSSIBLE_DAIFMT_DSP_B |
|
||||
SND_SOC_POSSIBLE_DAIFMT_AC97 |
|
||||
SND_SOC_POSSIBLE_DAIFMT_PDM |
|
||||
SND_SOC_POSSIBLE_DAIFMT_NB_NF |
|
||||
SND_SOC_POSSIBLE_DAIFMT_NB_IF |
|
||||
SND_SOC_POSSIBLE_DAIFMT_IB_NF |
|
||||
SND_SOC_POSSIBLE_DAIFMT_IB_IF;
|
||||
|
||||
static const struct snd_soc_dai_ops test_ops = {
|
||||
.set_fmt = test_dai_set_fmt,
|
||||
.startup = test_dai_startup,
|
||||
.shutdown = test_dai_shutdown,
|
||||
.auto_selectable_formats = &test_dai_formats,
|
||||
.num_auto_selectable_formats = 1,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops test_verbose_ops = {
|
||||
.set_sysclk = test_dai_set_sysclk,
|
||||
.set_pll = test_dai_set_pll,
|
||||
.set_clkdiv = test_dai_set_clkdiv,
|
||||
.set_fmt = test_dai_set_fmt,
|
||||
.mute_stream = test_dai_mute_stream,
|
||||
.startup = test_dai_startup,
|
||||
.shutdown = test_dai_shutdown,
|
||||
.hw_params = test_dai_hw_params,
|
||||
.hw_free = test_dai_hw_free,
|
||||
.trigger = test_dai_trigger,
|
||||
.bespoke_trigger = test_dai_bespoke_trigger,
|
||||
.auto_selectable_formats = &test_dai_formats,
|
||||
.num_auto_selectable_formats = 1,
|
||||
};
|
||||
|
||||
#define STUB_RATES SNDRV_PCM_RATE_8000_384000
|
||||
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
|
||||
SNDRV_PCM_FMTBIT_U8 | \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_U16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_3LE | \
|
||||
SNDRV_PCM_FMTBIT_U24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE | \
|
||||
SNDRV_PCM_FMTBIT_U32_LE)
|
||||
|
||||
static int test_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_component_remove(struct snd_soc_component *component)
|
||||
{
|
||||
mile_stone(component);
|
||||
}
|
||||
|
||||
static int test_component_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_resume(struct snd_soc_component *component)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PREALLOC_BUFFER (32 * 1024)
|
||||
static int test_component_pcm_construct(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
snd_pcm_set_managed_buffer_all(
|
||||
rtd->pcm,
|
||||
SNDRV_DMA_TYPE_DEV,
|
||||
rtd->card->snd_card->dev,
|
||||
PREALLOC_BUFFER, PREALLOC_BUFFER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_component_pcm_destruct(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm)
|
||||
{
|
||||
mile_stone(component);
|
||||
}
|
||||
|
||||
static int test_component_set_sysclk(struct snd_soc_component *component,
|
||||
int clk_id, int source, unsigned int freq, int dir)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_set_pll(struct snd_soc_component *component, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_set_jack(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, void *data)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_component_seq_notifier(struct snd_soc_component *component,
|
||||
enum snd_soc_dapm_type type, int subseq)
|
||||
{
|
||||
mile_stone(component);
|
||||
}
|
||||
|
||||
static int test_component_stream_event(struct snd_soc_component *component, int event)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_hardware test_component_hardware = {
|
||||
/* Random values to keep userspace happy when checking constraints */
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID,
|
||||
.buffer_bytes_max = 32 * 1024,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 8192,
|
||||
.periods_min = 1,
|
||||
.periods_max = 128,
|
||||
.fifo_size = 256,
|
||||
};
|
||||
|
||||
static int test_component_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
|
||||
mile_stone(component);
|
||||
|
||||
/* BE's dont need dummy params */
|
||||
if (!rtd->dai_link->no_pcm)
|
||||
snd_soc_set_runtime_hwparams(substream, &test_component_hardware);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_ioctl(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_component_timer_stop(struct test_priv *priv)
|
||||
{
|
||||
cancel_delayed_work(&priv->dwork);
|
||||
}
|
||||
|
||||
static void test_component_timer_start(struct test_priv *priv)
|
||||
{
|
||||
schedule_delayed_work(&priv->dwork, msecs_to_jiffies(10));
|
||||
}
|
||||
|
||||
static void test_component_dwork(struct work_struct *work)
|
||||
{
|
||||
struct test_priv *priv = container_of(work, struct test_priv, dwork.work);
|
||||
|
||||
if (priv->substream)
|
||||
snd_pcm_period_elapsed(priv->substream);
|
||||
|
||||
test_component_timer_start(priv);
|
||||
}
|
||||
|
||||
static int test_component_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct test_priv *priv = dev_get_drvdata(component->dev);
|
||||
|
||||
mile_stone(component);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
test_component_timer_start(priv);
|
||||
priv->substream = substream; /* set substream later */
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
priv->substream = NULL;
|
||||
test_component_timer_stop(priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_sync_stop(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t test_component_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
static int pointer;
|
||||
|
||||
if (!runtime)
|
||||
return 0;
|
||||
|
||||
pointer += 10;
|
||||
if (pointer > PREALLOC_BUFFER)
|
||||
pointer = 0;
|
||||
|
||||
/* mile_stone(component); */
|
||||
|
||||
return bytes_to_frames(runtime, pointer);
|
||||
}
|
||||
|
||||
static int test_component_get_time_info(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct timespec64 *system_ts,
|
||||
struct timespec64 *audio_ts,
|
||||
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
|
||||
struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
|
||||
{
|
||||
mile_stone(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_component_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
mile_stone_x(rtd->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CPU */
|
||||
static const struct test_adata test_cpu = { .is_cpu = 1, .cmp_v = 0, .dai_v = 0, };
|
||||
static const struct test_adata test_cpu_vv = { .is_cpu = 1, .cmp_v = 1, .dai_v = 1, };
|
||||
static const struct test_adata test_cpu_nv = { .is_cpu = 1, .cmp_v = 0, .dai_v = 1, };
|
||||
static const struct test_adata test_cpu_vn = { .is_cpu = 1, .cmp_v = 1, .dai_v = 0, };
|
||||
/* Codec */
|
||||
static const struct test_adata test_codec = { .is_cpu = 0, .cmp_v = 0, .dai_v = 0, };
|
||||
static const struct test_adata test_codec_vv = { .is_cpu = 0, .cmp_v = 1, .dai_v = 1, };
|
||||
static const struct test_adata test_codec_nv = { .is_cpu = 0, .cmp_v = 0, .dai_v = 1, };
|
||||
static const struct test_adata test_codec_vn = { .is_cpu = 0, .cmp_v = 1, .dai_v = 0, };
|
||||
|
||||
static const struct of_device_id test_of_match[] = {
|
||||
{ .compatible = "test-cpu", .data = (void *)&test_cpu, },
|
||||
{ .compatible = "test-cpu-verbose", .data = (void *)&test_cpu_vv, },
|
||||
{ .compatible = "test-cpu-verbose-dai", .data = (void *)&test_cpu_nv, },
|
||||
{ .compatible = "test-cpu-verbose-component", .data = (void *)&test_cpu_vn, },
|
||||
{ .compatible = "test-codec", .data = (void *)&test_codec, },
|
||||
{ .compatible = "test-codec-verbose", .data = (void *)&test_codec_vv, },
|
||||
{ .compatible = "test-codec-verbose-dai", .data = (void *)&test_codec_nv, },
|
||||
{ .compatible = "test-codec-verbose-component", .data = (void *)&test_codec_vn, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, test_of_match);
|
||||
|
||||
static const struct snd_soc_dapm_widget widgets[] = {
|
||||
/*
|
||||
* FIXME
|
||||
*
|
||||
* Just IN/OUT is OK for now,
|
||||
* but need to be updated ?
|
||||
*/
|
||||
SND_SOC_DAPM_INPUT("IN"),
|
||||
SND_SOC_DAPM_OUTPUT("OUT"),
|
||||
};
|
||||
|
||||
static int test_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *ep;
|
||||
const struct of_device_id *of_id = of_match_device(test_of_match, &pdev->dev);
|
||||
const struct test_adata *adata = of_id->data;
|
||||
struct snd_soc_component_driver *cdriv;
|
||||
struct snd_soc_dai_driver *ddriv;
|
||||
struct test_dai_name *dname;
|
||||
struct test_priv *priv;
|
||||
int num, ret, i;
|
||||
|
||||
num = of_graph_get_endpoint_count(node);
|
||||
if (!num) {
|
||||
dev_err(dev, "no port exits\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
cdriv = devm_kzalloc(dev, sizeof(*cdriv), GFP_KERNEL);
|
||||
ddriv = devm_kzalloc(dev, sizeof(*ddriv) * num, GFP_KERNEL);
|
||||
dname = devm_kzalloc(dev, sizeof(*dname) * num, GFP_KERNEL);
|
||||
if (!priv || !cdriv || !ddriv || !dname)
|
||||
return -EINVAL;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->component_driver = cdriv;
|
||||
priv->dai_driver = ddriv;
|
||||
priv->name = dname;
|
||||
|
||||
INIT_DELAYED_WORK(&priv->dwork, test_component_dwork);
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
||||
if (adata->is_cpu) {
|
||||
cdriv->name = "test_cpu";
|
||||
cdriv->pcm_construct = test_component_pcm_construct;
|
||||
cdriv->pointer = test_component_pointer;
|
||||
cdriv->trigger = test_component_trigger;
|
||||
} else {
|
||||
cdriv->name = "test_codec";
|
||||
cdriv->idle_bias_on = 1;
|
||||
cdriv->endianness = 1;
|
||||
cdriv->non_legacy_dai_naming = 1;
|
||||
}
|
||||
|
||||
cdriv->open = test_component_open;
|
||||
cdriv->dapm_widgets = widgets;
|
||||
cdriv->num_dapm_widgets = ARRAY_SIZE(widgets);
|
||||
|
||||
if (adata->cmp_v) {
|
||||
cdriv->probe = test_component_probe;
|
||||
cdriv->remove = test_component_remove;
|
||||
cdriv->suspend = test_component_suspend;
|
||||
cdriv->resume = test_component_resume;
|
||||
cdriv->set_sysclk = test_component_set_sysclk;
|
||||
cdriv->set_pll = test_component_set_pll;
|
||||
cdriv->set_jack = test_component_set_jack;
|
||||
cdriv->seq_notifier = test_component_seq_notifier;
|
||||
cdriv->stream_event = test_component_stream_event;
|
||||
cdriv->set_bias_level = test_component_set_bias_level;
|
||||
cdriv->close = test_component_close;
|
||||
cdriv->ioctl = test_component_ioctl;
|
||||
cdriv->hw_params = test_component_hw_params;
|
||||
cdriv->hw_free = test_component_hw_free;
|
||||
cdriv->prepare = test_component_prepare;
|
||||
cdriv->sync_stop = test_component_sync_stop;
|
||||
cdriv->get_time_info = test_component_get_time_info;
|
||||
cdriv->be_hw_params_fixup = test_component_be_hw_params_fixup;
|
||||
|
||||
if (adata->is_cpu)
|
||||
cdriv->pcm_destruct = test_component_pcm_destruct;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for_each_endpoint_of_node(node, ep) {
|
||||
snprintf(dname[i].name, TEST_NAME_LEN, "%s.%d", node->name, i);
|
||||
ddriv[i].name = dname[i].name;
|
||||
|
||||
snprintf(dname[i].name_playback, TEST_NAME_LEN, "DAI%d Playback", i);
|
||||
ddriv[i].playback.stream_name = dname[i].name_playback;
|
||||
ddriv[i].playback.channels_min = 1;
|
||||
ddriv[i].playback.channels_max = 384;
|
||||
ddriv[i].playback.rates = STUB_RATES;
|
||||
ddriv[i].playback.formats = STUB_FORMATS;
|
||||
|
||||
snprintf(dname[i].name_capture, TEST_NAME_LEN, "DAI%d Capture", i);
|
||||
ddriv[i].capture.stream_name = dname[i].name_capture;
|
||||
ddriv[i].capture.channels_min = 1;
|
||||
ddriv[i].capture.channels_max = 384;
|
||||
ddriv[i].capture.rates = STUB_RATES;
|
||||
ddriv[i].capture.formats = STUB_FORMATS;
|
||||
|
||||
if (adata->dai_v)
|
||||
ddriv[i].ops = &test_verbose_ops;
|
||||
else
|
||||
ddriv[i].ops = &test_ops;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, cdriv, ddriv, num);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mile_stone_x(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
mile_stone_x(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver test_driver = {
|
||||
.driver = {
|
||||
.name = "test-component",
|
||||
.of_match_table = test_of_match,
|
||||
},
|
||||
.probe = test_driver_probe,
|
||||
.remove = test_driver_remove,
|
||||
};
|
||||
module_platform_driver(test_driver);
|
||||
|
||||
MODULE_ALIAS("platform:asoc-test-component");
|
||||
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
|
||||
MODULE_DESCRIPTION("ASoC Test Component");
|
||||
MODULE_LICENSE("GPL v2");
|
Loading…
Reference in New Issue
Block a user