aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/apple/mca.c79
-rw-r--r--sound/soc/codecs/tas2562.c90
-rw-r--r--sound/soc/codecs/wm_adsp.c4
-rw-r--r--sound/soc/soc-pcm.c112
-rw-r--r--sound/soc/sof/sof-audio.c29
5 files changed, 154 insertions, 160 deletions
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index aa67d57c9a9b..69643524796e 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -885,6 +885,43 @@ static snd_pcm_uframes_t mca_pointer(struct snd_soc_component *component,
return snd_dmaengine_pcm_pointer(substream);
}
+static struct dma_chan *mca_request_dma_channel(struct mca_cluster *cl, unsigned int stream)
+{
+ bool is_tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+#ifndef USE_RXB_FOR_CAPTURE
+ char *name = devm_kasprintf(cl->host->dev, GFP_KERNEL,
+ is_tx ? "tx%da" : "rx%da", cl->no);
+#else
+ char *name = devm_kasprintf(cl->host->dev, GFP_KERNEL,
+ is_tx ? "tx%da" : "rx%db", cl->no);
+#endif
+ return of_dma_request_slave_channel(cl->host->dev->of_node, name);
+
+}
+
+static void mca_pcm_free(struct snd_soc_component *component,
+ struct snd_pcm *pcm)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_chip(pcm);
+ struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0));
+ unsigned int i;
+
+ if (rtd->dai_link->no_pcm)
+ return;
+
+ for_each_pcm_streams(i) {
+ struct snd_pcm_substream *substream =
+ rtd->pcm->streams[i].substream;
+
+ if (!substream || !cl->dma_chans[i])
+ continue;
+
+ dma_release_channel(cl->dma_chans[i]);
+ cl->dma_chans[i] = NULL;
+ }
+}
+
+
static int mca_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
@@ -897,17 +934,21 @@ static int mca_pcm_new(struct snd_soc_component *component,
for_each_pcm_streams(i) {
struct snd_pcm_substream *substream =
rtd->pcm->streams[i].substream;
- struct dma_chan *chan = cl->dma_chans[i];
+ struct dma_chan *chan;
if (!substream)
continue;
- if (!chan) {
- dev_err(component->dev, "missing DMA channel for stream %d on SERDES %d\n",
- i, cl->no);
+ chan = mca_request_dma_channel(cl, i);
+
+ if (IS_ERR_OR_NULL(chan)) {
+ dev_err(component->dev, "unable to obtain DMA channel (stream %d cluster %d): %pe\n",
+ i, cl->no, chan);
+ mca_pcm_free(component, rtd->pcm);
return -EINVAL;
}
+ cl->dma_chans[i] = chan;
snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV_IRAM,
chan->device->dev, 512 * 1024 * 6,
SIZE_MAX);
@@ -924,6 +965,7 @@ static const struct snd_soc_component_driver mca_component = {
.trigger = mca_trigger,
.pointer = mca_pointer,
.pcm_construct = mca_pcm_new,
+ .pcm_destruct = mca_pcm_free,
};
static void apple_mca_release(struct mca_data *mca)
@@ -1019,7 +1061,6 @@ static int apple_mca_probe(struct platform_device *pdev)
struct snd_soc_dai_driver *fe =
&dai_drivers[mca->nclusters + i];
struct snd_soc_dai_driver *be = &dai_drivers[i];
- int stream;
cl->host = mca;
cl->no = i;
@@ -1041,34 +1082,6 @@ static int apple_mca_probe(struct platform_device *pdev)
goto err_release;
}
- for_each_pcm_streams(stream) {
- struct dma_chan *chan;
- bool is_tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
-#ifndef USE_RXB_FOR_CAPTURE
- char *name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
- is_tx ? "tx%da" : "rx%da",
- i);
-#else
- char *name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
- is_tx ? "tx%da" : "rx%db",
- i);
-#endif
-
- chan = of_dma_request_slave_channel(pdev->dev.of_node,
- name);
- if (IS_ERR(chan)) {
- if (PTR_ERR(chan) != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "no %s DMA channel: %ld\n",
- name, PTR_ERR(chan));
-
- ret = PTR_ERR(chan);
- goto err_release;
- }
-
- cl->dma_chans[stream] = chan;
- }
-
fe->id = i;
fe->name =
devm_kasprintf(&pdev->dev, GFP_KERNEL, "mca-pcm-%d", i);
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index dc088a1c6721..66149055aba9 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -54,6 +54,8 @@ struct tas2562_data {
int i_sense_slot;
int volume_lvl;
int model_id;
+ bool dac_powered;
+ bool unmuted;
};
enum tas256x_model {
@@ -63,39 +65,6 @@ enum tas256x_model {
TAS2110,
};
-static int tas2562_set_bias_level(struct snd_soc_component *component,
- enum snd_soc_bias_level level)
-{
- struct tas2562_data *tas2562 =
- snd_soc_component_get_drvdata(component);
-
- switch (level) {
- case SND_SOC_BIAS_ON:
- snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK, TAS2562_ACTIVE);
- break;
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_PREPARE:
- snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK, TAS2562_MUTE);
- break;
- case SND_SOC_BIAS_OFF:
- snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK, TAS2562_SHUTDOWN);
- break;
-
- default:
- dev_err(tas2562->dev,
- "wrong power level setting %d\n", level);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate)
{
int samp_rate;
@@ -384,30 +353,43 @@ static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static int tas2562_update_pwr_ctrl(struct tas2562_data *tas2562)
+{
+ struct snd_soc_component *component = tas2562->component;
+ unsigned int val;
+ int ret;
+
+ if (tas2562->dac_powered)
+ val = tas2562->unmuted ?
+ TAS2562_ACTIVE : TAS2562_MUTE;
+ else
+ val = TAS2562_SHUTDOWN;
+
+ ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
+ TAS2562_MODE_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int tas2562_mute(struct snd_soc_dai *dai, int mute, int direction)
{
- struct snd_soc_component *component = dai->component;
+ struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(dai->component);
- return snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK,
- mute ? TAS2562_MUTE : 0);
+ tas2562->unmuted = !mute;
+ return tas2562_update_pwr_ctrl(tas2562);
}
static int tas2562_codec_probe(struct snd_soc_component *component)
{
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
- int ret;
tas2562->component = component;
if (tas2562->sdz_gpio)
gpiod_set_value_cansleep(tas2562->sdz_gpio, 1);
- ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK, TAS2562_MUTE);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -461,30 +443,18 @@ static int tas2562_dac_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- ret = snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK,
- TAS2562_MUTE);
- if (ret)
- goto end;
+ tas2562->dac_powered = true;
+ ret = tas2562_update_pwr_ctrl(tas2562);
break;
case SND_SOC_DAPM_PRE_PMD:
- ret = snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK,
- TAS2562_SHUTDOWN);
- if (ret)
- goto end;
+ tas2562->dac_powered = false;
+ ret = tas2562_update_pwr_ctrl(tas2562);
break;
default:
dev_err(tas2562->dev, "Not supported evevt\n");
return -EINVAL;
}
-end:
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -579,7 +549,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2110 = {
.probe = tas2562_codec_probe,
.suspend = tas2562_suspend,
.resume = tas2562_resume,
- .set_bias_level = tas2562_set_bias_level,
.controls = tas2562_snd_controls,
.num_controls = ARRAY_SIZE(tas2562_snd_controls),
.dapm_widgets = tas2110_dapm_widgets,
@@ -618,7 +587,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2562 = {
.probe = tas2562_codec_probe,
.suspend = tas2562_suspend,
.resume = tas2562_resume,
- .set_bias_level = tas2562_set_bias_level,
.controls = tas2562_snd_controls,
.num_controls = ARRAY_SIZE(tas2562_snd_controls),
.dapm_widgets = tas2562_dapm_widgets,
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index cfaa45ede916..8a2e9771bb50 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -1602,7 +1602,9 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp)
if (list_empty(&dsp->buffer_list)) {
/* Fall back to legacy support */
ret = wm_adsp_buffer_parse_legacy(dsp);
- if (ret)
+ if (ret == -ENODEV)
+ adsp_info(dsp, "Legacy support not available\n");
+ else if (ret)
adsp_warn(dsp, "Failed to parse legacy: %d\n", ret);
}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index b5720e272c51..f8b62487babd 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -27,6 +27,28 @@
#include <sound/soc-link.h>
#include <sound/initval.h>
+#define soc_pcm_ret(rtd, ret) _soc_pcm_ret(rtd, __func__, ret)
+static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd,
+ const char *func, int ret)
+{
+ /* Positive, Zero values are not errors */
+ if (ret >= 0)
+ return ret;
+
+ /* Negative values might be errors */
+ switch (ret) {
+ case -EPROBE_DEFER:
+ case -ENOTSUPP:
+ break;
+ default:
+ dev_err(rtd->dev,
+ "ASoC: error at %s on %s: %d\n",
+ func, rtd->dai_link->name, ret);
+ }
+
+ return ret;
+}
+
static inline void snd_soc_dpcm_mutex_lock(struct snd_soc_pcm_runtime *rtd)
{
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -832,12 +854,10 @@ dynamic:
snd_soc_runtime_activate(rtd, substream->stream);
ret = 0;
err:
- if (ret < 0) {
+ if (ret < 0)
soc_pcm_clean(rtd, substream, 1);
- dev_err(rtd->dev, "%s() failed (%d)", __func__, ret);
- }
- return ret;
+ return soc_pcm_ret(rtd, ret);
}
/* PCM open ops for non-DPCM streams */
@@ -852,16 +872,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
return ret;
}
-static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
-{
- /*
- * Currently nothing to do for c2c links
- * Since c2c links are internal nodes in the DAPM graph and
- * don't interface with the outside world or application layer
- * we don't have to do any special handling on close.
- */
-}
-
/*
* Called by ALSA when the PCM substream is prepared, can set format, sample
* rate, etc. This function is non atomic and can be called multiple times,
@@ -901,10 +911,7 @@ static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd,
snd_soc_dai_digital_mute(dai, 0, substream->stream);
out:
- if (ret < 0)
- dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
-
- return ret;
+ return soc_pcm_ret(rtd, ret);
}
/* PCM prepare ops for non-DPCM streams */
@@ -1070,12 +1077,10 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_pcm_component_hw_params(substream, params);
out:
- if (ret < 0) {
+ if (ret < 0)
soc_pcm_hw_clean(rtd, substream, 1);
- dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
- }
- return ret;
+ return soc_pcm_ret(rtd, ret);
}
/* hw_params PCM ops for non-DPCM streams */
@@ -1453,6 +1458,10 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
struct snd_soc_dapm_widget *widget;
int i, new = 0, err;
+ /* don't connect if FE is not running */
+ if (!fe->dpcm[stream].runtime && !fe->fe_compr)
+ return new;
+
/* Create any new FE <--> BE connections */
for_each_dapm_widgets(list, i, widget) {
@@ -1477,10 +1486,6 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
continue;
}
- /* don't connect if FE is not running */
- if (!fe->dpcm[stream].runtime && !fe->fe_compr)
- continue;
-
/*
* Filter for systems with 'component_chaining' enabled.
* This helps to avoid unnecessary re-configuration of an
@@ -1637,10 +1642,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
unwind:
dpcm_be_dai_startup_rollback(fe, stream, dpcm);
- dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n",
- __func__, be->dai_link->name, err);
-
- return err;
+ return soc_pcm_ret(fe, err);
}
static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
@@ -1840,10 +1842,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
}
}
error:
- if (err < 0)
- dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, err);
-
- return err;
+ return soc_pcm_ret(fe, err);
}
static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
@@ -1880,10 +1879,7 @@ unwind:
be_err:
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
- if (ret < 0)
- dev_err(fe->dev, "%s() failed (%d)\n", __func__, ret);
-
- return ret;
+ return soc_pcm_ret(fe, ret);
}
static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
@@ -2082,10 +2078,7 @@ out:
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
snd_soc_dpcm_mutex_unlock(fe);
- if (ret < 0)
- dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, ret);
-
- return ret;
+ return soc_pcm_ret(fe, ret);
}
int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
@@ -2254,10 +2247,7 @@ next:
if (ret)
break;
}
- if (ret < 0)
- dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n",
- __func__, be->dai_link->name, ret);
- return ret;
+ return soc_pcm_ret(fe, ret);
}
EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
@@ -2428,10 +2418,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
}
- if (ret < 0)
- dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
-
- return ret;
+ return soc_pcm_ret(fe, ret);
}
static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
@@ -2468,10 +2455,7 @@ out:
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
snd_soc_dpcm_mutex_unlock(fe);
- if (ret < 0)
- dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
-
- return ret;
+ return soc_pcm_ret(fe, ret);
}
static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
@@ -2504,10 +2488,7 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
/* run the stream event for each BE */
dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
- if (err < 0)
- dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, err);
-
- return err;
+ return soc_pcm_ret(fe, err);
}
static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
@@ -2597,10 +2578,7 @@ disconnect:
dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
}
- if (ret < 0)
- dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret);
-
- return ret;
+ return soc_pcm_ret(fe, ret);
}
static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
@@ -2899,9 +2877,13 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
return ret;
/* DAPM dai link stream work */
- if (rtd->dai_link->params)
- rtd->close_delayed_work_func = codec2codec_close_delayed_work;
- else
+ /*
+ * Currently nothing to do for c2c links
+ * Since c2c links are internal nodes in the DAPM graph and
+ * don't interface with the outside world or application layer
+ * we don't have to do any special handling on close.
+ */
+ if (!rtd->dai_link->params)
rtd->close_delayed_work_func = snd_soc_close_delayed_work;
rtd->pcm = pcm;
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index c18e723435bd..ea9663d448eb 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -785,6 +785,28 @@ int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd)
}
EXPORT_SYMBOL(sof_dai_get_bclk);
+static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_sof_of_mach *mach = desc->of_machines;
+
+ if (!mach)
+ return NULL;
+
+ for (; mach->compatible; mach++) {
+ if (of_machine_is_compatible(mach->compatible)) {
+ sof_pdata->tplg_filename = mach->sof_tplg_filename;
+ if (mach->fw_filename)
+ sof_pdata->fw_filename = mach->fw_filename;
+
+ return mach;
+ }
+ }
+
+ return NULL;
+}
+
/*
* SOF Driver enumeration.
*/
@@ -795,6 +817,7 @@ int sof_machine_check(struct snd_sof_dev *sdev)
struct snd_soc_acpi_mach *mach;
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
+ const struct snd_sof_of_mach *of_mach;
/* find machine */
mach = snd_sof_machine_select(sdev);
@@ -804,6 +827,12 @@ int sof_machine_check(struct snd_sof_dev *sdev)
return 0;
}
+ of_mach = sof_of_machine_select(sdev);
+ if (of_mach) {
+ sof_pdata->of_machine = of_mach;
+ return 0;
+ }
+
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) {
dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
return -ENODEV;