summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/fsl-asoc-card.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2024-07-15 16:31:00 +0200
committerTakashi Iwai <tiwai@suse.de>2024-07-15 16:31:00 +0200
commit97b10a77b150df664bb521ae217dd6bceb40d5d3 (patch)
tree9f14e5d6e0a9e048cfef95f41678569dd994aba6 /sound/soc/fsl/fsl-asoc-card.c
parente54dc34318f62bdeea7edefed386d47fae155618 (diff)
parentc51cba4755609ad97ba97713210c16f043c73224 (diff)
downloadlwn-97b10a77b150df664bb521ae217dd6bceb40d5d3.tar.gz
lwn-97b10a77b150df664bb521ae217dd6bceb40d5d3.zip
Merge tag 'asoc-v6.11' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for for v6.11 There are a lot of changes in here, though the big bulk of things is cleanups and simplifications of various kinds which are internally rather than externally visible. A good chunk of those are DT schema conversions, but there's also a lot of changes in the code. Highlights: - Syncing of features between simple-audio-card and the two audio-graph cards so there is no reason to stick with an older driver. - Support for specifying the order of operations for components within cards to allow quirking for unusual systems. - New support for Asahi Kasei AK4619, Cirrus Logic CS530x, Everest Semiconductors ES8311, NXP i.MX95 and LPC32xx, Qualcomm LPASS v2.5 and WCD937x, Realtek RT1318 and RT1320 and Texas Instruments PCM5242.
Diffstat (limited to 'sound/soc/fsl/fsl-asoc-card.c')
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c383
1 files changed, 256 insertions, 127 deletions
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index eb67689dcd6e..82df887b3af5 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -99,7 +99,7 @@ struct fsl_asoc_card_priv {
struct simple_util_jack hp_jack;
struct simple_util_jack mic_jack;
struct platform_device *pdev;
- struct codec_priv codec_priv;
+ struct codec_priv codec_priv[2];
struct cpu_priv cpu_priv;
struct snd_soc_card card;
u8 streams;
@@ -172,10 +172,12 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- struct codec_priv *codec_priv = &priv->codec_priv;
+ struct codec_priv *codec_priv;
+ struct snd_soc_dai *codec_dai;
struct cpu_priv *cpu_priv = &priv->cpu_priv;
struct device *dev = rtd->card->dev;
unsigned int pll_out;
+ int codec_idx;
int ret;
priv->sample_rate = params_rate(params);
@@ -208,28 +210,32 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
}
/* Specific configuration for PLL */
- if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
- if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
- pll_out = priv->sample_rate * 384;
- else
- pll_out = priv->sample_rate * 256;
+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+ codec_priv = &priv->codec_priv[codec_idx];
- ret = snd_soc_dai_set_pll(snd_soc_rtd_to_codec(rtd, 0),
- codec_priv->pll_id,
- codec_priv->mclk_id,
- codec_priv->mclk_freq, pll_out);
- if (ret) {
- dev_err(dev, "failed to start FLL: %d\n", ret);
- goto fail;
- }
+ if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
+ if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
+ pll_out = priv->sample_rate * 384;
+ else
+ pll_out = priv->sample_rate * 256;
- ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0),
- codec_priv->fll_id,
- pll_out, SND_SOC_CLOCK_IN);
+ ret = snd_soc_dai_set_pll(codec_dai,
+ codec_priv->pll_id,
+ codec_priv->mclk_id,
+ codec_priv->mclk_freq, pll_out);
+ if (ret) {
+ dev_err(dev, "failed to start FLL: %d\n", ret);
+ goto fail;
+ }
- if (ret && ret != -ENOTSUPP) {
- dev_err(dev, "failed to set SYSCLK: %d\n", ret);
- goto fail;
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ codec_priv->fll_id,
+ pll_out, SND_SOC_CLOCK_IN);
+
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set SYSCLK: %d\n", ret);
+ goto fail;
+ }
}
}
@@ -244,28 +250,34 @@ static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct codec_priv *codec_priv = &priv->codec_priv;
+ struct codec_priv *codec_priv;
+ struct snd_soc_dai *codec_dai;
struct device *dev = rtd->card->dev;
+ int codec_idx;
int ret;
priv->streams &= ~BIT(substream->stream);
- if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
- /* Force freq to be free_freq to avoid error message in codec */
- ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0),
- codec_priv->mclk_id,
- codec_priv->free_freq,
- SND_SOC_CLOCK_IN);
- if (ret) {
- dev_err(dev, "failed to switch away from FLL: %d\n", ret);
- return ret;
- }
+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+ codec_priv = &priv->codec_priv[codec_idx];
- ret = snd_soc_dai_set_pll(snd_soc_rtd_to_codec(rtd, 0),
- codec_priv->pll_id, 0, 0, 0);
- if (ret && ret != -ENOTSUPP) {
- dev_err(dev, "failed to stop FLL: %d\n", ret);
- return ret;
+ if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
+ /* Force freq to be free_freq to avoid error message in codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ codec_priv->mclk_id,
+ codec_priv->free_freq,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(dev, "failed to switch away from FLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai,
+ codec_priv->pll_id, 0, 0, 0);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to stop FLL: %d\n", ret);
+ return ret;
+ }
}
}
@@ -296,7 +308,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
SND_SOC_DAILINK_DEFS(hifi,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY(), COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hifi_fe,
@@ -306,7 +318,7 @@ SND_SOC_DAILINK_DEFS(hifi_fe,
SND_SOC_DAILINK_DEFS(hifi_be,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
+ DAILINK_COMP_ARRAY(COMP_EMPTY(), COMP_EMPTY()));
static const struct snd_soc_dai_link fsl_asoc_card_dai[] = {
/* Default ASoC DAI Link*/
@@ -465,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)
{
@@ -504,9 +585,10 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_pcm_runtime *rtd = list_first_entry(
&card->rtd_list, struct snd_soc_pcm_runtime, list);
- struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
- struct codec_priv *codec_priv = &priv->codec_priv;
+ struct snd_soc_dai *codec_dai;
+ struct codec_priv *codec_priv;
struct device *dev = card->dev;
+ int codec_idx;
int ret;
if (fsl_asoc_card_is_ac97(priv)) {
@@ -526,32 +608,39 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
return 0;
}
- ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
- codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
- if (ret && ret != -ENOTSUPP) {
- dev_err(dev, "failed to set sysclk in %s\n", __func__);
- return ret;
- }
+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+ codec_priv = &priv->codec_priv[codec_idx];
- if (!IS_ERR_OR_NULL(codec_priv->mclk))
- clk_prepare_enable(codec_priv->mclk);
+ ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
+ codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set sysclk in %s\n", __func__);
+ return ret;
+ }
+
+ if (!IS_ERR_OR_NULL(codec_priv->mclk))
+ clk_prepare_enable(codec_priv->mclk);
+ }
return 0;
}
static int fsl_asoc_card_probe(struct platform_device *pdev)
{
- struct device_node *cpu_np, *codec_np, *asrc_np;
+ struct device_node *cpu_np, *asrc_np;
+ struct snd_soc_dai_link_component *codec_comp;
+ struct device_node *codec_np[2];
struct device_node *np = pdev->dev.of_node;
struct platform_device *asrc_pdev = NULL;
struct device_node *bitclkprovider = NULL;
struct device_node *frameprovider = NULL;
struct platform_device *cpu_pdev;
struct fsl_asoc_card_priv *priv;
- struct device *codec_dev = NULL;
- const char *codec_dai_name;
- const char *codec_dev_name;
+ struct device *codec_dev[2] = { NULL, NULL };
+ const char *codec_dai_name[2];
+ const char *codec_dev_name[2];
u32 asrc_fmt = 0;
+ int codec_idx;
u32 width;
int ret;
@@ -562,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;
@@ -578,21 +669,25 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto fail;
}
- codec_np = of_parse_phandle(np, "audio-codec", 0);
- if (codec_np) {
- struct platform_device *codec_pdev;
- struct i2c_client *codec_i2c;
+ codec_np[0] = of_parse_phandle(np, "audio-codec", 0);
+ codec_np[1] = of_parse_phandle(np, "audio-codec", 1);
- codec_i2c = of_find_i2c_device_by_node(codec_np);
- if (codec_i2c) {
- codec_dev = &codec_i2c->dev;
- codec_dev_name = codec_i2c->name;
- }
- if (!codec_dev) {
- codec_pdev = of_find_device_by_node(codec_np);
- if (codec_pdev) {
- codec_dev = &codec_pdev->dev;
- codec_dev_name = codec_pdev->name;
+ for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+ if (codec_np[codec_idx]) {
+ struct platform_device *codec_pdev;
+ struct i2c_client *codec_i2c;
+
+ codec_i2c = of_find_i2c_device_by_node(codec_np[codec_idx]);
+ if (codec_i2c) {
+ codec_dev[codec_idx] = &codec_i2c->dev;
+ codec_dev_name[codec_idx] = codec_i2c->name;
+ }
+ if (!codec_dev[codec_idx]) {
+ codec_pdev = of_find_device_by_node(codec_np[codec_idx]);
+ if (codec_pdev) {
+ codec_dev[codec_idx] = &codec_pdev->dev;
+ codec_dev_name[codec_idx] = codec_pdev->name;
+ }
}
}
}
@@ -602,12 +697,14 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
asrc_pdev = of_find_device_by_node(asrc_np);
/* Get the MCLK rate only, and leave it controlled by CODEC drivers */
- if (codec_dev) {
- struct clk *codec_clk = clk_get(codec_dev, NULL);
+ for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+ if (codec_dev[codec_idx]) {
+ struct clk *codec_clk = clk_get(codec_dev[codec_idx], NULL);
- if (!IS_ERR(codec_clk)) {
- priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
- clk_put(codec_clk);
+ if (!IS_ERR(codec_clk)) {
+ priv->codec_priv[codec_idx].mclk_freq = clk_get_rate(codec_clk);
+ clk_put(codec_clk);
+ }
}
}
@@ -620,36 +717,40 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
memcpy(priv->dai_link, fsl_asoc_card_dai,
sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
+ priv->dai_link[0].num_codecs = 1;
+ priv->dai_link[2].num_codecs = 1;
priv->card.dapm_routes = audio_map;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
priv->card.driver_name = DRIVER_NAME;
- priv->codec_priv.fll_id = -1;
- priv->codec_priv.pll_id = -1;
+ for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+ priv->codec_priv[codec_idx].fll_id = -1;
+ priv->codec_priv[codec_idx].pll_id = -1;
+ }
/* Diversify the card configurations */
if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
- codec_dai_name = "cs42888";
- priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
- priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
+ codec_dai_name[0] = "cs42888";
+ priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv[0].mclk_freq;
+ priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv[0].mclk_freq;
priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
priv->cpu_priv.slot_width = 32;
priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
} else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) {
- codec_dai_name = "cs4271-hifi";
- priv->codec_priv.mclk_id = CS427x_SYSCLK_MCLK;
+ codec_dai_name[0] = "cs4271-hifi";
+ priv->codec_priv[0].mclk_id = CS427x_SYSCLK_MCLK;
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
- codec_dai_name = "sgtl5000";
- priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
+ codec_dai_name[0] = "sgtl5000";
+ priv->codec_priv[0].mclk_id = SGTL5000_SYSCLK;
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) {
- codec_dai_name = "tlv320aic32x4-hifi";
+ codec_dai_name[0] = "tlv320aic32x4-hifi";
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) {
- codec_dai_name = "tlv320dac31xx-hifi";
+ codec_dai_name[0] = "tlv320dac31xx-hifi";
priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
priv->dai_link[1].dpcm_capture = 0;
priv->dai_link[2].dpcm_capture = 0;
@@ -658,23 +759,23 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->card.dapm_routes = audio_map_tx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
- codec_dai_name = "wm8962";
- priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
- priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
- priv->codec_priv.pll_id = WM8962_FLL;
+ codec_dai_name[0] = "wm8962";
+ priv->codec_priv[0].mclk_id = WM8962_SYSCLK_MCLK;
+ priv->codec_priv[0].fll_id = WM8962_SYSCLK_FLL;
+ priv->codec_priv[0].pll_id = WM8962_FLL;
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) {
- codec_dai_name = "wm8960-hifi";
- priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
- priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
+ codec_dai_name[0] = "wm8960-hifi";
+ priv->codec_priv[0].fll_id = WM8960_SYSCLK_AUTO;
+ priv->codec_priv[0].pll_id = WM8960_SYSCLK_AUTO;
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
- codec_dai_name = "ac97-hifi";
+ codec_dai_name[0] = "ac97-hifi";
priv->dai_fmt = SND_SOC_DAIFMT_AC97;
priv->card.dapm_routes = audio_map_ac97;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_ac97);
} else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) {
- codec_dai_name = "fsl-mqs-dai";
+ codec_dai_name[0] = "fsl-mqs-dai";
priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J |
SND_SOC_DAIFMT_CBC_CFC |
SND_SOC_DAIFMT_NB_NF;
@@ -683,7 +784,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->card.dapm_routes = audio_map_tx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) {
- codec_dai_name = "wm8524-hifi";
+ codec_dai_name[0] = "wm8524-hifi";
priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
priv->dai_link[1].dpcm_capture = 0;
priv->dai_link[2].dpcm_capture = 0;
@@ -691,33 +792,37 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->card.dapm_routes = audio_map_tx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
} else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) {
- codec_dai_name = "si476x-codec";
+ codec_dai_name[0] = "si476x-codec";
priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
priv->card.dapm_routes = audio_map_rx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) {
- codec_dai_name = "wm8994-aif1";
+ codec_dai_name[0] = "wm8994-aif1";
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- priv->codec_priv.mclk_id = WM8994_FLL_SRC_MCLK1;
- priv->codec_priv.fll_id = WM8994_SYSCLK_FLL1;
- priv->codec_priv.pll_id = WM8994_FLL1;
- priv->codec_priv.free_freq = priv->codec_priv.mclk_freq;
+ priv->codec_priv[0].mclk_id = WM8994_FLL_SRC_MCLK1;
+ priv->codec_priv[0].fll_id = WM8994_SYSCLK_FLL1;
+ priv->codec_priv[0].pll_id = WM8994_FLL1;
+ priv->codec_priv[0].free_freq = priv->codec_priv[0].mclk_freq;
priv->card.dapm_routes = NULL;
priv->card.num_dapm_routes = 0;
} else if (of_device_is_compatible(np, "fsl,imx-audio-nau8822")) {
- codec_dai_name = "nau8822-hifi";
- priv->codec_priv.mclk_id = NAU8822_CLK_MCLK;
- priv->codec_priv.fll_id = NAU8822_CLK_PLL;
- priv->codec_priv.pll_id = NAU8822_CLK_PLL;
+ codec_dai_name[0] = "nau8822-hifi";
+ priv->codec_priv[0].mclk_id = NAU8822_CLK_MCLK;
+ priv->codec_priv[0].fll_id = NAU8822_CLK_PLL;
+ priv->codec_priv[0].pll_id = NAU8822_CLK_PLL;
priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
- if (codec_dev)
- priv->codec_priv.mclk = devm_clk_get(codec_dev, NULL);
+ if (codec_dev[0])
+ priv->codec_priv[0].mclk = devm_clk_get(codec_dev[0], NULL);
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8904")) {
- codec_dai_name = "wm8904-hifi";
- priv->codec_priv.mclk_id = WM8904_FLL_MCLK;
- priv->codec_priv.fll_id = WM8904_CLK_FLL;
- priv->codec_priv.pll_id = WM8904_FLL_MCLK;
+ codec_dai_name[0] = "wm8904-hifi";
+ priv->codec_priv[0].mclk_id = WM8904_FLL_MCLK;
+ 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;
@@ -728,18 +833,30 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
* Allow setting mclk-id from the device-tree node. Otherwise, the
* default value for each card configuration is used.
*/
- of_property_read_u32(np, "mclk-id", &priv->codec_priv.mclk_id);
+ for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+ of_property_read_u32_index(np, "mclk-id", codec_idx,
+ &priv->codec_priv[codec_idx].mclk_id);
+ }
/* Format info from DT is optional. */
snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkprovider, &frameprovider);
if (bitclkprovider || frameprovider) {
unsigned int daifmt = snd_soc_daifmt_parse_format(np, NULL);
+ bool codec_bitclkprovider = false;
+ bool codec_frameprovider = false;
+
+ for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+ if (bitclkprovider && codec_np[codec_idx] == bitclkprovider)
+ codec_bitclkprovider = true;
+ if (frameprovider && codec_np[codec_idx] == frameprovider)
+ codec_frameprovider = true;
+ }
- if (codec_np == bitclkprovider)
- daifmt |= (codec_np == frameprovider) ?
+ if (codec_bitclkprovider)
+ daifmt |= (codec_frameprovider) ?
SND_SOC_DAIFMT_CBP_CFP : SND_SOC_DAIFMT_CBP_CFC;
else
- daifmt |= (codec_np == frameprovider) ?
+ daifmt |= (codec_frameprovider) ?
SND_SOC_DAIFMT_CBC_CFP : SND_SOC_DAIFMT_CBC_CFC;
/* Override dai_fmt with value from DT */
@@ -755,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) {
+ 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;
@@ -794,7 +912,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
ret = snd_soc_of_parse_card_name(&priv->card, "model");
if (ret) {
snprintf(priv->name, sizeof(priv->name), "%s-audio",
- fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name);
+ fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name[0]);
priv->card.name = priv->name;
}
priv->card.dai_link = priv->dai_link;
@@ -816,11 +934,19 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* Normal DAI Link */
priv->dai_link[0].cpus->of_node = cpu_np;
- priv->dai_link[0].codecs->dai_name = codec_dai_name;
+ for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+ 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))
- priv->dai_link[0].codecs->of_node = codec_np;
- else {
+ 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];
+ }
+ } else {
u32 idx;
ret = of_property_read_u32(cpu_np, "cell-index", &idx);
@@ -830,11 +956,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto asrc_fail;
}
- priv->dai_link[0].codecs->name =
+ priv->dai_link[0].codecs[0].name =
devm_kasprintf(&pdev->dev, GFP_KERNEL,
"ac97-codec.%u",
(unsigned int)idx);
- if (!priv->dai_link[0].codecs->name) {
+ if (!priv->dai_link[0].codecs[0].name) {
ret = -ENOMEM;
goto asrc_fail;
}
@@ -848,10 +974,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* DPCM DAI Links only if ASRC exists */
priv->dai_link[1].cpus->of_node = asrc_np;
priv->dai_link[1].platforms->of_node = asrc_np;
- priv->dai_link[2].codecs->dai_name = codec_dai_name;
- priv->dai_link[2].codecs->of_node = codec_np;
- priv->dai_link[2].codecs->name =
- priv->dai_link[0].codecs->name;
+ for_each_link_codecs((&(priv->dai_link[2])), codec_idx, codec_comp) {
+ codec_comp->dai_name = priv->dai_link[0].codecs[codec_idx].dai_name;
+ codec_comp->of_node = priv->dai_link[0].codecs[codec_idx].of_node;
+ codec_comp->name = priv->dai_link[0].codecs[codec_idx].name;
+ }
priv->dai_link[2].cpus->of_node = cpu_np;
priv->dai_link[2].dai_fmt = priv->dai_fmt;
priv->card.num_links = 3;
@@ -921,7 +1048,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
asrc_fail:
of_node_put(asrc_np);
- of_node_put(codec_np);
+ of_node_put(codec_np[0]);
+ of_node_put(codec_np[1]);
put_device(&cpu_pdev->dev);
fail:
of_node_put(cpu_np);
@@ -944,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);