summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@ti.com>2011-07-24 20:59:43 +0100
committerAndy Green <andy.green@linaro.org>2011-08-25 07:38:03 +0100
commit2d94e5af43d7e400593d2f575f1861e79292fad4 (patch)
tree37625b740ccd794ca9981249c20ae78b2804edc5 /sound
parent63b68b93f480c261bd03f374aea76005b767ed23 (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.c199
-rw-r--r--sound/soc/soc-dapm.c3
-rw-r--r--sound/soc/soc-pcm.c38
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;