162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Freescale Generic ASoC Sound Card driver with ASRC
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (C) 2014 Freescale Semiconductor, Inc.
662306a36Sopenharmony_ci//
762306a36Sopenharmony_ci// Author: Nicolin Chen <nicoleotsuka@gmail.com>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/i2c.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/of_platform.h>
1362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
1462306a36Sopenharmony_ci#include <sound/ac97_codec.h>
1562306a36Sopenharmony_ci#endif
1662306a36Sopenharmony_ci#include <sound/pcm_params.h>
1762306a36Sopenharmony_ci#include <sound/soc.h>
1862306a36Sopenharmony_ci#include <sound/jack.h>
1962306a36Sopenharmony_ci#include <sound/simple_card_utils.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "fsl_esai.h"
2262306a36Sopenharmony_ci#include "fsl_sai.h"
2362306a36Sopenharmony_ci#include "imx-audmux.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "../codecs/sgtl5000.h"
2662306a36Sopenharmony_ci#include "../codecs/wm8962.h"
2762306a36Sopenharmony_ci#include "../codecs/wm8960.h"
2862306a36Sopenharmony_ci#include "../codecs/wm8994.h"
2962306a36Sopenharmony_ci#include "../codecs/tlv320aic31xx.h"
3062306a36Sopenharmony_ci#include "../codecs/nau8822.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define DRIVER_NAME "fsl-asoc-card"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define CS427x_SYSCLK_MCLK 0
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define RX 0
3762306a36Sopenharmony_ci#define TX 1
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* Default DAI format without Master and Slave flag */
4062306a36Sopenharmony_ci#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/**
4362306a36Sopenharmony_ci * struct codec_priv - CODEC private data
4462306a36Sopenharmony_ci * @mclk: Main clock of the CODEC
4562306a36Sopenharmony_ci * @mclk_freq: Clock rate of MCLK
4662306a36Sopenharmony_ci * @free_freq: Clock rate of MCLK for hw_free()
4762306a36Sopenharmony_ci * @mclk_id: MCLK (or main clock) id for set_sysclk()
4862306a36Sopenharmony_ci * @fll_id: FLL (or secordary clock) id for set_sysclk()
4962306a36Sopenharmony_ci * @pll_id: PLL id for set_pll()
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_cistruct codec_priv {
5262306a36Sopenharmony_ci	struct clk *mclk;
5362306a36Sopenharmony_ci	unsigned long mclk_freq;
5462306a36Sopenharmony_ci	unsigned long free_freq;
5562306a36Sopenharmony_ci	u32 mclk_id;
5662306a36Sopenharmony_ci	int fll_id;
5762306a36Sopenharmony_ci	int pll_id;
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/**
6162306a36Sopenharmony_ci * struct cpu_priv - CPU private data
6262306a36Sopenharmony_ci * @sysclk_freq: SYSCLK rates for set_sysclk()
6362306a36Sopenharmony_ci * @sysclk_dir: SYSCLK directions for set_sysclk()
6462306a36Sopenharmony_ci * @sysclk_id: SYSCLK ids for set_sysclk()
6562306a36Sopenharmony_ci * @slot_width: Slot width of each frame
6662306a36Sopenharmony_ci * @slot_num: Number of slots of each frame
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * Note: [1] for tx and [0] for rx
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_cistruct cpu_priv {
7162306a36Sopenharmony_ci	unsigned long sysclk_freq[2];
7262306a36Sopenharmony_ci	u32 sysclk_dir[2];
7362306a36Sopenharmony_ci	u32 sysclk_id[2];
7462306a36Sopenharmony_ci	u32 slot_width;
7562306a36Sopenharmony_ci	u32 slot_num;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * struct fsl_asoc_card_priv - Freescale Generic ASOC card private data
8062306a36Sopenharmony_ci * @dai_link: DAI link structure including normal one and DPCM link
8162306a36Sopenharmony_ci * @hp_jack: Headphone Jack structure
8262306a36Sopenharmony_ci * @mic_jack: Microphone Jack structure
8362306a36Sopenharmony_ci * @pdev: platform device pointer
8462306a36Sopenharmony_ci * @codec_priv: CODEC private data
8562306a36Sopenharmony_ci * @cpu_priv: CPU private data
8662306a36Sopenharmony_ci * @card: ASoC card structure
8762306a36Sopenharmony_ci * @streams: Mask of current active streams
8862306a36Sopenharmony_ci * @sample_rate: Current sample rate
8962306a36Sopenharmony_ci * @sample_format: Current sample format
9062306a36Sopenharmony_ci * @asrc_rate: ASRC sample rate used by Back-Ends
9162306a36Sopenharmony_ci * @asrc_format: ASRC sample format used by Back-Ends
9262306a36Sopenharmony_ci * @dai_fmt: DAI format between CPU and CODEC
9362306a36Sopenharmony_ci * @name: Card name
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistruct fsl_asoc_card_priv {
9762306a36Sopenharmony_ci	struct snd_soc_dai_link dai_link[3];
9862306a36Sopenharmony_ci	struct asoc_simple_jack hp_jack;
9962306a36Sopenharmony_ci	struct asoc_simple_jack mic_jack;
10062306a36Sopenharmony_ci	struct platform_device *pdev;
10162306a36Sopenharmony_ci	struct codec_priv codec_priv;
10262306a36Sopenharmony_ci	struct cpu_priv cpu_priv;
10362306a36Sopenharmony_ci	struct snd_soc_card card;
10462306a36Sopenharmony_ci	u8 streams;
10562306a36Sopenharmony_ci	u32 sample_rate;
10662306a36Sopenharmony_ci	snd_pcm_format_t sample_format;
10762306a36Sopenharmony_ci	u32 asrc_rate;
10862306a36Sopenharmony_ci	snd_pcm_format_t asrc_format;
10962306a36Sopenharmony_ci	u32 dai_fmt;
11062306a36Sopenharmony_ci	char name[32];
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/*
11462306a36Sopenharmony_ci * This dapm route map exists for DPCM link only.
11562306a36Sopenharmony_ci * The other routes shall go through Device Tree.
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * Note: keep all ASRC routes in the second half
11862306a36Sopenharmony_ci *	 to drop them easily for non-ASRC cases.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map[] = {
12162306a36Sopenharmony_ci	/* 1st half -- Normal DAPM routes */
12262306a36Sopenharmony_ci	{"Playback",  NULL, "CPU-Playback"},
12362306a36Sopenharmony_ci	{"CPU-Capture",  NULL, "Capture"},
12462306a36Sopenharmony_ci	/* 2nd half -- ASRC DAPM routes */
12562306a36Sopenharmony_ci	{"CPU-Playback",  NULL, "ASRC-Playback"},
12662306a36Sopenharmony_ci	{"ASRC-Capture",  NULL, "CPU-Capture"},
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map_ac97[] = {
13062306a36Sopenharmony_ci	/* 1st half -- Normal DAPM routes */
13162306a36Sopenharmony_ci	{"AC97 Playback",  NULL, "CPU AC97 Playback"},
13262306a36Sopenharmony_ci	{"CPU AC97 Capture",  NULL, "AC97 Capture"},
13362306a36Sopenharmony_ci	/* 2nd half -- ASRC DAPM routes */
13462306a36Sopenharmony_ci	{"CPU AC97 Playback",  NULL, "ASRC-Playback"},
13562306a36Sopenharmony_ci	{"ASRC-Capture",  NULL, "CPU AC97 Capture"},
13662306a36Sopenharmony_ci};
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map_tx[] = {
13962306a36Sopenharmony_ci	/* 1st half -- Normal DAPM routes */
14062306a36Sopenharmony_ci	{"Playback",  NULL, "CPU-Playback"},
14162306a36Sopenharmony_ci	/* 2nd half -- ASRC DAPM routes */
14262306a36Sopenharmony_ci	{"CPU-Playback",  NULL, "ASRC-Playback"},
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map_rx[] = {
14662306a36Sopenharmony_ci	/* 1st half -- Normal DAPM routes */
14762306a36Sopenharmony_ci	{"CPU-Capture",  NULL, "Capture"},
14862306a36Sopenharmony_ci	/* 2nd half -- ASRC DAPM routes */
14962306a36Sopenharmony_ci	{"ASRC-Capture",  NULL, "CPU-Capture"},
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* Add all possible widgets into here without being redundant */
15362306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
15462306a36Sopenharmony_ci	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
15562306a36Sopenharmony_ci	SND_SOC_DAPM_LINE("Line In Jack", NULL),
15662306a36Sopenharmony_ci	SND_SOC_DAPM_HP("Headphone Jack", NULL),
15762306a36Sopenharmony_ci	SND_SOC_DAPM_SPK("Ext Spk", NULL),
15862306a36Sopenharmony_ci	SND_SOC_DAPM_MIC("Mic Jack", NULL),
15962306a36Sopenharmony_ci	SND_SOC_DAPM_MIC("AMIC", NULL),
16062306a36Sopenharmony_ci	SND_SOC_DAPM_MIC("DMIC", NULL),
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic bool fsl_asoc_card_is_ac97(struct fsl_asoc_card_priv *priv)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	return priv->dai_fmt == SND_SOC_DAIFMT_AC97;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
16962306a36Sopenharmony_ci				   struct snd_pcm_hw_params *params)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
17262306a36Sopenharmony_ci	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
17362306a36Sopenharmony_ci	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
17462306a36Sopenharmony_ci	struct codec_priv *codec_priv = &priv->codec_priv;
17562306a36Sopenharmony_ci	struct cpu_priv *cpu_priv = &priv->cpu_priv;
17662306a36Sopenharmony_ci	struct device *dev = rtd->card->dev;
17762306a36Sopenharmony_ci	unsigned int pll_out;
17862306a36Sopenharmony_ci	int ret;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	priv->sample_rate = params_rate(params);
18162306a36Sopenharmony_ci	priv->sample_format = params_format(params);
18262306a36Sopenharmony_ci	priv->streams |= BIT(substream->stream);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (fsl_asoc_card_is_ac97(priv))
18562306a36Sopenharmony_ci		return 0;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	/* Specific configurations of DAIs starts from here */
18862306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), cpu_priv->sysclk_id[tx],
18962306a36Sopenharmony_ci				     cpu_priv->sysclk_freq[tx],
19062306a36Sopenharmony_ci				     cpu_priv->sysclk_dir[tx]);
19162306a36Sopenharmony_ci	if (ret && ret != -ENOTSUPP) {
19262306a36Sopenharmony_ci		dev_err(dev, "failed to set sysclk for cpu dai\n");
19362306a36Sopenharmony_ci		goto fail;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (cpu_priv->slot_width) {
19762306a36Sopenharmony_ci		if (!cpu_priv->slot_num)
19862306a36Sopenharmony_ci			cpu_priv->slot_num = 2;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3,
20162306a36Sopenharmony_ci					       cpu_priv->slot_num,
20262306a36Sopenharmony_ci					       cpu_priv->slot_width);
20362306a36Sopenharmony_ci		if (ret && ret != -ENOTSUPP) {
20462306a36Sopenharmony_ci			dev_err(dev, "failed to set TDM slot for cpu dai\n");
20562306a36Sopenharmony_ci			goto fail;
20662306a36Sopenharmony_ci		}
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* Specific configuration for PLL */
21062306a36Sopenharmony_ci	if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
21162306a36Sopenharmony_ci		if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
21262306a36Sopenharmony_ci			pll_out = priv->sample_rate * 384;
21362306a36Sopenharmony_ci		else
21462306a36Sopenharmony_ci			pll_out = priv->sample_rate * 256;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		ret = snd_soc_dai_set_pll(asoc_rtd_to_codec(rtd, 0),
21762306a36Sopenharmony_ci					  codec_priv->pll_id,
21862306a36Sopenharmony_ci					  codec_priv->mclk_id,
21962306a36Sopenharmony_ci					  codec_priv->mclk_freq, pll_out);
22062306a36Sopenharmony_ci		if (ret) {
22162306a36Sopenharmony_ci			dev_err(dev, "failed to start FLL: %d\n", ret);
22262306a36Sopenharmony_ci			goto fail;
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0),
22662306a36Sopenharmony_ci					     codec_priv->fll_id,
22762306a36Sopenharmony_ci					     pll_out, SND_SOC_CLOCK_IN);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		if (ret && ret != -ENOTSUPP) {
23062306a36Sopenharmony_ci			dev_err(dev, "failed to set SYSCLK: %d\n", ret);
23162306a36Sopenharmony_ci			goto fail;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return 0;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cifail:
23862306a36Sopenharmony_ci	priv->streams &= ~BIT(substream->stream);
23962306a36Sopenharmony_ci	return ret;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = substream->private_data;
24562306a36Sopenharmony_ci	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
24662306a36Sopenharmony_ci	struct codec_priv *codec_priv = &priv->codec_priv;
24762306a36Sopenharmony_ci	struct device *dev = rtd->card->dev;
24862306a36Sopenharmony_ci	int ret;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	priv->streams &= ~BIT(substream->stream);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
25362306a36Sopenharmony_ci		/* Force freq to be free_freq to avoid error message in codec */
25462306a36Sopenharmony_ci		ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0),
25562306a36Sopenharmony_ci					     codec_priv->mclk_id,
25662306a36Sopenharmony_ci					     codec_priv->free_freq,
25762306a36Sopenharmony_ci					     SND_SOC_CLOCK_IN);
25862306a36Sopenharmony_ci		if (ret) {
25962306a36Sopenharmony_ci			dev_err(dev, "failed to switch away from FLL: %d\n", ret);
26062306a36Sopenharmony_ci			return ret;
26162306a36Sopenharmony_ci		}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		ret = snd_soc_dai_set_pll(asoc_rtd_to_codec(rtd, 0),
26462306a36Sopenharmony_ci					  codec_priv->pll_id, 0, 0, 0);
26562306a36Sopenharmony_ci		if (ret && ret != -ENOTSUPP) {
26662306a36Sopenharmony_ci			dev_err(dev, "failed to stop FLL: %d\n", ret);
26762306a36Sopenharmony_ci			return ret;
26862306a36Sopenharmony_ci		}
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	return 0;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic const struct snd_soc_ops fsl_asoc_card_ops = {
27562306a36Sopenharmony_ci	.hw_params = fsl_asoc_card_hw_params,
27662306a36Sopenharmony_ci	.hw_free = fsl_asoc_card_hw_free,
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
28062306a36Sopenharmony_ci			      struct snd_pcm_hw_params *params)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
28362306a36Sopenharmony_ci	struct snd_interval *rate;
28462306a36Sopenharmony_ci	struct snd_mask *mask;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
28762306a36Sopenharmony_ci	rate->max = rate->min = priv->asrc_rate;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
29062306a36Sopenharmony_ci	snd_mask_none(mask);
29162306a36Sopenharmony_ci	snd_mask_set_format(mask, priv->asrc_format);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return 0;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(hifi,
29762306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
29862306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
29962306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()));
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(hifi_fe,
30262306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
30362306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_DUMMY()),
30462306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()));
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(hifi_be,
30762306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
30862306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
30962306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_DUMMY()));
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic const struct snd_soc_dai_link fsl_asoc_card_dai[] = {
31262306a36Sopenharmony_ci	/* Default ASoC DAI Link*/
31362306a36Sopenharmony_ci	{
31462306a36Sopenharmony_ci		.name = "HiFi",
31562306a36Sopenharmony_ci		.stream_name = "HiFi",
31662306a36Sopenharmony_ci		.ops = &fsl_asoc_card_ops,
31762306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(hifi),
31862306a36Sopenharmony_ci	},
31962306a36Sopenharmony_ci	/* DPCM Link between Front-End and Back-End (Optional) */
32062306a36Sopenharmony_ci	{
32162306a36Sopenharmony_ci		.name = "HiFi-ASRC-FE",
32262306a36Sopenharmony_ci		.stream_name = "HiFi-ASRC-FE",
32362306a36Sopenharmony_ci		.dpcm_playback = 1,
32462306a36Sopenharmony_ci		.dpcm_capture = 1,
32562306a36Sopenharmony_ci		.dynamic = 1,
32662306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(hifi_fe),
32762306a36Sopenharmony_ci	},
32862306a36Sopenharmony_ci	{
32962306a36Sopenharmony_ci		.name = "HiFi-ASRC-BE",
33062306a36Sopenharmony_ci		.stream_name = "HiFi-ASRC-BE",
33162306a36Sopenharmony_ci		.be_hw_params_fixup = be_hw_params_fixup,
33262306a36Sopenharmony_ci		.ops = &fsl_asoc_card_ops,
33362306a36Sopenharmony_ci		.dpcm_playback = 1,
33462306a36Sopenharmony_ci		.dpcm_capture = 1,
33562306a36Sopenharmony_ci		.no_pcm = 1,
33662306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(hifi_be),
33762306a36Sopenharmony_ci	},
33862306a36Sopenharmony_ci};
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int fsl_asoc_card_audmux_init(struct device_node *np,
34162306a36Sopenharmony_ci				     struct fsl_asoc_card_priv *priv)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct device *dev = &priv->pdev->dev;
34462306a36Sopenharmony_ci	u32 int_ptcr = 0, ext_ptcr = 0;
34562306a36Sopenharmony_ci	int int_port, ext_port;
34662306a36Sopenharmony_ci	int ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	ret = of_property_read_u32(np, "mux-int-port", &int_port);
34962306a36Sopenharmony_ci	if (ret) {
35062306a36Sopenharmony_ci		dev_err(dev, "mux-int-port missing or invalid\n");
35162306a36Sopenharmony_ci		return ret;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
35462306a36Sopenharmony_ci	if (ret) {
35562306a36Sopenharmony_ci		dev_err(dev, "mux-ext-port missing or invalid\n");
35662306a36Sopenharmony_ci		return ret;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/*
36062306a36Sopenharmony_ci	 * The port numbering in the hardware manual starts at 1, while
36162306a36Sopenharmony_ci	 * the AUDMUX API expects it starts at 0.
36262306a36Sopenharmony_ci	 */
36362306a36Sopenharmony_ci	int_port--;
36462306a36Sopenharmony_ci	ext_port--;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/*
36762306a36Sopenharmony_ci	 * Use asynchronous mode (6 wires) for all cases except AC97.
36862306a36Sopenharmony_ci	 * If only 4 wires are needed, just set SSI into
36962306a36Sopenharmony_ci	 * synchronous mode and enable 4 PADs in IOMUX.
37062306a36Sopenharmony_ci	 */
37162306a36Sopenharmony_ci	switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
37262306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFP:
37362306a36Sopenharmony_ci		int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
37462306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
37562306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
37662306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
37762306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RFSDIR |
37862306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RCLKDIR |
37962306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSDIR |
38062306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
38162306a36Sopenharmony_ci		break;
38262306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFC:
38362306a36Sopenharmony_ci		int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
38462306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
38562306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RCLKDIR |
38662306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
38762306a36Sopenharmony_ci		ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
38862306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
38962306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RFSDIR |
39062306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSDIR;
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFP:
39362306a36Sopenharmony_ci		int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
39462306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
39562306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RFSDIR |
39662306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSDIR;
39762306a36Sopenharmony_ci		ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
39862306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
39962306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RCLKDIR |
40062306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
40162306a36Sopenharmony_ci		break;
40262306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFC:
40362306a36Sopenharmony_ci		ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
40462306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
40562306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
40662306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
40762306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RFSDIR |
40862306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_RCLKDIR |
40962306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSDIR |
41062306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	default:
41362306a36Sopenharmony_ci		if (!fsl_asoc_card_is_ac97(priv))
41462306a36Sopenharmony_ci			return -EINVAL;
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (fsl_asoc_card_is_ac97(priv)) {
41862306a36Sopenharmony_ci		int_ptcr = IMX_AUDMUX_V2_PTCR_SYN |
41962306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
42062306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TCLKDIR;
42162306a36Sopenharmony_ci		ext_ptcr = IMX_AUDMUX_V2_PTCR_SYN |
42262306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
42362306a36Sopenharmony_ci			   IMX_AUDMUX_V2_PTCR_TFSDIR;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Asynchronous mode can not be set along with RCLKDIR */
42762306a36Sopenharmony_ci	if (!fsl_asoc_card_is_ac97(priv)) {
42862306a36Sopenharmony_ci		unsigned int pdcr =
42962306a36Sopenharmony_ci				IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		ret = imx_audmux_v2_configure_port(int_port, 0,
43262306a36Sopenharmony_ci						   pdcr);
43362306a36Sopenharmony_ci		if (ret) {
43462306a36Sopenharmony_ci			dev_err(dev, "audmux internal port setup failed\n");
43562306a36Sopenharmony_ci			return ret;
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	ret = imx_audmux_v2_configure_port(int_port, int_ptcr,
44062306a36Sopenharmony_ci					   IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
44162306a36Sopenharmony_ci	if (ret) {
44262306a36Sopenharmony_ci		dev_err(dev, "audmux internal port setup failed\n");
44362306a36Sopenharmony_ci		return ret;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (!fsl_asoc_card_is_ac97(priv)) {
44762306a36Sopenharmony_ci		unsigned int pdcr =
44862306a36Sopenharmony_ci				IMX_AUDMUX_V2_PDCR_RXDSEL(int_port);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		ret = imx_audmux_v2_configure_port(ext_port, 0,
45162306a36Sopenharmony_ci						   pdcr);
45262306a36Sopenharmony_ci		if (ret) {
45362306a36Sopenharmony_ci			dev_err(dev, "audmux external port setup failed\n");
45462306a36Sopenharmony_ci			return ret;
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr,
45962306a36Sopenharmony_ci					   IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
46062306a36Sopenharmony_ci	if (ret) {
46162306a36Sopenharmony_ci		dev_err(dev, "audmux external port setup failed\n");
46262306a36Sopenharmony_ci		return ret;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	return 0;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic int hp_jack_event(struct notifier_block *nb, unsigned long event,
46962306a36Sopenharmony_ci			 void *data)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
47262306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = &jack->card->dapm;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (event & SND_JACK_HEADPHONE)
47562306a36Sopenharmony_ci		/* Disable speaker if headphone is plugged in */
47662306a36Sopenharmony_ci		return snd_soc_dapm_disable_pin(dapm, "Ext Spk");
47762306a36Sopenharmony_ci	else
47862306a36Sopenharmony_ci		return snd_soc_dapm_enable_pin(dapm, "Ext Spk");
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic struct notifier_block hp_jack_nb = {
48262306a36Sopenharmony_ci	.notifier_call = hp_jack_event,
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic int mic_jack_event(struct notifier_block *nb, unsigned long event,
48662306a36Sopenharmony_ci			  void *data)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
48962306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = &jack->card->dapm;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (event & SND_JACK_MICROPHONE)
49262306a36Sopenharmony_ci		/* Disable dmic if microphone is plugged in */
49362306a36Sopenharmony_ci		return snd_soc_dapm_disable_pin(dapm, "DMIC");
49462306a36Sopenharmony_ci	else
49562306a36Sopenharmony_ci		return snd_soc_dapm_enable_pin(dapm, "DMIC");
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic struct notifier_block mic_jack_nb = {
49962306a36Sopenharmony_ci	.notifier_call = mic_jack_event,
50062306a36Sopenharmony_ci};
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic int fsl_asoc_card_late_probe(struct snd_soc_card *card)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
50562306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = list_first_entry(
50662306a36Sopenharmony_ci			&card->rtd_list, struct snd_soc_pcm_runtime, list);
50762306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
50862306a36Sopenharmony_ci	struct codec_priv *codec_priv = &priv->codec_priv;
50962306a36Sopenharmony_ci	struct device *dev = card->dev;
51062306a36Sopenharmony_ci	int ret;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (fsl_asoc_card_is_ac97(priv)) {
51362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
51462306a36Sopenharmony_ci		struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
51562306a36Sopenharmony_ci		struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		/*
51862306a36Sopenharmony_ci		 * Use slots 3/4 for S/PDIF so SSI won't try to enable
51962306a36Sopenharmony_ci		 * other slots and send some samples there
52062306a36Sopenharmony_ci		 * due to SLOTREQ bits for S/PDIF received from codec
52162306a36Sopenharmony_ci		 */
52262306a36Sopenharmony_ci		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,
52362306a36Sopenharmony_ci				     AC97_EA_SPSA_SLOT_MASK, AC97_EA_SPSA_3_4);
52462306a36Sopenharmony_ci#endif
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		return 0;
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
53062306a36Sopenharmony_ci				     codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
53162306a36Sopenharmony_ci	if (ret && ret != -ENOTSUPP) {
53262306a36Sopenharmony_ci		dev_err(dev, "failed to set sysclk in %s\n", __func__);
53362306a36Sopenharmony_ci		return ret;
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(codec_priv->mclk))
53762306a36Sopenharmony_ci		clk_prepare_enable(codec_priv->mclk);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic int fsl_asoc_card_probe(struct platform_device *pdev)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct device_node *cpu_np, *codec_np, *asrc_np;
54562306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
54662306a36Sopenharmony_ci	struct platform_device *asrc_pdev = NULL;
54762306a36Sopenharmony_ci	struct device_node *bitclkprovider = NULL;
54862306a36Sopenharmony_ci	struct device_node *frameprovider = NULL;
54962306a36Sopenharmony_ci	struct platform_device *cpu_pdev;
55062306a36Sopenharmony_ci	struct fsl_asoc_card_priv *priv;
55162306a36Sopenharmony_ci	struct device *codec_dev = NULL;
55262306a36Sopenharmony_ci	const char *codec_dai_name;
55362306a36Sopenharmony_ci	const char *codec_dev_name;
55462306a36Sopenharmony_ci	u32 asrc_fmt = 0;
55562306a36Sopenharmony_ci	u32 width;
55662306a36Sopenharmony_ci	int ret;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
55962306a36Sopenharmony_ci	if (!priv)
56062306a36Sopenharmony_ci		return -ENOMEM;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	cpu_np = of_parse_phandle(np, "audio-cpu", 0);
56362306a36Sopenharmony_ci	/* Give a chance to old DT binding */
56462306a36Sopenharmony_ci	if (!cpu_np)
56562306a36Sopenharmony_ci		cpu_np = of_parse_phandle(np, "ssi-controller", 0);
56662306a36Sopenharmony_ci	if (!cpu_np) {
56762306a36Sopenharmony_ci		dev_err(&pdev->dev, "CPU phandle missing or invalid\n");
56862306a36Sopenharmony_ci		ret = -EINVAL;
56962306a36Sopenharmony_ci		goto fail;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	cpu_pdev = of_find_device_by_node(cpu_np);
57362306a36Sopenharmony_ci	if (!cpu_pdev) {
57462306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to find CPU DAI device\n");
57562306a36Sopenharmony_ci		ret = -EINVAL;
57662306a36Sopenharmony_ci		goto fail;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	codec_np = of_parse_phandle(np, "audio-codec", 0);
58062306a36Sopenharmony_ci	if (codec_np) {
58162306a36Sopenharmony_ci		struct platform_device *codec_pdev;
58262306a36Sopenharmony_ci		struct i2c_client *codec_i2c;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		codec_i2c = of_find_i2c_device_by_node(codec_np);
58562306a36Sopenharmony_ci		if (codec_i2c) {
58662306a36Sopenharmony_ci			codec_dev = &codec_i2c->dev;
58762306a36Sopenharmony_ci			codec_dev_name = codec_i2c->name;
58862306a36Sopenharmony_ci		}
58962306a36Sopenharmony_ci		if (!codec_dev) {
59062306a36Sopenharmony_ci			codec_pdev = of_find_device_by_node(codec_np);
59162306a36Sopenharmony_ci			if (codec_pdev) {
59262306a36Sopenharmony_ci				codec_dev = &codec_pdev->dev;
59362306a36Sopenharmony_ci				codec_dev_name = codec_pdev->name;
59462306a36Sopenharmony_ci			}
59562306a36Sopenharmony_ci		}
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	asrc_np = of_parse_phandle(np, "audio-asrc", 0);
59962306a36Sopenharmony_ci	if (asrc_np)
60062306a36Sopenharmony_ci		asrc_pdev = of_find_device_by_node(asrc_np);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* Get the MCLK rate only, and leave it controlled by CODEC drivers */
60362306a36Sopenharmony_ci	if (codec_dev) {
60462306a36Sopenharmony_ci		struct clk *codec_clk = clk_get(codec_dev, NULL);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		if (!IS_ERR(codec_clk)) {
60762306a36Sopenharmony_ci			priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
60862306a36Sopenharmony_ci			clk_put(codec_clk);
60962306a36Sopenharmony_ci		}
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	/* Default sample rate and format, will be updated in hw_params() */
61362306a36Sopenharmony_ci	priv->sample_rate = 44100;
61462306a36Sopenharmony_ci	priv->sample_format = SNDRV_PCM_FORMAT_S16_LE;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* Assign a default DAI format, and allow each card to overwrite it */
61762306a36Sopenharmony_ci	priv->dai_fmt = DAI_FMT_BASE;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	memcpy(priv->dai_link, fsl_asoc_card_dai,
62062306a36Sopenharmony_ci	       sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	priv->card.dapm_routes = audio_map;
62362306a36Sopenharmony_ci	priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
62462306a36Sopenharmony_ci	priv->card.driver_name = DRIVER_NAME;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	priv->codec_priv.fll_id = -1;
62762306a36Sopenharmony_ci	priv->codec_priv.pll_id = -1;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	/* Diversify the card configurations */
63062306a36Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
63162306a36Sopenharmony_ci		codec_dai_name = "cs42888";
63262306a36Sopenharmony_ci		priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
63362306a36Sopenharmony_ci		priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
63462306a36Sopenharmony_ci		priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
63562306a36Sopenharmony_ci		priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
63662306a36Sopenharmony_ci		priv->cpu_priv.slot_width = 32;
63762306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
63862306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) {
63962306a36Sopenharmony_ci		codec_dai_name = "cs4271-hifi";
64062306a36Sopenharmony_ci		priv->codec_priv.mclk_id = CS427x_SYSCLK_MCLK;
64162306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
64262306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
64362306a36Sopenharmony_ci		codec_dai_name = "sgtl5000";
64462306a36Sopenharmony_ci		priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
64562306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
64662306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) {
64762306a36Sopenharmony_ci		codec_dai_name = "tlv320aic32x4-hifi";
64862306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
64962306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) {
65062306a36Sopenharmony_ci		codec_dai_name = "tlv320dac31xx-hifi";
65162306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
65262306a36Sopenharmony_ci		priv->dai_link[1].dpcm_capture = 0;
65362306a36Sopenharmony_ci		priv->dai_link[2].dpcm_capture = 0;
65462306a36Sopenharmony_ci		priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
65562306a36Sopenharmony_ci		priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
65662306a36Sopenharmony_ci		priv->card.dapm_routes = audio_map_tx;
65762306a36Sopenharmony_ci		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
65862306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
65962306a36Sopenharmony_ci		codec_dai_name = "wm8962";
66062306a36Sopenharmony_ci		priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
66162306a36Sopenharmony_ci		priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
66262306a36Sopenharmony_ci		priv->codec_priv.pll_id = WM8962_FLL;
66362306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
66462306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) {
66562306a36Sopenharmony_ci		codec_dai_name = "wm8960-hifi";
66662306a36Sopenharmony_ci		priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
66762306a36Sopenharmony_ci		priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
66862306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
66962306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
67062306a36Sopenharmony_ci		codec_dai_name = "ac97-hifi";
67162306a36Sopenharmony_ci		priv->dai_fmt = SND_SOC_DAIFMT_AC97;
67262306a36Sopenharmony_ci		priv->card.dapm_routes = audio_map_ac97;
67362306a36Sopenharmony_ci		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_ac97);
67462306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) {
67562306a36Sopenharmony_ci		codec_dai_name = "fsl-mqs-dai";
67662306a36Sopenharmony_ci		priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J |
67762306a36Sopenharmony_ci				SND_SOC_DAIFMT_CBC_CFC |
67862306a36Sopenharmony_ci				SND_SOC_DAIFMT_NB_NF;
67962306a36Sopenharmony_ci		priv->dai_link[1].dpcm_capture = 0;
68062306a36Sopenharmony_ci		priv->dai_link[2].dpcm_capture = 0;
68162306a36Sopenharmony_ci		priv->card.dapm_routes = audio_map_tx;
68262306a36Sopenharmony_ci		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
68362306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) {
68462306a36Sopenharmony_ci		codec_dai_name = "wm8524-hifi";
68562306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
68662306a36Sopenharmony_ci		priv->dai_link[1].dpcm_capture = 0;
68762306a36Sopenharmony_ci		priv->dai_link[2].dpcm_capture = 0;
68862306a36Sopenharmony_ci		priv->cpu_priv.slot_width = 32;
68962306a36Sopenharmony_ci		priv->card.dapm_routes = audio_map_tx;
69062306a36Sopenharmony_ci		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
69162306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) {
69262306a36Sopenharmony_ci		codec_dai_name = "si476x-codec";
69362306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
69462306a36Sopenharmony_ci		priv->card.dapm_routes = audio_map_rx;
69562306a36Sopenharmony_ci		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
69662306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) {
69762306a36Sopenharmony_ci		codec_dai_name = "wm8994-aif1";
69862306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
69962306a36Sopenharmony_ci		priv->codec_priv.mclk_id = WM8994_FLL_SRC_MCLK1;
70062306a36Sopenharmony_ci		priv->codec_priv.fll_id = WM8994_SYSCLK_FLL1;
70162306a36Sopenharmony_ci		priv->codec_priv.pll_id = WM8994_FLL1;
70262306a36Sopenharmony_ci		priv->codec_priv.free_freq = priv->codec_priv.mclk_freq;
70362306a36Sopenharmony_ci		priv->card.dapm_routes = NULL;
70462306a36Sopenharmony_ci		priv->card.num_dapm_routes = 0;
70562306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "fsl,imx-audio-nau8822")) {
70662306a36Sopenharmony_ci		codec_dai_name = "nau8822-hifi";
70762306a36Sopenharmony_ci		priv->codec_priv.mclk_id = NAU8822_CLK_MCLK;
70862306a36Sopenharmony_ci		priv->codec_priv.fll_id = NAU8822_CLK_PLL;
70962306a36Sopenharmony_ci		priv->codec_priv.pll_id = NAU8822_CLK_PLL;
71062306a36Sopenharmony_ci		priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
71162306a36Sopenharmony_ci		if (codec_dev)
71262306a36Sopenharmony_ci			priv->codec_priv.mclk = devm_clk_get(codec_dev, NULL);
71362306a36Sopenharmony_ci	} else {
71462306a36Sopenharmony_ci		dev_err(&pdev->dev, "unknown Device Tree compatible\n");
71562306a36Sopenharmony_ci		ret = -EINVAL;
71662306a36Sopenharmony_ci		goto asrc_fail;
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/*
72062306a36Sopenharmony_ci	 * Allow setting mclk-id from the device-tree node. Otherwise, the
72162306a36Sopenharmony_ci	 * default value for each card configuration is used.
72262306a36Sopenharmony_ci	 */
72362306a36Sopenharmony_ci	of_property_read_u32(np, "mclk-id", &priv->codec_priv.mclk_id);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	/* Format info from DT is optional. */
72662306a36Sopenharmony_ci	snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkprovider, &frameprovider);
72762306a36Sopenharmony_ci	if (bitclkprovider || frameprovider) {
72862306a36Sopenharmony_ci		unsigned int daifmt = snd_soc_daifmt_parse_format(np, NULL);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		if (codec_np == bitclkprovider)
73162306a36Sopenharmony_ci			daifmt |= (codec_np == frameprovider) ?
73262306a36Sopenharmony_ci				SND_SOC_DAIFMT_CBP_CFP : SND_SOC_DAIFMT_CBP_CFC;
73362306a36Sopenharmony_ci		else
73462306a36Sopenharmony_ci			daifmt |= (codec_np == frameprovider) ?
73562306a36Sopenharmony_ci				SND_SOC_DAIFMT_CBC_CFP : SND_SOC_DAIFMT_CBC_CFC;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		/* Override dai_fmt with value from DT */
73862306a36Sopenharmony_ci		priv->dai_fmt = daifmt;
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* Change direction according to format */
74262306a36Sopenharmony_ci	if (priv->dai_fmt & SND_SOC_DAIFMT_CBP_CFP) {
74362306a36Sopenharmony_ci		priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_IN;
74462306a36Sopenharmony_ci		priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_IN;
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	of_node_put(bitclkprovider);
74862306a36Sopenharmony_ci	of_node_put(frameprovider);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) {
75162306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "failed to find codec device\n");
75262306a36Sopenharmony_ci		ret = -EPROBE_DEFER;
75362306a36Sopenharmony_ci		goto asrc_fail;
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	/* Common settings for corresponding Freescale CPU DAI driver */
75762306a36Sopenharmony_ci	if (of_node_name_eq(cpu_np, "ssi")) {
75862306a36Sopenharmony_ci		/* Only SSI needs to configure AUDMUX */
75962306a36Sopenharmony_ci		ret = fsl_asoc_card_audmux_init(np, priv);
76062306a36Sopenharmony_ci		if (ret) {
76162306a36Sopenharmony_ci			dev_err(&pdev->dev, "failed to init audmux\n");
76262306a36Sopenharmony_ci			goto asrc_fail;
76362306a36Sopenharmony_ci		}
76462306a36Sopenharmony_ci	} else if (of_node_name_eq(cpu_np, "esai")) {
76562306a36Sopenharmony_ci		struct clk *esai_clk = clk_get(&cpu_pdev->dev, "extal");
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		if (!IS_ERR(esai_clk)) {
76862306a36Sopenharmony_ci			priv->cpu_priv.sysclk_freq[TX] = clk_get_rate(esai_clk);
76962306a36Sopenharmony_ci			priv->cpu_priv.sysclk_freq[RX] = clk_get_rate(esai_clk);
77062306a36Sopenharmony_ci			clk_put(esai_clk);
77162306a36Sopenharmony_ci		} else if (PTR_ERR(esai_clk) == -EPROBE_DEFER) {
77262306a36Sopenharmony_ci			ret = -EPROBE_DEFER;
77362306a36Sopenharmony_ci			goto asrc_fail;
77462306a36Sopenharmony_ci		}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
77762306a36Sopenharmony_ci		priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
77862306a36Sopenharmony_ci	} else if (of_node_name_eq(cpu_np, "sai")) {
77962306a36Sopenharmony_ci		priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
78062306a36Sopenharmony_ci		priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	/* Initialize sound card */
78462306a36Sopenharmony_ci	priv->pdev = pdev;
78562306a36Sopenharmony_ci	priv->card.dev = &pdev->dev;
78662306a36Sopenharmony_ci	priv->card.owner = THIS_MODULE;
78762306a36Sopenharmony_ci	ret = snd_soc_of_parse_card_name(&priv->card, "model");
78862306a36Sopenharmony_ci	if (ret) {
78962306a36Sopenharmony_ci		snprintf(priv->name, sizeof(priv->name), "%s-audio",
79062306a36Sopenharmony_ci			 fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name);
79162306a36Sopenharmony_ci		priv->card.name = priv->name;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci	priv->card.dai_link = priv->dai_link;
79462306a36Sopenharmony_ci	priv->card.late_probe = fsl_asoc_card_late_probe;
79562306a36Sopenharmony_ci	priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
79662306a36Sopenharmony_ci	priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	/* Drop the second half of DAPM routes -- ASRC */
79962306a36Sopenharmony_ci	if (!asrc_pdev)
80062306a36Sopenharmony_ci		priv->card.num_dapm_routes /= 2;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (of_property_read_bool(np, "audio-routing")) {
80362306a36Sopenharmony_ci		ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing");
80462306a36Sopenharmony_ci		if (ret) {
80562306a36Sopenharmony_ci			dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
80662306a36Sopenharmony_ci			goto asrc_fail;
80762306a36Sopenharmony_ci		}
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/* Normal DAI Link */
81162306a36Sopenharmony_ci	priv->dai_link[0].cpus->of_node = cpu_np;
81262306a36Sopenharmony_ci	priv->dai_link[0].codecs->dai_name = codec_dai_name;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (!fsl_asoc_card_is_ac97(priv))
81562306a36Sopenharmony_ci		priv->dai_link[0].codecs->of_node = codec_np;
81662306a36Sopenharmony_ci	else {
81762306a36Sopenharmony_ci		u32 idx;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci		ret = of_property_read_u32(cpu_np, "cell-index", &idx);
82062306a36Sopenharmony_ci		if (ret) {
82162306a36Sopenharmony_ci			dev_err(&pdev->dev,
82262306a36Sopenharmony_ci				"cannot get CPU index property\n");
82362306a36Sopenharmony_ci			goto asrc_fail;
82462306a36Sopenharmony_ci		}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		priv->dai_link[0].codecs->name =
82762306a36Sopenharmony_ci				devm_kasprintf(&pdev->dev, GFP_KERNEL,
82862306a36Sopenharmony_ci					       "ac97-codec.%u",
82962306a36Sopenharmony_ci					       (unsigned int)idx);
83062306a36Sopenharmony_ci		if (!priv->dai_link[0].codecs->name) {
83162306a36Sopenharmony_ci			ret = -ENOMEM;
83262306a36Sopenharmony_ci			goto asrc_fail;
83362306a36Sopenharmony_ci		}
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	priv->dai_link[0].platforms->of_node = cpu_np;
83762306a36Sopenharmony_ci	priv->dai_link[0].dai_fmt = priv->dai_fmt;
83862306a36Sopenharmony_ci	priv->card.num_links = 1;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if (asrc_pdev) {
84162306a36Sopenharmony_ci		/* DPCM DAI Links only if ASRC exists */
84262306a36Sopenharmony_ci		priv->dai_link[1].cpus->of_node = asrc_np;
84362306a36Sopenharmony_ci		priv->dai_link[1].platforms->of_node = asrc_np;
84462306a36Sopenharmony_ci		priv->dai_link[2].codecs->dai_name = codec_dai_name;
84562306a36Sopenharmony_ci		priv->dai_link[2].codecs->of_node = codec_np;
84662306a36Sopenharmony_ci		priv->dai_link[2].codecs->name =
84762306a36Sopenharmony_ci				priv->dai_link[0].codecs->name;
84862306a36Sopenharmony_ci		priv->dai_link[2].cpus->of_node = cpu_np;
84962306a36Sopenharmony_ci		priv->dai_link[2].dai_fmt = priv->dai_fmt;
85062306a36Sopenharmony_ci		priv->card.num_links = 3;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci		ret = of_property_read_u32(asrc_np, "fsl,asrc-rate",
85362306a36Sopenharmony_ci					   &priv->asrc_rate);
85462306a36Sopenharmony_ci		if (ret) {
85562306a36Sopenharmony_ci			dev_err(&pdev->dev, "failed to get output rate\n");
85662306a36Sopenharmony_ci			ret = -EINVAL;
85762306a36Sopenharmony_ci			goto asrc_fail;
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci		ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt);
86162306a36Sopenharmony_ci		priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
86262306a36Sopenharmony_ci		if (ret) {
86362306a36Sopenharmony_ci			/* Fallback to old binding; translate to asrc_format */
86462306a36Sopenharmony_ci			ret = of_property_read_u32(asrc_np, "fsl,asrc-width",
86562306a36Sopenharmony_ci						   &width);
86662306a36Sopenharmony_ci			if (ret) {
86762306a36Sopenharmony_ci				dev_err(&pdev->dev,
86862306a36Sopenharmony_ci					"failed to decide output format\n");
86962306a36Sopenharmony_ci				goto asrc_fail;
87062306a36Sopenharmony_ci			}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci			if (width == 24)
87362306a36Sopenharmony_ci				priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
87462306a36Sopenharmony_ci			else
87562306a36Sopenharmony_ci				priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
87662306a36Sopenharmony_ci		}
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* Finish card registering */
88062306a36Sopenharmony_ci	platform_set_drvdata(pdev, priv);
88162306a36Sopenharmony_ci	snd_soc_card_set_drvdata(&priv->card, priv);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	ret = devm_snd_soc_register_card(&pdev->dev, &priv->card);
88462306a36Sopenharmony_ci	if (ret) {
88562306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n");
88662306a36Sopenharmony_ci		goto asrc_fail;
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/*
89062306a36Sopenharmony_ci	 * Properties "hp-det-gpio" and "mic-det-gpio" are optional, and
89162306a36Sopenharmony_ci	 * asoc_simple_init_jack uses these properties for creating
89262306a36Sopenharmony_ci	 * Headphone Jack and Microphone Jack.
89362306a36Sopenharmony_ci	 *
89462306a36Sopenharmony_ci	 * The notifier is initialized in snd_soc_card_jack_new(), then
89562306a36Sopenharmony_ci	 * snd_soc_jack_notifier_register can be called.
89662306a36Sopenharmony_ci	 */
89762306a36Sopenharmony_ci	if (of_property_read_bool(np, "hp-det-gpio")) {
89862306a36Sopenharmony_ci		ret = asoc_simple_init_jack(&priv->card, &priv->hp_jack,
89962306a36Sopenharmony_ci					    1, NULL, "Headphone Jack");
90062306a36Sopenharmony_ci		if (ret)
90162306a36Sopenharmony_ci			goto asrc_fail;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci		snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb);
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	if (of_property_read_bool(np, "mic-det-gpio")) {
90762306a36Sopenharmony_ci		ret = asoc_simple_init_jack(&priv->card, &priv->mic_jack,
90862306a36Sopenharmony_ci					    0, NULL, "Mic Jack");
90962306a36Sopenharmony_ci		if (ret)
91062306a36Sopenharmony_ci			goto asrc_fail;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		snd_soc_jack_notifier_register(&priv->mic_jack.jack, &mic_jack_nb);
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ciasrc_fail:
91662306a36Sopenharmony_ci	of_node_put(asrc_np);
91762306a36Sopenharmony_ci	of_node_put(codec_np);
91862306a36Sopenharmony_ci	put_device(&cpu_pdev->dev);
91962306a36Sopenharmony_cifail:
92062306a36Sopenharmony_ci	of_node_put(cpu_np);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	return ret;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic const struct of_device_id fsl_asoc_card_dt_ids[] = {
92662306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-ac97", },
92762306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-cs42888", },
92862306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-cs427x", },
92962306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-tlv320aic32x4", },
93062306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-tlv320aic31xx", },
93162306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-sgtl5000", },
93262306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-wm8962", },
93362306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-wm8960", },
93462306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-mqs", },
93562306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-wm8524", },
93662306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-si476x", },
93762306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-wm8958", },
93862306a36Sopenharmony_ci	{ .compatible = "fsl,imx-audio-nau8822", },
93962306a36Sopenharmony_ci	{}
94062306a36Sopenharmony_ci};
94162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic struct platform_driver fsl_asoc_card_driver = {
94462306a36Sopenharmony_ci	.probe = fsl_asoc_card_probe,
94562306a36Sopenharmony_ci	.driver = {
94662306a36Sopenharmony_ci		.name = DRIVER_NAME,
94762306a36Sopenharmony_ci		.pm = &snd_soc_pm_ops,
94862306a36Sopenharmony_ci		.of_match_table = fsl_asoc_card_dt_ids,
94962306a36Sopenharmony_ci	},
95062306a36Sopenharmony_ci};
95162306a36Sopenharmony_cimodule_platform_driver(fsl_asoc_card_driver);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ciMODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC");
95462306a36Sopenharmony_ciMODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>");
95562306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRIVER_NAME);
95662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
957