diff options
author | Liam Girdwood <lrg@ti.com> | 2011-07-24 20:59:43 +0100 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2011-08-25 07:38:03 +0100 |
commit | 2d94e5af43d7e400593d2f575f1861e79292fad4 (patch) | |
tree | 37625b740ccd794ca9981249c20ae78b2804edc5 /sound | |
parent | 63b68b93f480c261bd03f374aea76005b767ed23 (diff) |
Subject: [PATCH 072/104] ASoC: dsp - add DSP support to ASoC core.
Add DSP support to ASoC core.
This adds a NULL CODEC driver allow binding and configuration of
DSP DAIs, configures the PCM for DSP, initilaises the DSP state
variables and managed the DSP DAI link registration.
TODO: come cleanup and refactor some variable names.
TODO: split out with previous patch into smaller patches.
Signed-off-by: Liam Girdwood <lrg@ti.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/soc-core.c | 199 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 3 | ||||
-rw-r--r-- | sound/soc/soc-pcm.c | 38 |
3 files changed, 196 insertions, 44 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3d3314185cd..a00637c37a3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -37,6 +37,7 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/soc-dsp.h> #include <sound/initval.h> #define CREATE_TRACE_POINTS @@ -58,6 +59,7 @@ static LIST_HEAD(platform_list); static LIST_HEAD(codec_list); int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); +int soc_dsp_debugfs_add(struct snd_soc_pcm_runtime *rtd); /* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -451,6 +453,35 @@ static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card) } #endif +struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, + const char *dai_link, int stream) +{ + int i; + + for (i = 0; i < card->num_links; i++) { + if (card->rtd[i].dai_link->no_pcm && + !strcmp(card->rtd[i].dai_link->name, dai_link)) + return card->rtd[i].pcm->streams[stream].substream; + } + dev_dbg(card->dev, "failed to find dai link %s\n", dai_link); + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); + +struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, + const char *dai_link) +{ + int i; + + for (i = 0; i < card->num_links; i++) { + if (!strcmp(card->rtd[i].dai_link->name, dai_link)) + return &card->rtd[i]; + } + dev_dbg(card->dev, "failed to find rtd %s\n", dai_link); + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); + #ifdef CONFIG_SND_SOC_AC97_BUS /* unregister ac97 codec */ static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) @@ -513,16 +544,22 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_dai *dai = card->rtd[i].codec_dai; struct snd_soc_dai_driver *drv = dai->driver; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, 1); + if (card->rtd[i].dai_link->dynamic) + soc_dsp_be_digital_mute(&card->rtd[i], 1); + else { + if (drv->ops->digital_mute && dai->playback_active) + drv->ops->digital_mute(dai, 1); + } } /* suspend all pcms */ for (i = 0; i < card->num_rtd; i++) { - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; snd_pcm_suspend_all(card->rtd[i].pcm); @@ -535,14 +572,20 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; struct snd_soc_platform *platform = card->rtd[i].platform; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) - cpu_dai->driver->suspend(cpu_dai); - if (platform->driver->suspend && !platform->suspended) { - platform->driver->suspend(cpu_dai); - platform->suspended = 1; + if (card->rtd[i].dai_link->dynamic) { + soc_dsp_be_cpu_dai_suspend(&card->rtd[i]); + soc_dsp_be_platform_suspend(&card->rtd[i]); + } else { + if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) + cpu_dai->driver->suspend(cpu_dai); + if (platform->driver->suspend && !platform->suspended) { + platform->driver->suspend(cpu_dai); + platform->suspended = 1; + } } } @@ -555,7 +598,8 @@ int snd_soc_suspend(struct device *dev) for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; if (driver->playback.stream_name != NULL) @@ -589,11 +633,15 @@ int snd_soc_suspend(struct device *dev) for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) - cpu_dai->driver->suspend(cpu_dai); + if (card->rtd[i].dai_link->dynamic) + soc_dsp_be_ac97_cpu_dai_suspend(&card->rtd[i]); + else + if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) + cpu_dai->driver->suspend(cpu_dai); } if (card->suspend_post) @@ -629,11 +677,15 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) - cpu_dai->driver->resume(cpu_dai); + if (card->rtd[i].dai_link->dynamic) + soc_dsp_be_ac97_cpu_dai_resume(&card->rtd[i]); + else + if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) + cpu_dai->driver->resume(cpu_dai); } list_for_each_entry(codec, &card->codec_dev_list, card_list) { @@ -658,7 +710,8 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; if (driver->playback.stream_name != NULL) @@ -675,25 +728,36 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_dai *dai = card->rtd[i].codec_dai; struct snd_soc_dai_driver *drv = dai->driver; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, 0); + if (card->rtd[i].dai_link->dynamic) + soc_dsp_be_digital_mute(&card->rtd[i], 0); + else { + if (drv->ops->digital_mute && dai->playback_active) + drv->ops->digital_mute(dai, 0); + } } for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; struct snd_soc_platform *platform = card->rtd[i].platform; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) - cpu_dai->driver->resume(cpu_dai); - if (platform->driver->resume && platform->suspended) { - platform->driver->resume(cpu_dai); - platform->suspended = 0; + if (card->rtd[i].dai_link->dynamic) { + soc_dsp_be_cpu_dai_resume(&card->rtd[i]); + soc_dsp_be_platform_resume(&card->rtd[i]); + } else { + if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) + cpu_dai->driver->resume(cpu_dai); + if (platform->driver->resume && platform->suspended) { + platform->driver->resume(cpu_dai); + platform->suspended = 0; + } } } @@ -738,8 +802,30 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); #define snd_soc_resume NULL #endif +#define NULL_FORMATS \ + (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |\ + SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |\ + SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32) + static struct snd_soc_dai_ops null_dai_ops = { }; +static struct snd_soc_dai_driver null_codec_dai_drv = { + .name = "null-codec-dai", + .ops = &null_dai_ops, + .capture = { + .channels_min = 1 , + .channels_max = 16, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = NULL_FORMATS, + }, + .playback = { + .channels_min = 1 , + .channels_max = 16, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = NULL_FORMATS, + }, +}; +static struct snd_soc_codec_driver null_codec_drv = {}; static int soc_bind_dai_link(struct snd_soc_card *card, int num) { @@ -1068,6 +1154,10 @@ static int soc_post_component_init(struct snd_soc_card *card, rtd->dev.release = rtd_release; rtd->dev.init_name = name; mutex_init(&rtd->pcm_mutex); + INIT_LIST_HEAD(&rtd->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients); + INIT_LIST_HEAD(&rtd->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients); + INIT_LIST_HEAD(&rtd->dsp[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); + INIT_LIST_HEAD(&rtd->dsp[SNDRV_PCM_STREAM_CAPTURE].fe_clients); ret = device_register(&rtd->dev); if (ret < 0) { dev_err(card->dev, @@ -1089,6 +1179,17 @@ static int soc_post_component_init(struct snd_soc_card *card, dev_err(codec->dev, "asoc: failed to add codec sysfs files: %d\n", ret); +#ifdef CONFIG_DEBUG_FS + /* add DSP sysfs entries */ + if (!dai_link->dynamic) + goto out; + + ret = soc_dsp_debugfs_add(rtd); + if (ret < 0) + dev_err(&rtd->dev, "asoc: failed to add dsp sysfs entries: %d\n", ret); + +out: +#endif return 0; } @@ -1861,6 +1962,8 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, const struct snd_pcm_hardware *hw) { struct snd_pcm_runtime *runtime = substream->runtime; + if (!runtime) + return 0; runtime->hw.info = hw->info; runtime->hw.formats = hw->formats; runtime->hw.period_bytes_min = hw->period_bytes_min; @@ -2850,6 +2953,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); int snd_soc_register_card(struct snd_soc_card *card) { int i; + int ret = 0; if (!card->name || !card->dev) return -EINVAL; @@ -2867,12 +2971,41 @@ int snd_soc_register_card(struct snd_soc_card *card) return -ENOMEM; card->rtd_aux = &card->rtd[card->num_links]; - for (i = 0; i < card->num_links; i++) - card->rtd[i].dai_link = &card->dai_link[i]; + for (i = 0; i < card->num_links; i++) { + card->rtd[i].dai_link = &card->dai_link[i]; + if (card->rtd[i].dai_link->dynamic) { + + card->rtd[i].dai_link->codec_name = "null-codec"; + card->rtd[i].dai_link->codec_dai_name = "null-codec-dai"; + + ret = snd_soc_register_codec(card->dev, &null_codec_drv, + &null_codec_dai_drv, 1); + if (ret < 0) { + printk(KERN_ERR "%s: failed to register dynamic DAI link %d\n", + __func__, ret); + goto out; + } + + continue; + } + if (card->rtd[i].dai_link->no_codec) { + card->rtd[i].dai_link->codec_name = "null-codec"; + + ret = snd_soc_register_codec(card->dev, &null_codec_drv, + &null_codec_dai_drv, 1); + if (ret < 0) { + printk(KERN_ERR "%s: failed to register dynamic DAI link %d\n", + __func__, ret); + goto out; + } + continue; + } + } INIT_LIST_HEAD(&card->list); card->instantiated = 0; mutex_init(&card->mutex); + mutex_init(&card->dsp_mutex); mutex_lock(&client_mutex); list_add(&card->list, &card_list); @@ -2881,7 +3014,8 @@ int snd_soc_register_card(struct snd_soc_card *card) dev_dbg(card->dev, "Registered card '%s'\n", card->name); - return 0; +out: + return ret; } EXPORT_SYMBOL_GPL(snd_soc_register_card); @@ -3222,7 +3356,10 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; /* create CODEC component name */ - codec->name = fmt_single_name(dev, &codec->id); + if (codec_drv == &null_codec_drv) + codec->name = kstrdup("null-codec", GFP_KERNEL); + else + codec->name = fmt_single_name(dev, &codec->id); if (codec->name == NULL) { kfree(codec); return -ENOMEM; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a9b3fb1b49f..0818a4a4719 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2895,6 +2895,9 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, { struct snd_soc_dapm_widget *w; + if (!dapm) + return; + list_for_each_entry(w, &dapm->card->widgets, list) { if (!w->sname || w->dapm != dapm) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index f62f925552a..1878fcc7fa2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -122,6 +122,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } + /* DSP DAI links compat checks are different */ + if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) + goto dynamic; + /* Check that the codec and cpu DAIs are compatible */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { runtime->hw.rate_min = @@ -205,6 +209,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, runtime->hw.rate_max); +dynamic: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active++; codec_dai->playback_active++; @@ -2049,6 +2054,7 @@ 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 = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_pcm_substream *substream[2]; struct snd_pcm *pcm; char new_name[64]; int ret = 0, playback = 0, capture = 0; @@ -2057,10 +2063,15 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) snprintf(new_name, sizeof(new_name), "%s %s-%d", rtd->dai_link->stream_name, codec_dai->name, num); - if (codec_dai->driver->playback.channels_min) - playback = 1; - if (codec_dai->driver->capture.channels_min) - capture = 1; + if (rtd->dai_link->dynamic) { + playback = rtd->dai_link->dsp_link->playback; + capture = rtd->dai_link->dsp_link->capture; + } else { + if (codec_dai->driver->playback.channels_min) + playback = 1; + if (codec_dai->driver->capture.channels_min) + capture = 1; + } dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name); ret = snd_pcm_new(rtd->card->snd_card, new_name, @@ -2099,6 +2110,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) &no_host_hardware); } + /* ASoC PCM operations */ if (rtd->dai_link->dynamic) { rtd->ops.open = soc_dsp_fe_dai_open; @@ -2119,20 +2131,18 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.ioctl = soc_pcm_ioctl; if (platform->driver->ops) { - soc_pcm_ops.mmap = platform->driver->ops->mmap; - soc_pcm_ops.pointer = platform->driver->ops->pointer; - soc_pcm_ops.ioctl = platform->driver->ops->ioctl; - soc_pcm_ops.copy = platform->driver->ops->copy; - soc_pcm_ops.silence = platform->driver->ops->silence; - soc_pcm_ops.ack = platform->driver->ops->ack; - soc_pcm_ops.page = platform->driver->ops->page; + rtd->ops.ack = platform->driver->ops->ack; + rtd->ops.copy = platform->driver->ops->copy; + rtd->ops.silence = platform->driver->ops->silence; + rtd->ops.page = platform->driver->ops->page; + rtd->ops.mmap = platform->driver->ops->mmap; } if (playback) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops); if (capture) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); if (platform->driver->pcm_new) { ret = platform->driver->pcm_new(rtd); @@ -2143,6 +2153,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } pcm->private_free = platform->driver->pcm_free; + +out: printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; |