Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable tone generator #3

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion include/sound/soc-dpcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,5 +158,8 @@ static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
kfree(*list);
}


/* create/free virtual FE dai links */
int soc_dpcm_vfe_new(struct snd_soc_card *, int index, const char *link_name,
const char *cpu_dai_name, const char *platform_name);
int soc_dpcm_vfe_free(struct snd_soc_card *card);
#endif
3 changes: 3 additions & 0 deletions include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,9 @@ struct snd_soc_dai_link {
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int ignore:1;

/* virtual link */
unsigned int virtual:1;

struct list_head list; /* DAI link list of the soc card */
struct snd_soc_dobj dobj; /* For topology */
};
Expand Down
1 change: 1 addition & 0 deletions include/uapi/sound/sof-ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ struct sof_ipc_comp_mux {
struct sof_ipc_comp_tone {
struct sof_ipc_comp comp;
struct sof_ipc_comp_config config;
int32_t sample_rate;
int32_t frequency;
int32_t amplitude;
int32_t freq_mult;
Expand Down
4 changes: 4 additions & 0 deletions include/uapi/sound/sof-topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#define SOF_TPLG_KCTL_VOL_ID 256
#define SOF_TPLG_KCTL_ENUM_ID 257
#define SOF_TPLG_KCTL_BYTES_ID 258
#define SOF_TPLG_KCTL_SWITCH_ID 259

/*
* Tokens - must match values in topology configurations
Expand Down Expand Up @@ -88,4 +89,7 @@
#define SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE 705
#define SOF_TKN_INTEL_DMIC_PDM_SKEW 706

/* Tone */
#define SOF_TKN_TONE_SAMPLE_RATE 800

#endif
20 changes: 20 additions & 0 deletions sound/soc/soc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
struct snd_soc_dai **codec_dais;
struct snd_soc_platform *platform;
struct device_node *platform_of_node;
struct snd_pcm_runtime *runtime;
const char *platform_name;
int i;

Expand Down Expand Up @@ -1134,6 +1135,25 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
}

soc_add_pcm_runtime(card, rtd);

/* if the dai link is virtual, create runtime to set it as running */
if (rtd->dai_link->virtual) {
runtime = kzalloc(sizeof(*runtime),
GFP_KERNEL);
if (!runtime)
return -ENOMEM;

if (rtd->dai_link->dpcm_playback) {
rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].runtime = runtime;
rtd->cpu_dai->playback_active = 1;
rtd->codec_dai->playback_active = 1;
}

/* increment the active count for cpu dai */
rtd->cpu_dai->active++;

/* does virtual FE for capture make sense */
}
return 0;

_err_defer:
Expand Down
5 changes: 4 additions & 1 deletion sound/soc/soc-dapm.c
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
kcname_in_long_name = true;
} else {
switch (w->id) {
case snd_soc_dapm_siggen:
case snd_soc_dapm_switch:
case snd_soc_dapm_mixer:
case snd_soc_dapm_pga:
Expand Down Expand Up @@ -1246,7 +1247,8 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
custom_stop_condition);

/* Drop starting point */
list_del(widgets.next);
if (!list_is_singular(&widgets))
list_del(widgets.next);

ret = dapm_widget_list_create(list, &widgets);
if (ret)
Expand Down Expand Up @@ -3076,6 +3078,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
case snd_soc_dapm_demux:
dapm_new_mux(w);
break;
case snd_soc_dapm_siggen:
case snd_soc_dapm_pga:
case snd_soc_dapm_out_drv:
dapm_new_pga(w);
Expand Down
151 changes: 150 additions & 1 deletion sound/soc/soc-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1582,7 +1582,6 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,

/* Create any new FE <--> BE connections */
for (i = 0; i < list->num_widgets; i++) {

switch (list->widgets[i]->id) {
case snd_soc_dapm_dai_in:
if (stream != SNDRV_PCM_STREAM_PLAYBACK)
Expand Down Expand Up @@ -2759,6 +2758,8 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card)
mutex_unlock(&card->mutex);
return 0;
}
EXPORT_SYMBOL_GPL(soc_dpcm_runtime_update);

int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
{
struct snd_soc_dpcm *dpcm;
Expand Down Expand Up @@ -2789,6 +2790,114 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
return 0;
}

/*
* create a virtual FE DAI link
* Virtual FE DAI links are used in hostless pipelines
* to enable the codecs when the pipeline is triggered
*/
int soc_dpcm_vfe_new(struct snd_soc_card *card, int index,
const char *link_name, const char *cpu_dai_name,
const char *platform_name)
{
struct snd_soc_dai_link *link;

link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link)
return -ENOMEM;

dev_dbg(card->dev, "ASoC: adding new virtual FE DAI link %s\n",
link_name);

/* define virtual FE DAI link */
link->virtual = 1;
link->name = link_name;
link->id = 1;
link->cpu_dai_name = cpu_dai_name;
link->platform_name = platform_name;
link->codec_name = "snd-soc-dummy";
link->codec_dai_name = "snd-soc-dummy-dai";
link->num_codecs = 1;

/* allocate memory for link codecs */
link->codecs = devm_kzalloc(card->dev,
sizeof(struct snd_soc_dai_link_component),
GFP_KERNEL);
if (!link->codecs)
return -ENOMEM;

link->codecs[0].name = link->codec_name;
link->codecs[0].dai_name = link->codec_dai_name;

/* enable DPCM */
link->dynamic = 1;

/*TODO: check if we need to handle capture for virtual FE */
link->dpcm_playback = 1;

link->dobj.index = index;
link->dobj.type = SND_SOC_DOBJ_DAI_LINK;

/* add virtual dai link to card dai link list */
snd_soc_add_dai_link(card, link);

return 0;
}
EXPORT_SYMBOL_GPL(soc_dpcm_vfe_new);

/* free virtual FE DAI link */
int soc_dpcm_vfe_free(struct snd_soc_card *card)
{
struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2;
struct snd_soc_pcm_runtime *rtd;
struct snd_pcm_str *pstr;
int stream_dir;

list_for_each_entry(rtd, &card->rtd_list, list) {

/* check if this is a virtual dai link */
if (rtd->dai_link->virtual) {

if (rtd->dai_link->dpcm_playback) {
stream_dir = SNDRV_PCM_STREAM_PLAYBACK;

/* disconnect FE from BE */
dpcm_be_disconnect(rtd, stream_dir);

/* free pcm runtime */
kfree(rtd->dpcm[stream_dir].runtime);

pstr = &rtd->pcm->streams[stream_dir];

/* free pcm substream amd pcm */
kfree(pstr->substream);
}

/* free pcm */
kfree(rtd->pcm);

/* free codec dais and component list */
kfree(rtd->codec_dais);

for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2)
kfree(rtdcom1);

INIT_LIST_HEAD(&rtd->component_list);

/* remove dai_link from card */
snd_soc_remove_dai_link(card, rtd->dai_link);

/* free link */
kfree(rtd->dai_link);

/* free runtime */
kfree(rtd);
}
}

return 0;
}
EXPORT_SYMBOL_GPL(soc_dpcm_vfe_free);

static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
{
struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
Expand Down Expand Up @@ -3004,7 +3113,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_component *component;
struct snd_soc_rtdcom_list *rtdcom;
struct snd_pcm_substream *substream;
struct snd_pcm *pcm;
int stream_dir;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
int i;
Expand Down Expand Up @@ -3043,6 +3154,44 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
playback, capture, &pcm);
} else {

/*
* for virtual FE dai links, there is no need
* to register PCM device. So only allocate memory for
* pcm device and substream for the requested direction
*/
if (rtd->dai_link->virtual) {
struct snd_pcm_str *pstr;

if (rtd->dai_link->dpcm_playback)
stream_dir = SNDRV_PCM_STREAM_PLAYBACK;

pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;

pstr = &pcm->streams[stream_dir];

substream = kzalloc(sizeof(*substream), GFP_KERNEL);
if (!substream)
return -ENOMEM;

substream->pcm = pcm;
substream->pstr = pstr;
substream->number = 0;
substream->stream = stream_dir;
sprintf(substream->name, "subdevice #%i", 0);
substream->buffer_bytes_max = UINT_MAX;

pstr->substream = substream;

pcm->nonatomic = rtd->dai_link->nonatomic;
rtd->pcm = pcm;
pcm->private_data = rtd;

goto out;
}

if (rtd->dai_link->dynamic)
snprintf(new_name, sizeof(new_name), "%s (*)",
rtd->dai_link->stream_name);
Expand Down
Loading