From: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> In current ALSA SoC, Platform only has pcm_new/pcm_free feature, but it should be supported on Component level. This patch adds it. The v1 was added commit 99b04f4c4051f7 ("ASoC: add Component level pcm_new/pcm_free") but it called all "card" connected component's pcm_new/free, it was wrong. This patch calls "rtd" connected component. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> Tested-by: Arnaud Pouliquen <arnaud.pouliquen@xxxxxx> --- include/sound/soc.h | 6 ++++++ sound/soc/soc-core.c | 42 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 30 +++++++++++++++++++++++++----- 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 963eef6..ff5773d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -806,6 +806,10 @@ struct snd_soc_component_driver { int (*suspend)(struct snd_soc_component *); int (*resume)(struct snd_soc_component *); + /* pcm creation and destruction */ + int (*pcm_new)(struct snd_soc_pcm_runtime *); + void (*pcm_free)(struct snd_pcm *); + /* DT */ int (*of_xlate_dai_name)(struct snd_soc_component *component, struct of_phandle_args *args, @@ -881,6 +885,8 @@ struct snd_soc_component { void (*remove)(struct snd_soc_component *); int (*suspend)(struct snd_soc_component *); int (*resume)(struct snd_soc_component *); + int (*pcm_new)(struct snd_soc_component *, struct snd_soc_pcm_runtime *); + void (*pcm_free)(struct snd_soc_component *, struct snd_pcm *); /* machine specific init */ int (*init)(struct snd_soc_component *component); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d65520c..800c5b5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3197,6 +3197,22 @@ static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, return component->driver->stream_event(component, event); } +static int snd_soc_component_drv_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + if (component->driver->pcm_new) + return component->driver->pcm_new(rtd); + + return 0; +} + +static void snd_soc_component_drv_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) +{ + if (component->driver->pcm_free) + component->driver->pcm_free(pcm); +} + static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev) { @@ -3214,6 +3230,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->remove = component->driver->remove; component->suspend = component->driver->suspend; component->resume = component->driver->resume; + component->pcm_new = snd_soc_component_drv_pcm_new; + component->pcm_free= snd_soc_component_drv_pcm_free; dapm = &component->dapm; dapm->dev = dev; @@ -3443,6 +3461,26 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component) platform->driver->remove(platform); } +static int snd_soc_platform_drv_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); + + if (platform->driver->pcm_new) + return platform->driver->pcm_new(rtd); + + return 0; +} + +static void snd_soc_platform_drv_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) +{ + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); + + if (platform->driver->pcm_free) + platform->driver->pcm_free(pcm); +} + /** * snd_soc_add_platform - Add a platform to the ASoC core * @dev: The parent device for the platform @@ -3466,6 +3504,10 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->component.probe = snd_soc_platform_drv_probe; if (platform_drv->remove) platform->component.remove = snd_soc_platform_drv_remove; + if (platform_drv->pcm_new) + platform->component.pcm_new = snd_soc_platform_drv_pcm_new; + if (platform_drv->pcm_free) + platform->component.pcm_free = snd_soc_platform_drv_pcm_free; #ifdef CONFIG_DEBUG_FS platform->component.debugfs_prefix = "platform"; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index df1587c..844bbd5 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2632,12 +2632,28 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) return ret; } +static void soc_pcm_free(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->pcm_free) + component->pcm_free(component, pcm); + } +} + /* create a new pcm */ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) { struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; struct snd_pcm *pcm; char new_name[64]; int ret = 0, playback = 0, capture = 0; @@ -2747,17 +2763,21 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); - if (platform->driver->pcm_new) { - ret = platform->driver->pcm_new(rtd); + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->pcm_new) + continue; + + ret = component->pcm_new(component, rtd); if (ret < 0) { - dev_err(platform->dev, + dev_err(component->dev, "ASoC: pcm constructor failed: %d\n", ret); return ret; } } - - pcm->private_free = platform->driver->pcm_free; + pcm->private_free = soc_pcm_free; out: dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, -- 1.9.1