diff options
Diffstat (limited to 'sound/soc/meson')
31 files changed, 410 insertions, 389 deletions
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index b93ea33739f2..d9a730994a2a 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "ASoC support for Amlogic platforms" +menu "Amlogic" depends on ARCH_MESON || (COMPILE_TEST && COMMON_CLK) config SND_MESON_AIU @@ -99,6 +99,7 @@ config SND_MESON_AXG_PDM config SND_MESON_CARD_UTILS tristate + select SND_DYNAMIC_MINORS config SND_MESON_CODEC_GLUE tristate diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index e446bc980481..24078e4396b0 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile @@ -1,30 +1,30 @@ # SPDX-License-Identifier: (GPL-2.0 OR MIT) -snd-soc-meson-aiu-objs := aiu.o -snd-soc-meson-aiu-objs += aiu-acodec-ctrl.o -snd-soc-meson-aiu-objs += aiu-codec-ctrl.o -snd-soc-meson-aiu-objs += aiu-encoder-i2s.o -snd-soc-meson-aiu-objs += aiu-encoder-spdif.o -snd-soc-meson-aiu-objs += aiu-fifo.o -snd-soc-meson-aiu-objs += aiu-fifo-i2s.o -snd-soc-meson-aiu-objs += aiu-fifo-spdif.o -snd-soc-meson-axg-fifo-objs := axg-fifo.o -snd-soc-meson-axg-frddr-objs := axg-frddr.o -snd-soc-meson-axg-toddr-objs := axg-toddr.o -snd-soc-meson-axg-tdm-formatter-objs := axg-tdm-formatter.o -snd-soc-meson-axg-tdm-interface-objs := axg-tdm-interface.o -snd-soc-meson-axg-tdmin-objs := axg-tdmin.o -snd-soc-meson-axg-tdmout-objs := axg-tdmout.o -snd-soc-meson-axg-sound-card-objs := axg-card.o -snd-soc-meson-axg-spdifin-objs := axg-spdifin.o -snd-soc-meson-axg-spdifout-objs := axg-spdifout.o -snd-soc-meson-axg-pdm-objs := axg-pdm.o -snd-soc-meson-card-utils-objs := meson-card-utils.o -snd-soc-meson-codec-glue-objs := meson-codec-glue.o -snd-soc-meson-gx-sound-card-objs := gx-card.o -snd-soc-meson-g12a-toacodec-objs := g12a-toacodec.o -snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o -snd-soc-meson-t9015-objs := t9015.o +snd-soc-meson-aiu-y := aiu.o +snd-soc-meson-aiu-y += aiu-acodec-ctrl.o +snd-soc-meson-aiu-y += aiu-codec-ctrl.o +snd-soc-meson-aiu-y += aiu-encoder-i2s.o +snd-soc-meson-aiu-y += aiu-encoder-spdif.o +snd-soc-meson-aiu-y += aiu-fifo.o +snd-soc-meson-aiu-y += aiu-fifo-i2s.o +snd-soc-meson-aiu-y += aiu-fifo-spdif.o +snd-soc-meson-axg-fifo-y := axg-fifo.o +snd-soc-meson-axg-frddr-y := axg-frddr.o +snd-soc-meson-axg-toddr-y := axg-toddr.o +snd-soc-meson-axg-tdm-formatter-y := axg-tdm-formatter.o +snd-soc-meson-axg-tdm-interface-y := axg-tdm-interface.o +snd-soc-meson-axg-tdmin-y := axg-tdmin.o +snd-soc-meson-axg-tdmout-y := axg-tdmout.o +snd-soc-meson-axg-sound-card-y := axg-card.o +snd-soc-meson-axg-spdifin-y := axg-spdifin.o +snd-soc-meson-axg-spdifout-y := axg-spdifout.o +snd-soc-meson-axg-pdm-y := axg-pdm.o +snd-soc-meson-card-utils-y := meson-card-utils.o +snd-soc-meson-codec-glue-y := meson-codec-glue.o +snd-soc-meson-gx-sound-card-y := gx-card.o +snd-soc-meson-g12a-toacodec-y := g12a-toacodec.o +snd-soc-meson-g12a-tohdmitx-y := g12a-tohdmitx.o +snd-soc-meson-t9015-y := t9015.o obj-$(CONFIG_SND_MESON_AIU) += snd-soc-meson-aiu.o obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c index d0f0ada5f4bc..483772ba69cd 100644 --- a/sound/soc/meson/aiu-acodec-ctrl.c +++ b/sound/soc/meson/aiu-acodec-ctrl.c @@ -31,10 +31,8 @@ static const char * const aiu_acodec_ctrl_mux_texts[] = { static int aiu_acodec_ctrl_mux_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_dapm_kcontrol_component(kcontrol); - struct snd_soc_dapm_context *dapm = - snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mux, changed; @@ -103,6 +101,8 @@ static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = aiu_acodec_ctrl_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -130,8 +130,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = { .name = "ACODEC CTRL " xname, \ .playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \ .ops = &aiu_acodec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_ACODEC_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c index 84c10956c241..396f815077e2 100644 --- a/sound/soc/meson/aiu-codec-ctrl.c +++ b/sound/soc/meson/aiu-codec-ctrl.c @@ -23,10 +23,8 @@ static const char * const aiu_codec_ctrl_mux_texts[] = { static int aiu_codec_ctrl_mux_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_dapm_kcontrol_component(kcontrol); - struct snd_soc_dapm_context *dapm = - snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mux, changed; @@ -75,6 +73,8 @@ static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = { }; static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -102,8 +102,6 @@ static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = { .name = "CODEC CTRL " xname, \ .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \ .ops = &aiu_codec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_CODEC_CTRL_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c index a0dd914c8ed1..3b4061508c18 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -236,8 +236,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) inv == SND_SOC_DAIFMT_IB_IF) val |= AIU_CLK_CTRL_LRCLK_INVERT; - if (inv == SND_SOC_DAIFMT_IB_NF || - inv == SND_SOC_DAIFMT_IB_IF) + /* + * The SoC changes data on the rising edge of the bitclock + * so an inversion of the bitclock is required in normal mode + */ + if (inv == SND_SOC_DAIFMT_NB_NF || + inv == SND_SOC_DAIFMT_NB_IF) val |= AIU_CLK_CTRL_AOCLK_INVERT; /* Signal skew */ @@ -328,4 +332,3 @@ const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = { .startup = aiu_encoder_i2s_startup, .shutdown = aiu_encoder_i2s_shutdown, }; - diff --git a/sound/soc/meson/aiu-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c index 57e6e7160d2f..eccbc16b293a 100644 --- a/sound/soc/meson/aiu-fifo-i2s.c +++ b/sound/soc/meson/aiu-fifo-i2s.c @@ -25,7 +25,7 @@ #define AIU_FIFO_I2S_BLOCK 256 -static struct snd_pcm_hardware fifo_i2s_pcm = { +static const struct snd_pcm_hardware fifo_i2s_pcm = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -88,7 +88,7 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; - struct aiu_fifo *fifo = dai->playback_dma_data; + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); unsigned int val; int ret; @@ -140,6 +140,9 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_i2s_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = aiu_fifo_i2s_trigger, .prepare = aiu_fifo_i2s_prepare, .hw_params = aiu_fifo_i2s_hw_params, @@ -158,7 +161,7 @@ int aiu_fifo_i2s_dai_probe(struct snd_soc_dai *dai) if (ret) return ret; - fifo = dai->playback_dma_data; + fifo = snd_soc_dai_dma_data_get_playback(dai); fifo->pcm = &fifo_i2s_pcm; fifo->mem_offset = AIU_MEM_I2S_START; diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c index 2fb30f89bf7a..e0e00ec026dc 100644 --- a/sound/soc/meson/aiu-fifo-spdif.c +++ b/sound/soc/meson/aiu-fifo-spdif.c @@ -27,7 +27,7 @@ #define AIU_FIFO_SPDIF_BLOCK 8 -static struct snd_pcm_hardware fifo_spdif_pcm = { +static const struct snd_pcm_hardware fifo_spdif_pcm = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -155,6 +155,9 @@ static int fifo_spdif_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_spdif_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = fifo_spdif_trigger, .prepare = fifo_spdif_prepare, .hw_params = fifo_spdif_hw_params, @@ -173,7 +176,7 @@ int aiu_fifo_spdif_dai_probe(struct snd_soc_dai *dai) if (ret) return ret; - fifo = dai->playback_dma_data; + fifo = snd_soc_dai_dma_data_get_playback(dai); fifo->pcm = &fifo_spdif_pcm; fifo->mem_offset = AIU_MEM_IEC958_START; diff --git a/sound/soc/meson/aiu-fifo.c b/sound/soc/meson/aiu-fifo.c index d67ff4cdabd5..b222bde1f61b 100644 --- a/sound/soc/meson/aiu-fifo.c +++ b/sound/soc/meson/aiu-fifo.c @@ -25,16 +25,16 @@ static struct snd_soc_dai *aiu_fifo_dai(struct snd_pcm_substream *ss) { - struct snd_soc_pcm_runtime *rtd = ss->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(ss); - return asoc_rtd_to_cpu(rtd, 0); + return snd_soc_rtd_to_cpu(rtd, 0); } snd_pcm_uframes_t aiu_fifo_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_dai *dai = aiu_fifo_dai(substream); - struct aiu_fifo *fifo = dai->playback_dma_data; + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int addr; @@ -46,7 +46,7 @@ snd_pcm_uframes_t aiu_fifo_pointer(struct snd_soc_component *component, static void aiu_fifo_enable(struct snd_soc_dai *dai, bool enable) { struct snd_soc_component *component = dai->component; - struct aiu_fifo *fifo = dai->playback_dma_data; + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); unsigned int en_mask = (AIU_MEM_CONTROL_FILL_EN | AIU_MEM_CONTROL_EMPTY_EN); @@ -80,7 +80,7 @@ int aiu_fifo_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; - struct aiu_fifo *fifo = dai->playback_dma_data; + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); snd_soc_component_update_bits(component, fifo->mem_offset + AIU_MEM_CONTROL, @@ -98,7 +98,7 @@ int aiu_fifo_hw_params(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_component *component = dai->component; - struct aiu_fifo *fifo = dai->playback_dma_data; + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); dma_addr_t end; /* Setup the fifo boundaries */ @@ -132,7 +132,7 @@ static irqreturn_t aiu_fifo_isr(int irq, void *dev_id) int aiu_fifo_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct aiu_fifo *fifo = dai->playback_dma_data; + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); int ret; snd_soc_set_runtime_hwparams(substream, fifo->pcm); @@ -168,7 +168,7 @@ int aiu_fifo_startup(struct snd_pcm_substream *substream, void aiu_fifo_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct aiu_fifo *fifo = dai->playback_dma_data; + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); free_irq(fifo->irq, substream); clk_disable_unprepare(fifo->pclk); @@ -178,7 +178,7 @@ int aiu_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_card *card = rtd->card->snd_card; - struct aiu_fifo *fifo = dai->playback_dma_data; + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); size_t size = fifo->pcm->buffer_bytes_max; int ret; @@ -200,15 +200,16 @@ int aiu_fifo_dai_probe(struct snd_soc_dai *dai) if (!fifo) return -ENOMEM; - dai->playback_dma_data = fifo; + snd_soc_dai_dma_data_set_playback(dai, fifo); return 0; } int aiu_fifo_dai_remove(struct snd_soc_dai *dai) { - kfree(dai->playback_dma_data); + struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai); + + kfree(fifo); return 0; } - diff --git a/sound/soc/meson/aiu-fifo.h b/sound/soc/meson/aiu-fifo.h index 42ce266677cc..b02cfcc4de7f 100644 --- a/sound/soc/meson/aiu-fifo.h +++ b/sound/soc/meson/aiu-fifo.h @@ -18,7 +18,7 @@ struct snd_pcm_hw_params; struct platform_device; struct aiu_fifo { - struct snd_pcm_hardware *pcm; + const struct snd_pcm_hardware *pcm; unsigned int mem_offset; unsigned int fifo_block; struct clk *pclk; @@ -38,8 +38,6 @@ int aiu_fifo_prepare(struct snd_pcm_substream *substream, int aiu_fifo_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai); -int aiu_fifo_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai); int aiu_fifo_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); void aiu_fifo_shutdown(struct snd_pcm_substream *substream, diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index 88e611e64d14..f2890111c1d2 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -121,9 +121,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_i2s_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_i2s_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_SPDIF_FIFO] = { .name = "SPDIF FIFO", @@ -137,9 +134,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_spdif_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_spdif_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_I2S_ENCODER] = { .name = "I2S Encoder", @@ -218,11 +212,12 @@ static const char * const aiu_spdif_ids[] = { static int aiu_clk_get(struct device *dev) { struct aiu *aiu = dev_get_drvdata(dev); + struct clk *pclk; int ret; - aiu->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(aiu->pclk)) - return dev_err_probe(dev, PTR_ERR(aiu->pclk), "Can't get the aiu pclk\n"); + pclk = devm_clk_get_enabled(dev, "pclk"); + if (IS_ERR(pclk)) + return dev_err_probe(dev, PTR_ERR(pclk), "Can't get the aiu pclk\n"); aiu->spdif_mclk = devm_clk_get(dev, "spdif_mclk"); if (IS_ERR(aiu->spdif_mclk)) @@ -239,18 +234,6 @@ static int aiu_clk_get(struct device *dev) if (ret) return dev_err_probe(dev, ret, "Can't get the spdif clocks\n"); - ret = clk_prepare_enable(aiu->pclk); - if (ret) { - dev_err(dev, "peripheral clock enable failed\n"); - return ret; - } - - ret = devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - aiu->pclk); - if (ret) - dev_err(dev, "failed to add reset action on pclk"); - return ret; } @@ -331,11 +314,9 @@ err: return ret; } -static int aiu_remove(struct platform_device *pdev) +static void aiu_remove(struct platform_device *pdev) { snd_soc_unregister_component(&pdev->dev); - - return 0; } static const struct aiu_platform_data aiu_gxbb_pdata = { diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h index 393b6c2307e4..0f94c8bf6081 100644 --- a/sound/soc/meson/aiu.h +++ b/sound/soc/meson/aiu.h @@ -33,7 +33,6 @@ struct aiu_platform_data { }; struct aiu { - struct clk *pclk; struct clk *spdif_mclk; struct aiu_interface i2s; struct aiu_interface spdif; diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 2b77010c2c5c..b4dca80e15e4 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -40,10 +40,10 @@ static const struct snd_soc_pcm_stream codec_params = { static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs); } @@ -56,7 +56,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd) { struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; struct snd_soc_dai *codec_dai; int ret, i; @@ -72,10 +72,10 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd) } } - ret = axg_tdm_set_tdm_slots(asoc_rtd_to_cpu(rtd, 0), be->tx_mask, be->rx_mask, + ret = axg_tdm_set_tdm_slots(snd_soc_rtd_to_cpu(rtd, 0), be->tx_mask, be->rx_mask, be->slots, be->slot_width); if (ret) { - dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n"); + dev_err(snd_soc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n"); return ret; } @@ -86,14 +86,14 @@ static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd) { struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; int ret; /* The loopback rx_mask is the pad tx_mask */ - ret = axg_tdm_set_tdm_slots(asoc_rtd_to_cpu(rtd, 0), NULL, be->tx_mask, + ret = axg_tdm_set_tdm_slots(snd_soc_rtd_to_cpu(rtd, 0), NULL, be->tx_mask, be->slots, be->slot_width); if (ret) { - dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n"); + dev_err(snd_soc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n"); return ret; } @@ -104,7 +104,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card, int *index) { struct meson_card *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link *pad = &card->dai_link[*index]; + struct snd_soc_dai_link *pad; struct snd_soc_dai_link *lb; struct snd_soc_dai_link_component *dlc; int ret; @@ -114,27 +114,26 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card, if (ret) return ret; + pad = &card->dai_link[*index]; lb = &card->dai_link[*index + 1]; lb->name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-lb", pad->name); if (!lb->name) return -ENOMEM; - dlc = devm_kzalloc(card->dev, 2 * sizeof(*dlc), GFP_KERNEL); + dlc = devm_kzalloc(card->dev, sizeof(*dlc), GFP_KERNEL); if (!dlc) return -ENOMEM; - lb->cpus = &dlc[0]; - lb->codecs = &dlc[1]; + lb->cpus = dlc; + lb->codecs = &snd_soc_dummy_dlc; lb->num_cpus = 1; lb->num_codecs = 1; lb->stream_name = lb->name; lb->cpus->of_node = pad->cpus->of_node; lb->cpus->dai_name = "TDM Loopback"; - lb->codecs->name = "snd-soc-dummy"; - lb->codecs->dai_name = "snd-soc-dummy-dai"; - lb->dpcm_capture = 1; + lb->capture_only = 1; lb->no_pcm = 1; lb->ops = &axg_card_tdm_be_ops; lb->init = axg_card_tdm_dai_lb_init; @@ -178,7 +177,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, /* Disable playback is the interface has no tx slots */ if (!tx) - link->dpcm_playback = 0; + link->capture_only = 1; for (i = 0, rx = 0; i < AXG_TDM_NUM_LANES; i++) { snprintf(propname, 32, "dai-tdm-slot-rx-mask-%d", i); @@ -188,9 +187,9 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, /* Disable capture is the interface has no rx slots */ if (!rx) - link->dpcm_capture = 0; + link->playback_only = 1; - /* ... but the interface should at least have one of them */ + /* ... but the interface should at least have one direction */ if (!tx && !rx) { dev_err(card->dev, "tdm link has no cpu slots\n"); return -EINVAL; @@ -223,7 +222,6 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card, struct axg_dai_link_tdm_data *be) { struct axg_dai_link_tdm_mask *codec_mask; - struct device_node *np; codec_mask = devm_kcalloc(card->dev, link->num_codecs, sizeof(*codec_mask), GFP_KERNEL); @@ -232,7 +230,7 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card, be->codec_masks = codec_mask; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", &codec_mask->rx); snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", @@ -277,7 +275,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card, return ret; /* Add loopback if the pad dai has playback */ - if (link->dpcm_playback) { + if (!link->capture_only) { ret = axg_card_add_tdm_loopback(card, index); if (ret) return ret; @@ -320,9 +318,9 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, dai_link->cpus = cpu; dai_link->num_cpus = 1; + dai_link->nonatomic = true; - ret = meson_card_parse_dai(card, np, &dai_link->cpus->of_node, - &dai_link->cpus->dai_name); + ret = meson_card_parse_dai(card, np, dai_link->cpus); if (ret) return ret; @@ -337,10 +335,10 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, return ret; if (axg_card_cpu_is_codec(dai_link->cpus->of_node)) { - dai_link->params = &codec_params; + dai_link->c2c_params = &codec_params; + dai_link->num_c2c_params = 1; } else { dai_link->no_pcm = 1; - snd_soc_dai_link_set_capabilities(dai_link); if (axg_card_cpu_is_tdm_iface(dai_link->cpus->of_node)) ret = axg_card_parse_tdm(card, np, index); } diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index bccfb770b339..75909196b769 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -3,6 +3,7 @@ // Copyright (c) 2018 BayLibre, SAS. // Author: Jerome Brunet <jbrunet@baylibre.com> +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/of_irq.h> #include <linux/of_platform.h> @@ -22,7 +23,7 @@ * These differences are handled in the respective DAI drivers */ -static struct snd_pcm_hardware axg_fifo_hw = { +static const struct snd_pcm_hardware axg_fifo_hw = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -31,7 +32,7 @@ static struct snd_pcm_hardware axg_fifo_hw = { SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = AXG_FIFO_FORMATS, .rate_min = 5512, - .rate_max = 192000, + .rate_max = 768000, .channels_min = 1, .channels_max = AXG_FIFO_CH_MAX, .period_bytes_min = AXG_FIFO_BURST, @@ -45,9 +46,9 @@ static struct snd_pcm_hardware axg_fifo_hw = { static struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss) { - struct snd_soc_pcm_runtime *rtd = ss->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(ss); - return asoc_rtd_to_cpu(rtd, 0); + return snd_soc_rtd_to_cpu(rtd, 0); } static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss) @@ -145,8 +146,8 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component, /* Enable irq if necessary */ irq_en = runtime->no_period_wakeup ? 0 : FIFO_INT_COUNT_REPEAT; regmap_update_bits(fifo->map, FIFO_CTRL0, - CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), - CTRL0_INT_EN(irq_en)); + CTRL0_INT_EN, + FIELD_PREP(CTRL0_INT_EN, irq_en)); return 0; } @@ -176,9 +177,9 @@ int axg_fifo_pcm_hw_free(struct snd_soc_component *component, { struct axg_fifo *fifo = axg_fifo_data(ss); - /* Disable the block count irq */ + /* Disable irqs */ regmap_update_bits(fifo->map, FIFO_CTRL0, - CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0); + CTRL0_INT_EN, 0); return 0; } @@ -187,13 +188,13 @@ EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free); static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask) { regmap_update_bits(fifo->map, FIFO_CTRL1, - CTRL1_INT_CLR(FIFO_INT_MASK), - CTRL1_INT_CLR(mask)); + CTRL1_INT_CLR, + FIELD_PREP(CTRL1_INT_CLR, mask)); /* Clear must also be cleared */ regmap_update_bits(fifo->map, FIFO_CTRL1, - CTRL1_INT_CLR(FIFO_INT_MASK), - 0); + CTRL1_INT_CLR, + FIELD_PREP(CTRL1_INT_CLR, 0)); } static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id) @@ -203,18 +204,19 @@ static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id) unsigned int status; regmap_read(fifo->map, FIFO_STATUS1, &status); + status = FIELD_GET(STATUS1_INT_STS, status); + axg_fifo_ack_irq(fifo, status); - status = STATUS1_INT_STS(status) & FIFO_INT_MASK; - if (status & FIFO_INT_COUNT_REPEAT) - snd_pcm_period_elapsed(ss); - else + if (status & ~FIFO_INT_COUNT_REPEAT) dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n", status); - /* Ack irqs */ - axg_fifo_ack_irq(fifo, status); + if (status & FIFO_INT_COUNT_REPEAT) { + snd_pcm_period_elapsed(ss); + return IRQ_HANDLED; + } - return IRQ_RETVAL(status); + return IRQ_NONE; } int axg_fifo_pcm_open(struct snd_soc_component *component, @@ -242,8 +244,10 @@ int axg_fifo_pcm_open(struct snd_soc_component *component, if (ret) return ret; - ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0, - dev_name(dev), ss); + /* Use the threaded irq handler only with non-atomic links */ + ret = request_threaded_irq(fifo->irq, NULL, + axg_fifo_pcm_irq_block, + IRQF_ONESHOT, dev_name(dev), ss); if (ret) return ret; @@ -254,15 +258,15 @@ int axg_fifo_pcm_open(struct snd_soc_component *component, /* Setup status2 so it reports the memory pointer */ regmap_update_bits(fifo->map, FIFO_CTRL1, - CTRL1_STATUS2_SEL_MASK, - CTRL1_STATUS2_SEL(STATUS2_SEL_DDR_READ)); + CTRL1_STATUS2_SEL, + FIELD_PREP(CTRL1_STATUS2_SEL, STATUS2_SEL_DDR_READ)); /* Make sure the dma is initially disabled */ __dma_enable(fifo, false); /* Disable irqs until params are ready */ regmap_update_bits(fifo->map, FIFO_CTRL0, - CTRL0_INT_EN(FIFO_INT_MASK), 0); + CTRL0_INT_EN, 0); /* Clear any pending interrupt */ axg_fifo_ack_irq(fifo, FIFO_INT_MASK); diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h index b63acd723c87..4c48c0a08481 100644 --- a/sound/soc/meson/axg-fifo.h +++ b/sound/soc/meson/axg-fifo.h @@ -21,8 +21,6 @@ struct snd_soc_dai_driver; struct snd_soc_pcm_runtime; #define AXG_FIFO_CH_MAX 128 -#define AXG_FIFO_RATES (SNDRV_PCM_RATE_5512 | \ - SNDRV_PCM_RATE_8000_192000) #define AXG_FIFO_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ @@ -42,21 +40,19 @@ struct snd_soc_pcm_runtime; #define FIFO_CTRL0 0x00 #define CTRL0_DMA_EN BIT(31) -#define CTRL0_INT_EN(x) ((x) << 16) +#define CTRL0_INT_EN GENMASK(23, 16) #define CTRL0_SEL_MASK GENMASK(2, 0) #define CTRL0_SEL_SHIFT 0 #define FIFO_CTRL1 0x04 -#define CTRL1_INT_CLR(x) ((x) << 0) -#define CTRL1_STATUS2_SEL_MASK GENMASK(11, 8) -#define CTRL1_STATUS2_SEL(x) ((x) << 8) +#define CTRL1_INT_CLR GENMASK(7, 0) +#define CTRL1_STATUS2_SEL GENMASK(11, 8) #define STATUS2_SEL_DDR_READ 0 -#define CTRL1_FRDDR_DEPTH_MASK GENMASK(31, 24) -#define CTRL1_FRDDR_DEPTH(x) ((x) << 24) +#define CTRL1_FRDDR_DEPTH GENMASK(31, 24) #define FIFO_START_ADDR 0x08 #define FIFO_FINISH_ADDR 0x0c #define FIFO_INT_ADDR 0x10 #define FIFO_STATUS1 0x14 -#define STATUS1_INT_STS(x) ((x) << 0) +#define STATUS1_INT_STS GENMASK(7, 0) #define FIFO_STATUS2 0x18 #define FIFO_INIT_ADDR 0x24 #define FIFO_CTRL2 0x28 diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 61f9d417fd60..e70c8c34c7db 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -7,6 +7,7 @@ * This driver implements the frontend playback DAI of AXG and G12A based SoCs */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/regmap.h> #include <linux/module.h> @@ -59,8 +60,8 @@ static int axg_frddr_dai_hw_params(struct snd_pcm_substream *substream, /* Trim the FIFO depth if the period is small to improve latency */ depth = min(period, fifo->depth); val = (depth / AXG_FIFO_BURST) - 1; - regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK, - CTRL1_FRDDR_DEPTH(val)); + regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH, + FIELD_PREP(CTRL1_FRDDR_DEPTH, val)); return 0; } @@ -100,6 +101,7 @@ static const struct snd_soc_dai_ops axg_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver axg_frddr_dai_drv = { @@ -108,11 +110,12 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = { .stream_name = "Playback", .channels_min = 1, .channels_max = AXG_FIFO_CH_MAX, - .rates = AXG_FIFO_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5515, + .rate_max = 768000, .formats = AXG_FIFO_FORMATS, }, .ops = &axg_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static const char * const axg_frddr_sel_texts[] = { @@ -175,6 +178,7 @@ static const struct snd_soc_dai_ops g12a_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver g12a_frddr_dai_drv = { @@ -183,11 +187,12 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = { .stream_name = "Playback", .channels_min = 1, .channels_max = AXG_FIFO_CH_MAX, - .rates = AXG_FIFO_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5515, + .rate_max = 768000, .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index ad43cb2a1e3f..d59050914d3c 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -294,13 +294,6 @@ static void axg_pdm_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(priv->dclk); } -static const struct snd_soc_dai_ops axg_pdm_dai_ops = { - .trigger = axg_pdm_trigger, - .hw_params = axg_pdm_hw_params, - .startup = axg_pdm_startup, - .shutdown = axg_pdm_shutdown, -}; - static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv) { const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic; @@ -440,6 +433,15 @@ static int axg_pdm_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops axg_pdm_dai_ops = { + .probe = axg_pdm_dai_probe, + .remove = axg_pdm_dai_remove, + .trigger = axg_pdm_trigger, + .hw_params = axg_pdm_hw_params, + .startup = axg_pdm_startup, + .shutdown = axg_pdm_shutdown, +}; + static struct snd_soc_dai_driver axg_pdm_dai_drv = { .name = "PDM", .capture = { @@ -453,8 +455,6 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = { SNDRV_PCM_FMTBIT_S32_LE), }, .ops = &axg_pdm_dai_ops, - .probe = axg_pdm_dai_probe, - .remove = axg_pdm_dai_remove, }; static const struct snd_soc_component_driver axg_pdm_component_drv = { diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index e2cc4c4be758..e721f579321e 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -112,34 +112,6 @@ static int axg_spdifin_prepare(struct snd_pcm_substream *substream, return 0; } -static int axg_spdifin_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); - int ret; - - ret = clk_prepare_enable(priv->refclk); - if (ret) { - dev_err(dai->dev, - "failed to enable spdifin reference clock\n"); - return ret; - } - - regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, - SPDIFIN_CTRL0_EN); - - return 0; -} - -static void axg_spdifin_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); - - regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0); - clk_disable_unprepare(priv->refclk); -} - static void axg_spdifin_write_mode_param(struct regmap *map, int mode, unsigned int val, unsigned int num_per_reg, @@ -207,9 +179,9 @@ static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai, SPDIFIN_CTRL1_BASE_TIMER, FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000)); - /* Threshold based on the minimum width between two edges */ + /* Threshold based on the maximum width between two edges */ regmap_update_bits(priv->map, SPDIFIN_CTRL0, - SPDIFIN_CTRL0_WIDTH_SEL, SPDIFIN_CTRL0_WIDTH_SEL); + SPDIFIN_CTRL0_WIDTH_SEL, 0); /* Calculate the last timer which has no threshold */ t_next = axg_spdifin_mode_timer(priv, i, rate); @@ -227,7 +199,7 @@ static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai, axg_spdifin_write_timer(priv->map, i, t); /* Set the threshold value */ - axg_spdifin_write_threshold(priv->map, i, t + t_next); + axg_spdifin_write_threshold(priv->map, i, 3 * (t + t_next)); /* Save the current timer for the next threshold calculation */ t_next = t; @@ -251,25 +223,40 @@ static int axg_spdifin_dai_probe(struct snd_soc_dai *dai) ret = axg_spdifin_sample_mode_config(dai, priv); if (ret) { dev_err(dai->dev, "mode configuration failed\n"); - clk_disable_unprepare(priv->pclk); - return ret; + goto pclk_err; } + ret = clk_prepare_enable(priv->refclk); + if (ret) { + dev_err(dai->dev, + "failed to enable spdifin reference clock\n"); + goto pclk_err; + } + + regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, + SPDIFIN_CTRL0_EN); + return 0; + +pclk_err: + clk_disable_unprepare(priv->pclk); + return ret; } static int axg_spdifin_dai_remove(struct snd_soc_dai *dai) { struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); + regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0); + clk_disable_unprepare(priv->refclk); clk_disable_unprepare(priv->pclk); return 0; } static const struct snd_soc_dai_ops axg_spdifin_ops = { + .probe = axg_spdifin_dai_probe, + .remove = axg_spdifin_dai_remove, .prepare = axg_spdifin_prepare, - .startup = axg_spdifin_startup, - .shutdown = axg_spdifin_shutdown, }; static int axg_spdifin_iec958_info(struct snd_kcontrol *kcontrol, @@ -429,8 +416,6 @@ axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv) drv->name = "SPDIF Input"; drv->ops = &axg_spdifin_ops; - drv->probe = axg_spdifin_dai_probe; - drv->remove = axg_spdifin_dai_remove; drv->capture.stream_name = "Capture"; drv->capture.channels_min = 1; drv->capture.channels_max = 2; diff --git a/sound/soc/meson/axg-spdifout.c b/sound/soc/meson/axg-spdifout.c index e8a12f15f3b4..84868fe574e0 100644 --- a/sound/soc/meson/axg-spdifout.c +++ b/sound/soc/meson/axg-spdifout.c @@ -352,8 +352,8 @@ static int axg_spdifout_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { struct axg_spdifout *priv = snd_soc_component_get_drvdata(component); - enum snd_soc_bias_level now = - snd_soc_component_get_bias_level(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + enum snd_soc_bias_level now = snd_soc_dapm_get_bias_level(dapm); int ret = 0; switch (level) { diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index 9883dc777f63..a6579efd3775 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -30,27 +30,32 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map, struct axg_tdm_stream *ts, unsigned int offset) { - unsigned int val, ch = ts->channels; - unsigned long mask; - int i, j; + unsigned int ch = ts->channels; + u32 val[AXG_TDM_NUM_LANES]; + int i, j, k; + + /* + * We need to mimick the slot distribution used by the HW to keep the + * channel placement consistent regardless of the number of channel + * in the stream. This is why the odd algorithm below is used. + */ + memset(val, 0, sizeof(*val) * AXG_TDM_NUM_LANES); /* * Distribute the channels of the stream over the available slots - * of each TDM lane + * of each TDM lane. We need to go over the 32 slots ... */ - for (i = 0; i < AXG_TDM_NUM_LANES; i++) { - val = 0; - mask = ts->mask[i]; - - for (j = find_first_bit(&mask, 32); - (j < 32) && ch; - j = find_next_bit(&mask, 32, j + 1)) { - val |= 1 << j; - ch -= 1; + for (i = 0; (i < 32) && ch; i += 2) { + /* ... of all the lanes ... */ + for (j = 0; j < AXG_TDM_NUM_LANES; j++) { + /* ... then distribute the channels in pairs */ + for (k = 0; k < 2; k++) { + if ((BIT(i + k) & ts->mask[j]) && ch) { + val[j] |= BIT(i + k); + ch -= 1; + } + } } - - regmap_write(map, offset, val); - offset += regmap_get_reg_stride(map); } /* @@ -63,6 +68,11 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map, return -EINVAL; } + for (i = 0; i < AXG_TDM_NUM_LANES; i++) { + regmap_write(map, offset, val[i]); + offset += regmap_get_reg_stride(map); + } + return 0; } EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks); @@ -382,6 +392,46 @@ void axg_tdm_stream_free(struct axg_tdm_stream *ts) } EXPORT_SYMBOL_GPL(axg_tdm_stream_free); +int axg_tdm_stream_set_cont_clocks(struct axg_tdm_stream *ts, + unsigned int fmt) +{ + int ret = 0; + + if (fmt & SND_SOC_DAIFMT_CONT) { + /* Clock are already enabled - skipping */ + if (ts->clk_enabled) + return 0; + + ret = clk_prepare_enable(ts->iface->mclk); + if (ret) + return ret; + + ret = clk_prepare_enable(ts->iface->sclk); + if (ret) + goto err_sclk; + + ret = clk_prepare_enable(ts->iface->lrclk); + if (ret) + goto err_lrclk; + + ts->clk_enabled = true; + return 0; + } + + /* Clocks are already disabled - skipping */ + if (!ts->clk_enabled) + return 0; + + clk_disable_unprepare(ts->iface->lrclk); +err_lrclk: + clk_disable_unprepare(ts->iface->sclk); +err_sclk: + clk_disable_unprepare(ts->iface->mclk); + ts->clk_enabled = false; + return ret; +} +EXPORT_SYMBOL_GPL(axg_tdm_stream_set_cont_clocks); + MODULE_DESCRIPTION("Amlogic AXG TDM formatter driver"); MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index c040c83637e0..d5287d78f53b 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -12,6 +12,9 @@ #include "axg-tdm.h" +/* Maximum bit clock frequency according the datasheets */ +#define MAX_SCLK 100000000 /* Hz */ + enum { TDM_IFACE_PAD, TDM_IFACE_LOOPBACK, @@ -37,10 +40,8 @@ int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask, unsigned int slot_width) { struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); - struct axg_tdm_stream *tx = (struct axg_tdm_stream *) - dai->playback_dma_data; - struct axg_tdm_stream *rx = (struct axg_tdm_stream *) - dai->capture_dma_data; + struct axg_tdm_stream *tx = snd_soc_dai_dma_data_get_playback(dai); + struct axg_tdm_stream *rx = snd_soc_dai_dma_data_get_capture(dai); unsigned int tx_slots, rx_slots; unsigned int fmt = 0; @@ -132,7 +133,7 @@ static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_BP_FC: case SND_SOC_DAIFMT_BC_FP: - dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n"); + dev_err(dai->dev, "only BP_FP and BC_FC are supported\n"); fallthrough; default: return -EINVAL; @@ -155,19 +156,27 @@ static int axg_tdm_iface_startup(struct snd_pcm_substream *substream, return -EINVAL; } - /* Apply component wide rate symmetry */ if (snd_soc_component_active(dai->component)) { + /* Apply component wide rate symmetry */ ret = snd_pcm_hw_constraint_single(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, iface->rate); - if (ret < 0) { - dev_err(dai->dev, - "can't set iface rate constraint\n"); - return ret; - } + + } else { + /* Limit rate according to the slot number and width */ + unsigned int max_rate = + MAX_SCLK / (iface->slots * iface->slot_width); + ret = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + 0, max_rate); } - return 0; + if (ret < 0) + dev_err(dai->dev, "can't set iface rate constraint\n"); + else + ret = 0; + + return ret; } static int axg_tdm_iface_set_stream(struct snd_pcm_substream *substream, @@ -266,8 +275,8 @@ static int axg_tdm_iface_set_sclk(struct snd_soc_dai *dai, srate = iface->slots * iface->slot_width * params_rate(params); if (!iface->mclk_rate) { - /* If no specific mclk is requested, default to bit clock * 4 */ - clk_set_rate(iface->mclk, 4 * srate); + /* If no specific mclk is requested, default to bit clock * 2 */ + clk_set_rate(iface->mclk, 2 * srate); } else { /* Check if we can actually get the bit clock from mclk */ if (iface->mclk_rate % srate) { @@ -300,6 +309,7 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); + struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); int ret; switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -337,7 +347,11 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream, return ret; } - return 0; + ret = axg_tdm_stream_set_cont_clocks(ts, iface->fmt); + if (ret) + dev_err(dai->dev, "failed to apply continuous clock setting\n"); + + return ret; } static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream, @@ -345,28 +359,44 @@ static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream, { struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); - /* Stop all attached formatters */ - axg_tdm_stream_stop(ts); - - return 0; + return axg_tdm_stream_set_cont_clocks(ts, 0); } -static int axg_tdm_iface_prepare(struct snd_pcm_substream *substream, +static int axg_tdm_iface_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) { - struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); + struct axg_tdm_stream *ts = + snd_soc_dai_get_dma_data(dai, substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + axg_tdm_stream_start(ts); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + axg_tdm_stream_stop(ts); + break; + default: + return -EINVAL; + } - /* Force all attached formatters to update */ - return axg_tdm_stream_reset(ts); + return 0; } static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai) { - if (dai->capture_dma_data) - axg_tdm_stream_free(dai->capture_dma_data); + int stream; + + for_each_pcm_streams(stream) { + struct axg_tdm_stream *ts = snd_soc_dai_dma_data_get(dai, stream); - if (dai->playback_dma_data) - axg_tdm_stream_free(dai->playback_dma_data); + if (ts) + axg_tdm_stream_free(ts); + } return 0; } @@ -374,31 +404,34 @@ static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai) static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai) { struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); + int stream; - if (dai->capture_widget) { - dai->capture_dma_data = axg_tdm_stream_alloc(iface); - if (!dai->capture_dma_data) - return -ENOMEM; - } + for_each_pcm_streams(stream) { + struct axg_tdm_stream *ts; + + if (!snd_soc_dai_get_widget(dai, stream)) + continue; - if (dai->playback_widget) { - dai->playback_dma_data = axg_tdm_stream_alloc(iface); - if (!dai->playback_dma_data) { + ts = axg_tdm_stream_alloc(iface); + if (!ts) { axg_tdm_iface_remove_dai(dai); return -ENOMEM; } + snd_soc_dai_dma_data_set(dai, stream, ts); } return 0; } static const struct snd_soc_dai_ops axg_tdm_iface_ops = { + .probe = axg_tdm_iface_probe_dai, + .remove = axg_tdm_iface_remove_dai, .set_sysclk = axg_tdm_iface_set_sysclk, .set_fmt = axg_tdm_iface_set_fmt, .startup = axg_tdm_iface_startup, .hw_params = axg_tdm_iface_hw_params, - .prepare = axg_tdm_iface_prepare, .hw_free = axg_tdm_iface_hw_free, + .trigger = axg_tdm_iface_trigger, }; /* TDM Backend DAIs */ @@ -409,20 +442,22 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { .stream_name = "Playback", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .id = TDM_IFACE_PAD, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, [TDM_IFACE_LOOPBACK] = { .name = "TDM Loopback", @@ -430,13 +465,13 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { .stream_name = "Loopback", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .id = TDM_IFACE_LOOPBACK, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, }; @@ -444,8 +479,8 @@ static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { struct axg_tdm_iface *iface = snd_soc_component_get_drvdata(component); - enum snd_soc_bias_level now = - snd_soc_component_get_bias_level(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + enum snd_soc_bias_level now = snd_soc_dapm_get_bias_level(dapm); int ret = 0; switch (level) { @@ -494,7 +529,6 @@ static int axg_tdm_iface_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct snd_soc_dai_driver *dai_drv; struct axg_tdm_iface *iface; - int ret, i; iface = devm_kzalloc(dev, sizeof(*iface), GFP_KERNEL); if (!iface) @@ -506,15 +540,11 @@ static int axg_tdm_iface_probe(struct platform_device *pdev) * We'll change the number of channel provided by DAI stream, so dpcm * channel merge can be done properly */ - dai_drv = devm_kcalloc(dev, ARRAY_SIZE(axg_tdm_iface_dai_drv), - sizeof(*dai_drv), GFP_KERNEL); + dai_drv = devm_kmemdup_array(dev, axg_tdm_iface_dai_drv, ARRAY_SIZE(axg_tdm_iface_dai_drv), + sizeof(axg_tdm_iface_dai_drv[0]), GFP_KERNEL); if (!dai_drv) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(axg_tdm_iface_dai_drv); i++) - memcpy(&dai_drv[i], &axg_tdm_iface_dai_drv[i], - sizeof(*dai_drv)); - /* Bit clock provided on the pad */ iface->sclk = devm_clk_get(dev, "sclk"); if (IS_ERR(iface->sclk)) @@ -531,14 +561,9 @@ static int axg_tdm_iface_probe(struct platform_device *pdev) * At this point, ignore the error if mclk is missing. We'll * throw an error if the cpu dai is master and mclk is missing */ - iface->mclk = devm_clk_get(dev, "mclk"); - if (IS_ERR(iface->mclk)) { - ret = PTR_ERR(iface->mclk); - if (ret == -ENOENT) - iface->mclk = NULL; - else - return dev_err_probe(dev, ret, "failed to get mclk\n"); - } + iface->mclk = devm_clk_get_optional(dev, "mclk"); + if (IS_ERR(iface->mclk)) + return dev_err_probe(dev, PTR_ERR(iface->mclk), "failed to get mclk\n"); return devm_snd_soc_register_component(dev, &axg_tdm_iface_component_drv, dai_drv, diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h index 5774ce0916d4..acfcd48f8a00 100644 --- a/sound/soc/meson/axg-tdm.h +++ b/sound/soc/meson/axg-tdm.h @@ -15,8 +15,6 @@ #define AXG_TDM_NUM_LANES 4 #define AXG_TDM_CHANNEL_MAX 128 -#define AXG_TDM_RATES (SNDRV_PCM_RATE_5512 | \ - SNDRV_PCM_RATE_8000_192000) #define AXG_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ @@ -58,12 +56,17 @@ struct axg_tdm_stream { unsigned int physical_width; u32 *mask; bool ready; + + /* For continuous clock tracking */ + bool clk_enabled; }; struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface); void axg_tdm_stream_free(struct axg_tdm_stream *ts); int axg_tdm_stream_start(struct axg_tdm_stream *ts); void axg_tdm_stream_stop(struct axg_tdm_stream *ts); +int axg_tdm_stream_set_cont_clocks(struct axg_tdm_stream *ts, + unsigned int fmt); static inline int axg_tdm_stream_reset(struct axg_tdm_stream *ts) { diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c index 49b613a1faf2..c8f6ea24ae78 100644 --- a/sound/soc/meson/axg-tdmin.c +++ b/sound/soc/meson/axg-tdmin.c @@ -83,7 +83,7 @@ axg_tdmin_get_tdm_stream(struct snd_soc_dapm_widget *w) if (!be) return NULL; - return be->capture_dma_data; + return snd_soc_dai_dma_data_get_capture(be); } static void axg_tdmin_enable(struct regmap *map) diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c index 22d519fc07b2..c4039e4f0847 100644 --- a/sound/soc/meson/axg-tdmout.c +++ b/sound/soc/meson/axg-tdmout.c @@ -81,7 +81,7 @@ axg_tdmout_get_tdm_stream(struct snd_soc_dapm_widget *w) if (!be) return NULL; - return be->playback_dma_data; + return snd_soc_dai_dma_data_get_playback(be); } static void axg_tdmout_enable(struct regmap *map) diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index e9208e74e965..03512da4092b 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -5,6 +5,7 @@ /* This driver implements the frontend capture DAI of AXG based SoCs */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/regmap.h> #include <linux/module.h> @@ -19,12 +20,9 @@ #define CTRL0_TODDR_EXT_SIGNED BIT(29) #define CTRL0_TODDR_PP_MODE BIT(28) #define CTRL0_TODDR_SYNC_CH BIT(27) -#define CTRL0_TODDR_TYPE_MASK GENMASK(15, 13) -#define CTRL0_TODDR_TYPE(x) ((x) << 13) -#define CTRL0_TODDR_MSB_POS_MASK GENMASK(12, 8) -#define CTRL0_TODDR_MSB_POS(x) ((x) << 8) -#define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3) -#define CTRL0_TODDR_LSB_POS(x) ((x) << 3) +#define CTRL0_TODDR_TYPE GENMASK(15, 13) +#define CTRL0_TODDR_MSB_POS GENMASK(12, 8) +#define CTRL0_TODDR_LSB_POS GENMASK(7, 3) #define CTRL1_TODDR_FORCE_FINISH BIT(25) #define CTRL1_SEL_SHIFT 28 @@ -76,12 +74,12 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream, width = params_width(params); regmap_update_bits(fifo->map, FIFO_CTRL0, - CTRL0_TODDR_TYPE_MASK | - CTRL0_TODDR_MSB_POS_MASK | - CTRL0_TODDR_LSB_POS_MASK, - CTRL0_TODDR_TYPE(type) | - CTRL0_TODDR_MSB_POS(TODDR_MSB_POS) | - CTRL0_TODDR_LSB_POS(TODDR_MSB_POS - (width - 1))); + CTRL0_TODDR_TYPE | + CTRL0_TODDR_MSB_POS | + CTRL0_TODDR_LSB_POS, + FIELD_PREP(CTRL0_TODDR_TYPE, type) | + FIELD_PREP(CTRL0_TODDR_MSB_POS, TODDR_MSB_POS) | + FIELD_PREP(CTRL0_TODDR_LSB_POS, TODDR_MSB_POS - (width - 1))); return 0; } @@ -122,6 +120,7 @@ static const struct snd_soc_dai_ops axg_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = axg_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver axg_toddr_dai_drv = { @@ -130,11 +129,12 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = { .stream_name = "Capture", .channels_min = 1, .channels_max = AXG_FIFO_CH_MAX, - .rates = AXG_FIFO_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5515, + .rate_max = 768000, .formats = AXG_FIFO_FORMATS, }, .ops = &axg_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const char * const axg_toddr_sel_texts[] = { @@ -217,6 +217,7 @@ static const struct snd_soc_dai_ops g12a_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = g12a_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver g12a_toddr_dai_drv = { @@ -225,11 +226,12 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = { .stream_name = "Capture", .channels_min = 1, .channels_max = AXG_FIFO_CH_MAX, - .rates = AXG_FIFO_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5515, + .rate_max = 768000, .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const struct snd_soc_component_driver g12a_toddr_component_drv = { diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index ddc667956cf5..a95375b53f0a 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -63,14 +63,15 @@ static const char * const g12a_toacodec_mux_texts[] = { static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol); struct g12a_toacodec *priv = snd_soc_component_get_drvdata(component); - struct snd_soc_dapm_context *dapm = - snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mux, reg; + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); regmap_field_read(priv->field_dat_sel, ®); @@ -101,7 +102,7 @@ static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol, snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); - return 0; + return 1; } static SOC_ENUM_SINGLE_DECL(g12a_toacodec_mux_enum, TOACODEC_CTRL0, @@ -162,6 +163,8 @@ static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops g12a_toacodec_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = g12a_toacodec_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -185,8 +188,6 @@ static const struct snd_soc_dai_ops g12a_toacodec_output_ops = { .id = (xid), \ .playback = TOACODEC_STREAM(xname, "Playback", 8), \ .ops = &g12a_toacodec_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOACODEC_OUTPUT(xname, xid) { \ diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 579a04ad4d19..d541ca4acfaf 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -38,13 +38,14 @@ static const char * const g12a_tohdmitx_i2s_mux_texts[] = { static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_dapm_kcontrol_component(kcontrol); - struct snd_soc_dapm_context *dapm = - snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mux, changed; + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); changed = snd_soc_component_test_bits(component, e->reg, CTRL0_I2S_DAT_SEL, @@ -86,13 +87,14 @@ static const char * const g12a_tohdmitx_spdif_mux_texts[] = { static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_dapm_kcontrol_component(kcontrol); - struct snd_soc_dapm_context *dapm = - snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mux, changed; + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); changed = snd_soc_component_test_bits(component, TOHDMITX_CTRL0, CTRL0_SPDIF_SEL, @@ -112,7 +114,7 @@ static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); - return 0; + return 1; } static SOC_ENUM_SINGLE_DECL(g12a_tohdmitx_spdif_mux_enum, TOHDMITX_CTRL0, @@ -140,6 +142,8 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { }; static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -172,8 +176,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { .id = (xid), \ .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \ .ops = &g12a_tohdmitx_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \ diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c index 5119434a81c4..b408cc2bbc91 100644 --- a/sound/soc/meson/gx-card.c +++ b/sound/soc/meson/gx-card.c @@ -29,10 +29,10 @@ static const struct snd_soc_pcm_stream codec_params = { static int gx_card_i2s_be_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct gx_dai_link_i2s_data *be = - (struct gx_dai_link_i2s_data *)priv->link_data[rtd->num]; + (struct gx_dai_link_i2s_data *)priv->link_data[rtd->id]; return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs); } @@ -90,8 +90,7 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np, dai_link->cpus = cpu; dai_link->num_cpus = 1; - ret = meson_card_parse_dai(card, np, &dai_link->cpus->of_node, - &dai_link->cpus->dai_name); + ret = meson_card_parse_dai(card, np, dai_link->cpus); if (ret) return ret; @@ -104,10 +103,10 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np, /* Or apply codec to codec params if necessary */ if (gx_card_cpu_identify(dai_link->cpus, "CODEC CTRL")) { - dai_link->params = &codec_params; + dai_link->c2c_params = &codec_params; + dai_link->num_c2c_params = 1; } else { dai_link->no_pcm = 1; - snd_soc_dai_link_set_capabilities(dai_link); /* Check if the cpu is the i2s encoder and parse i2s data */ if (gx_card_cpu_identify(dai_link->cpus, "I2S Encoder")) ret = gx_card_parse_i2s(card, np, index); diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 2d8d5717fd8b..cdb759b466ad 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -13,7 +13,7 @@ int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, unsigned int mclk_fs) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; unsigned int mclk; int ret, i; @@ -30,7 +30,7 @@ int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream, return ret; } - ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, + ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk, SND_SOC_CLOCK_OUT); if (ret && ret != -ENOTSUPP) return ret; @@ -74,23 +74,18 @@ EXPORT_SYMBOL_GPL(meson_card_reallocate_links); int meson_card_parse_dai(struct snd_soc_card *card, struct device_node *node, - struct device_node **dai_of_node, - const char **dai_name) + struct snd_soc_dai_link_component *dlc) { - struct of_phandle_args args; int ret; - if (!dai_name || !dai_of_node || !node) + if (!dlc || !node) return -EINVAL; - ret = of_parse_phandle_with_args(node, "sound-dai", - "#sound-dai-cells", 0, &args); + ret = snd_soc_of_get_dlc(node, NULL, dlc, 0); if (ret) return dev_err_probe(card->dev, ret, "can't parse dai\n"); - *dai_of_node = args.np; - - return snd_soc_get_dai_name(&args, dai_name); + return ret; } EXPORT_SYMBOL_GPL(meson_card_parse_dai); @@ -124,10 +119,10 @@ unsigned int meson_card_parse_daifmt(struct device_node *node, /* If no master is provided, default to cpu master */ if (!bitclkmaster || bitclkmaster == cpu_node) { daifmt |= (!framemaster || framemaster == cpu_node) ? - SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM; + SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBC_CFP; } else { daifmt |= (!framemaster || framemaster == cpu_node) ? - SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFC : SND_SOC_DAIFMT_CBP_CFP; } of_node_put(bitclkmaster); @@ -142,7 +137,6 @@ int meson_card_set_be_link(struct snd_soc_card *card, struct device_node *node) { struct snd_soc_dai_link_component *codec; - struct device_node *np; int ret, num_codecs; num_codecs = of_get_child_count(node); @@ -159,20 +153,17 @@ int meson_card_set_be_link(struct snd_soc_card *card, link->codecs = codec; link->num_codecs = num_codecs; - for_each_child_of_node(node, np) { - ret = meson_card_parse_dai(card, np, &codec->of_node, - &codec->dai_name); - if (ret) { - of_node_put(np); + for_each_child_of_node_scoped(node, np) { + ret = meson_card_parse_dai(card, np, codec); + if (ret) return ret; - } codec++; } ret = meson_card_set_link_name(card, link, node, "be"); if (ret) - dev_err(card->dev, "error setting %pOFn link name\n", np); + dev_err(card->dev, "error setting %pOFn link name\n", node); return ret; } @@ -183,26 +174,18 @@ int meson_card_set_fe_link(struct snd_soc_card *card, struct device_node *node, bool is_playback) { - struct snd_soc_dai_link_component *codec; - - codec = devm_kzalloc(card->dev, sizeof(*codec), GFP_KERNEL); - if (!codec) - return -ENOMEM; - - link->codecs = codec; + link->codecs = &snd_soc_dummy_dlc; link->num_codecs = 1; link->dynamic = 1; link->dpcm_merged_format = 1; link->dpcm_merged_chan = 1; link->dpcm_merged_rate = 1; - link->codecs->dai_name = "snd-soc-dummy-dai"; - link->codecs->name = "snd-soc-dummy"; if (is_playback) - link->dpcm_playback = 1; + link->playback_only = 1; else - link->dpcm_capture = 1; + link->capture_only = 1; return meson_card_set_link_name(card, link, node, "fe"); } @@ -212,7 +195,6 @@ static int meson_card_add_links(struct snd_soc_card *card) { struct meson_card *priv = snd_soc_card_get_drvdata(card); struct device_node *node = card->dev->of_node; - struct device_node *np; int num, i, ret; num = of_get_child_count(node); @@ -226,12 +208,10 @@ static int meson_card_add_links(struct snd_soc_card *card) return ret; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { ret = priv->match_data->add_link(card, np, &i); - if (ret) { - of_node_put(np); + if (ret) return ret; - } i++; } @@ -245,7 +225,7 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card, const char *p)) { /* If property is not provided, don't fail ... */ - if (!of_property_read_bool(card->dev->of_node, propname)) + if (!of_property_present(card->dev->of_node, propname)) return 0; /* ... but do fail if it is provided and the parsing fails */ @@ -341,13 +321,11 @@ out_err: } EXPORT_SYMBOL_GPL(meson_card_probe); -int meson_card_remove(struct platform_device *pdev) +void meson_card_remove(struct platform_device *pdev) { struct meson_card *priv = platform_get_drvdata(pdev); meson_card_clean_references(priv); - - return 0; } EXPORT_SYMBOL_GPL(meson_card_remove); diff --git a/sound/soc/meson/meson-card.h b/sound/soc/meson/meson-card.h index 74314071c80d..a0d693e4f460 100644 --- a/sound/soc/meson/meson-card.h +++ b/sound/soc/meson/meson-card.h @@ -39,8 +39,7 @@ int meson_card_reallocate_links(struct snd_soc_card *card, unsigned int num_links); int meson_card_parse_dai(struct snd_soc_card *card, struct device_node *node, - struct device_node **dai_of_node, - const char **dai_name); + struct snd_soc_dai_link_component *dlc); int meson_card_set_be_link(struct snd_soc_card *card, struct snd_soc_dai_link *link, struct device_node *node); @@ -50,6 +49,6 @@ int meson_card_set_fe_link(struct snd_soc_card *card, bool is_playback); int meson_card_probe(struct platform_device *pdev); -int meson_card_remove(struct platform_device *pdev); +void meson_card_remove(struct platform_device *pdev); #endif /* _MESON_SND_CARD_H */ diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c index 80c5ed196961..f8c5643f3cfe 100644 --- a/sound/soc/meson/meson-codec-glue.c +++ b/sound/soc/meson/meson-codec-glue.c @@ -39,13 +39,13 @@ meson_codec_glue_get_input(struct snd_soc_dapm_widget *w) static void meson_codec_glue_input_set_data(struct snd_soc_dai *dai, struct meson_codec_glue_input *data) { - dai->playback_dma_data = data; + snd_soc_dai_dma_data_set_playback(dai, data); } struct meson_codec_glue_input * meson_codec_glue_input_get_data(struct snd_soc_dai *dai) { - return dai->playback_dma_data; + return snd_soc_dai_dma_data_get_playback(dai); } EXPORT_SYMBOL_GPL(meson_codec_glue_input_get_data); @@ -98,20 +98,21 @@ EXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt); int meson_codec_glue_output_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct meson_codec_glue_input *in_data = - meson_codec_glue_output_get_input_data(dai->capture_widget); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget_capture(dai); + struct meson_codec_glue_input *in_data = meson_codec_glue_output_get_input_data(w); if (!in_data) return -ENODEV; - if (WARN_ON(!rtd->dai_link->params)) { + if (WARN_ON(!rtd->dai_link->c2c_params)) { dev_warn(dai->dev, "codec2codec link expected\n"); return -EINVAL; } /* Replace link params with the input params */ - rtd->dai_link->params = &in_data->params; + rtd->dai_link->c2c_params = &in_data->params; + rtd->dai_link->num_c2c_params = 1; return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt); } diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c index 9c6b4dac6893..da1a93946d67 100644 --- a/sound/soc/meson/t9015.c +++ b/sound/soc/meson/t9015.c @@ -48,7 +48,6 @@ #define POWER_CFG 0x10 struct t9015 { - struct clk *pclk; struct regulator *avdd; }; @@ -58,11 +57,11 @@ static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int val; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: val = I2S_MODE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: val = 0; break; @@ -178,8 +177,8 @@ static int t9015_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { struct t9015 *priv = snd_soc_component_get_drvdata(component); - enum snd_soc_bias_level now = - snd_soc_component_get_bias_level(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + enum snd_soc_bias_level now = snd_soc_dapm_get_bias_level(dapm); int ret; switch (level) { @@ -249,6 +248,7 @@ static int t9015_probe(struct platform_device *pdev) struct t9015 *priv; void __iomem *regs; struct regmap *regmap; + struct clk *pclk; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -256,26 +256,14 @@ static int t9015_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, priv); - priv->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(priv->pclk)) - return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get core clock\n"); + pclk = devm_clk_get_enabled(dev, "pclk"); + if (IS_ERR(pclk)) + return dev_err_probe(dev, PTR_ERR(pclk), "failed to get core clock\n"); priv->avdd = devm_regulator_get(dev, "AVDD"); if (IS_ERR(priv->avdd)) return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n"); - ret = clk_prepare_enable(priv->pclk); - if (ret) { - dev_err(dev, "core clock enable failed\n"); - return ret; - } - - ret = devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - priv->pclk); - if (ret) - return ret; - ret = device_reset(dev); if (ret) { dev_err(dev, "reset failed\n"); |
