The imx-spdif machine driver creates audio card to directly use an S/PDIF device. However, it doesn't support interacting with an ASRC. fsl-asoc-card already has the support to create audio card which can use the ASRC. Merge the S/PDIF support from imx-spdif into driver fsl-asoc-card to extend the support of S/PDIF audio card with the use of ASRC devices. fsl-asoc-card uses slightly different DT properties than imx-spdif: * the "spdif-controller" property from imx-spdif is named "audio-cpu" in fsl-asoc-card. * fsl-asoc-card uses codecs explicitly declared in DT with "audio-codec". With an SPDIF, codec drivers spdif_transmitter and spdif_receiver should be used. Driver imx-spdif used instead the dummy codec and a pair of boolean properties, "spdif-in" and "spdif-out". To keep backward compatibility, support for "spdif-controller", "spdif-in" and "spdif-out" is also added to fsl-asoc-card. However, it is recommended to use the new properties if possible. It is better to declare transmitter and/or receiver in DT than using the dummy codec. DTs using compatible "fsl,imx-audio-spdif" are still compatible, and fsl-asoc-card will behave the same as imx-spdif for these DTs. Signed-off-by: Elinor Montmasson <elinor.montmasson@xxxxxxxxxxxxxxxxxxxx> --- arch/arm/configs/imx_v6_v7_defconfig | 1 - arch/arm64/configs/defconfig | 1 - sound/soc/fsl/Kconfig | 10 +-- sound/soc/fsl/Makefile | 2 - sound/soc/fsl/fsl-asoc-card.c | 85 +++++++++++++++++++++- sound/soc/fsl/imx-spdif.c | 103 --------------------------- 6 files changed, 84 insertions(+), 118 deletions(-) delete mode 100644 sound/soc/fsl/imx-spdif.c diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index cf2480dce285..ac5ae621b2af 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -311,7 +311,6 @@ CONFIG_SND_IMX_SOC=y CONFIG_SND_SOC_EUKREA_TLV320=y CONFIG_SND_SOC_IMX_ES8328=y CONFIG_SND_SOC_IMX_SGTL5000=y -CONFIG_SND_SOC_IMX_SPDIF=y CONFIG_SND_SOC_FSL_ASOC_CARD=y CONFIG_SND_SOC_AC97_CODEC=y CONFIG_SND_SOC_CS42XX8_I2C=y diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 57a9abe78ee4..a6c9688fee0e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -940,7 +940,6 @@ CONFIG_SND_SOC_FSL_MICFIL=m CONFIG_SND_SOC_FSL_EASRC=m CONFIG_SND_IMX_SOC=m CONFIG_SND_SOC_IMX_SGTL5000=m -CONFIG_SND_SOC_IMX_SPDIF=m CONFIG_SND_SOC_FSL_ASOC_CARD=m CONFIG_SND_SOC_IMX_AUDMIX=m CONFIG_SND_SOC_MT8183=m diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 9a371d4496c2..e3b2bfb016c8 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -296,15 +296,6 @@ config SND_SOC_IMX_SGTL5000 SND_SOC_FSL_ASOC_CARD and SND_SOC_SGTL5000 to use the newer driver. -config SND_SOC_IMX_SPDIF - tristate "SoC Audio support for i.MX boards with S/PDIF" - select SND_SOC_IMX_PCM_DMA - select SND_SOC_FSL_SPDIF - help - SoC Audio support for i.MX boards with S/PDIF - Say Y if you want to add support for SoC audio on an i.MX board with - a S/DPDIF. - config SND_SOC_FSL_ASOC_CARD tristate "Generic ASoC Sound Card with ASRC support" depends on OF && I2C @@ -316,6 +307,7 @@ config SND_SOC_FSL_ASOC_CARD select SND_SOC_FSL_ESAI select SND_SOC_FSL_SAI select SND_SOC_FSL_SSI + select SND_SOC_FSL_SPDIF select SND_SOC_TLV320AIC31XX select SND_SOC_WM8994 select MFD_WM8994 diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 2fe78eed3a48..1ae181b24a88 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -65,7 +65,6 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_RPMSG) += imx-pcm-rpmsg.o snd-soc-eukrea-tlv320-y := eukrea-tlv320.o snd-soc-imx-es8328-y := imx-es8328.o snd-soc-imx-sgtl5000-y := imx-sgtl5000.o -snd-soc-imx-spdif-y := imx-spdif.o snd-soc-imx-audmix-y := imx-audmix.o snd-soc-imx-hdmi-y := imx-hdmi.o snd-soc-imx-rpmsg-y := imx-rpmsg.o @@ -74,7 +73,6 @@ snd-soc-imx-card-y := imx-card.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o -obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o obj-$(CONFIG_SND_SOC_IMX_RPMSG) += snd-soc-imx-rpmsg.o diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 87329731e02d..82df887b3af5 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -477,6 +477,75 @@ static int fsl_asoc_card_audmux_init(struct device_node *np, return 0; } +static int fsl_asoc_card_spdif_init(struct device_node *codec_np[], + struct device_node *cpu_np, + const char *codec_dai_name[], + struct fsl_asoc_card_priv *priv) +{ + struct device *dev = &priv->pdev->dev; + struct device_node *np = dev->of_node; + + if (!of_node_name_eq(cpu_np, "spdif")) { + dev_err(dev, "CPU phandle invalid, should be an SPDIF device\n"); + return -EINVAL; + } + + priv->dai_link[0].playback_only = true; + priv->dai_link[0].capture_only = true; + + for (int i = 0; i < 2; i++) { + if (!codec_np[i]) + break; + + if (of_device_is_compatible(codec_np[i], "linux,spdif-dit")) { + priv->dai_link[0].capture_only = false; + codec_dai_name[i] = "dit-hifi"; + } else if (of_device_is_compatible(codec_np[i], "linux,spdif-dir")) { + priv->dai_link[0].playback_only = false; + codec_dai_name[i] = "dir-hifi"; + } + } + + // Old SPDIF DT binding + if (!codec_np[0]) { + codec_dai_name[0] = snd_soc_dummy_dlc.dai_name; + if (of_property_read_bool(np, "spdif-out")) + priv->dai_link[0].capture_only = false; + if (of_property_read_bool(np, "spdif-in")) + priv->dai_link[0].playback_only = false; + } + + if (priv->dai_link[0].playback_only && priv->dai_link[0].capture_only) { + dev_err(dev, "no enabled S/PDIF DAI link\n"); + return -EINVAL; + } + + if (priv->dai_link[0].playback_only) { + priv->dai_link[1].dpcm_capture = false; + priv->dai_link[2].dpcm_capture = false; + priv->card.dapm_routes = audio_map_tx; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); + } else if (priv->dai_link[0].capture_only) { + priv->dai_link[1].dpcm_playback = false; + priv->dai_link[2].dpcm_playback = false; + priv->card.dapm_routes = audio_map_rx; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); + } + + // No DAPM routes with old bindings and dummy codec + if (!codec_np[0]) { + priv->card.dapm_routes = NULL; + priv->card.num_dapm_routes = 0; + } + + if (codec_np[0] && codec_np[1]) { + priv->dai_link[0].num_codecs = 2; + priv->dai_link[2].num_codecs = 2; + } + + return 0; +} + static int hp_jack_event(struct notifier_block *nb, unsigned long event, void *data) { @@ -582,9 +651,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->pdev = pdev; cpu_np = of_parse_phandle(np, "audio-cpu", 0); - /* Give a chance to old DT binding */ + /* Give a chance to old DT bindings */ if (!cpu_np) cpu_np = of_parse_phandle(np, "ssi-controller", 0); + if (!cpu_np) + cpu_np = of_parse_phandle(np, "spdif-controller", 0); if (!cpu_np) { dev_err(&pdev->dev, "CPU phandle missing or invalid\n"); ret = -EINVAL; @@ -748,6 +819,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->codec_priv[0].fll_id = WM8904_CLK_FLL; priv->codec_priv[0].pll_id = WM8904_FLL_MCLK; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; + } else if (of_device_is_compatible(np, "fsl,imx-audio-spdif")) { + ret = fsl_asoc_card_spdif_init(codec_np, cpu_np, codec_dai_name, priv); + if (ret) + goto asrc_fail; } else { dev_err(&pdev->dev, "unknown Device Tree compatible\n"); ret = -EINVAL; @@ -797,7 +872,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) of_node_put(bitclkprovider); of_node_put(frameprovider); - if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0]) { + if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0] + && codec_dai_name[0] != snd_soc_dummy_dlc.dai_name) { dev_dbg(&pdev->dev, "failed to find codec device\n"); ret = -EPROBE_DEFER; goto asrc_fail; @@ -862,6 +938,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) codec_comp->dai_name = codec_dai_name[codec_idx]; } + // Old SPDIF DT binding support + if (codec_dai_name[0] == snd_soc_dummy_dlc.dai_name) + priv->dai_link[0].codecs[0].name = snd_soc_dummy_dlc.name; + if (!fsl_asoc_card_is_ac97(priv)) { for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) { codec_comp->of_node = codec_np[codec_idx]; @@ -992,6 +1072,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-wm8958", }, { .compatible = "fsl,imx-audio-nau8822", }, { .compatible = "fsl,imx-audio-wm8904", }, + { .compatible = "fsl,imx-audio-spdif", }, {} }; MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids); diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c deleted file mode 100644 index 1e57939a7e29..000000000000 --- a/sound/soc/fsl/imx-spdif.c +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// Copyright (C) 2013 Freescale Semiconductor, Inc. - -#include <linux/module.h> -#include <linux/of_platform.h> -#include <sound/soc.h> - -struct imx_spdif_data { - struct snd_soc_dai_link dai; - struct snd_soc_card card; -}; - -static int imx_spdif_audio_probe(struct platform_device *pdev) -{ - struct device_node *spdif_np, *np = pdev->dev.of_node; - struct imx_spdif_data *data; - struct snd_soc_dai_link_component *comp; - int ret = 0; - - spdif_np = of_parse_phandle(np, "spdif-controller", 0); - if (!spdif_np) { - dev_err(&pdev->dev, "failed to find spdif-controller\n"); - ret = -EINVAL; - goto end; - } - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - comp = devm_kzalloc(&pdev->dev, sizeof(*comp), GFP_KERNEL); - if (!data || !comp) { - ret = -ENOMEM; - goto end; - } - - /* - * CPU == Platform - * platform is using soc-generic-dmaengine-pcm - */ - data->dai.cpus = - data->dai.platforms = comp; - data->dai.codecs = &snd_soc_dummy_dlc; - - data->dai.num_cpus = 1; - data->dai.num_codecs = 1; - data->dai.num_platforms = 1; - - data->dai.name = "S/PDIF PCM"; - data->dai.stream_name = "S/PDIF PCM"; - data->dai.cpus->of_node = spdif_np; - data->dai.playback_only = true; - data->dai.capture_only = true; - - if (of_property_read_bool(np, "spdif-out")) - data->dai.capture_only = false; - - if (of_property_read_bool(np, "spdif-in")) - data->dai.playback_only = false; - - if (data->dai.playback_only && data->dai.capture_only) { - dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n"); - goto end; - } - - data->card.dev = &pdev->dev; - data->card.dai_link = &data->dai; - data->card.num_links = 1; - data->card.owner = THIS_MODULE; - - ret = snd_soc_of_parse_card_name(&data->card, "model"); - if (ret) - goto end; - - ret = devm_snd_soc_register_card(&pdev->dev, &data->card); - if (ret) - dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); - -end: - of_node_put(spdif_np); - - return ret; -} - -static const struct of_device_id imx_spdif_dt_ids[] = { - { .compatible = "fsl,imx-audio-spdif", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids); - -static struct platform_driver imx_spdif_driver = { - .driver = { - .name = "imx-spdif", - .pm = &snd_soc_pm_ops, - .of_match_table = imx_spdif_dt_ids, - }, - .probe = imx_spdif_audio_probe, -}; - -module_platform_driver(imx_spdif_driver); - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:imx-spdif"); -- 2.34.1