diff options
-rw-r--r-- | sound/soc/apple/mca.c | 79 | ||||
-rw-r--r-- | sound/soc/codecs/tas2562.c | 90 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 4 | ||||
-rw-r--r-- | sound/soc/soc-pcm.c | 112 | ||||
-rw-r--r-- | sound/soc/sof/sof-audio.c | 29 |
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; |