xref: /linux/sound/soc/fsl/imx-audmix.c (revision b86ef5367761603df5f66ce08fb014b991f6b51d)
1*b86ef536SViorel Suman // SPDX-License-Identifier: GPL-2.0
2*b86ef536SViorel Suman /*
3*b86ef536SViorel Suman  * Copyright 2017 NXP
4*b86ef536SViorel Suman  *
5*b86ef536SViorel Suman  * The code contained herein is licensed under the GNU General Public
6*b86ef536SViorel Suman  * License. You may obtain a copy of the GNU General Public License
7*b86ef536SViorel Suman  * Version 2 or later at the following locations:
8*b86ef536SViorel Suman  *
9*b86ef536SViorel Suman  * http://www.opensource.org/licenses/gpl-license.html
10*b86ef536SViorel Suman  * http://www.gnu.org/copyleft/gpl.html
11*b86ef536SViorel Suman  */
12*b86ef536SViorel Suman 
13*b86ef536SViorel Suman #include <linux/module.h>
14*b86ef536SViorel Suman #include <linux/of_platform.h>
15*b86ef536SViorel Suman #include <linux/clk.h>
16*b86ef536SViorel Suman #include <sound/soc.h>
17*b86ef536SViorel Suman #include <sound/soc-dapm.h>
18*b86ef536SViorel Suman #include <linux/pm_runtime.h>
19*b86ef536SViorel Suman #include "fsl_sai.h"
20*b86ef536SViorel Suman #include "fsl_audmix.h"
21*b86ef536SViorel Suman 
22*b86ef536SViorel Suman struct imx_audmix {
23*b86ef536SViorel Suman 	struct platform_device *pdev;
24*b86ef536SViorel Suman 	struct snd_soc_card card;
25*b86ef536SViorel Suman 	struct platform_device *audmix_pdev;
26*b86ef536SViorel Suman 	struct platform_device *out_pdev;
27*b86ef536SViorel Suman 	struct clk *cpu_mclk;
28*b86ef536SViorel Suman 	int num_dai;
29*b86ef536SViorel Suman 	struct snd_soc_dai_link *dai;
30*b86ef536SViorel Suman 	int num_dai_conf;
31*b86ef536SViorel Suman 	struct snd_soc_codec_conf *dai_conf;
32*b86ef536SViorel Suman 	int num_dapm_routes;
33*b86ef536SViorel Suman 	struct snd_soc_dapm_route *dapm_routes;
34*b86ef536SViorel Suman };
35*b86ef536SViorel Suman 
36*b86ef536SViorel Suman static const u32 imx_audmix_rates[] = {
37*b86ef536SViorel Suman 	8000, 12000, 16000, 24000, 32000, 48000, 64000, 96000,
38*b86ef536SViorel Suman };
39*b86ef536SViorel Suman 
40*b86ef536SViorel Suman static const struct snd_pcm_hw_constraint_list imx_audmix_rate_constraints = {
41*b86ef536SViorel Suman 	.count = ARRAY_SIZE(imx_audmix_rates),
42*b86ef536SViorel Suman 	.list = imx_audmix_rates,
43*b86ef536SViorel Suman };
44*b86ef536SViorel Suman 
45*b86ef536SViorel Suman static int imx_audmix_fe_startup(struct snd_pcm_substream *substream)
46*b86ef536SViorel Suman {
47*b86ef536SViorel Suman 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
48*b86ef536SViorel Suman 	struct imx_audmix *priv = snd_soc_card_get_drvdata(rtd->card);
49*b86ef536SViorel Suman 	struct snd_pcm_runtime *runtime = substream->runtime;
50*b86ef536SViorel Suman 	struct device *dev = rtd->card->dev;
51*b86ef536SViorel Suman 	unsigned long clk_rate = clk_get_rate(priv->cpu_mclk);
52*b86ef536SViorel Suman 	int ret;
53*b86ef536SViorel Suman 
54*b86ef536SViorel Suman 	if (clk_rate % 24576000 == 0) {
55*b86ef536SViorel Suman 		ret = snd_pcm_hw_constraint_list(runtime, 0,
56*b86ef536SViorel Suman 						 SNDRV_PCM_HW_PARAM_RATE,
57*b86ef536SViorel Suman 						 &imx_audmix_rate_constraints);
58*b86ef536SViorel Suman 		if (ret < 0)
59*b86ef536SViorel Suman 			return ret;
60*b86ef536SViorel Suman 	} else {
61*b86ef536SViorel Suman 		dev_warn(dev, "mclk may be not supported %lu\n", clk_rate);
62*b86ef536SViorel Suman 	}
63*b86ef536SViorel Suman 
64*b86ef536SViorel Suman 	ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
65*b86ef536SViorel Suman 					   1, 8);
66*b86ef536SViorel Suman 	if (ret < 0)
67*b86ef536SViorel Suman 		return ret;
68*b86ef536SViorel Suman 
69*b86ef536SViorel Suman 	return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,
70*b86ef536SViorel Suman 					    FSL_AUDMIX_FORMATS);
71*b86ef536SViorel Suman }
72*b86ef536SViorel Suman 
73*b86ef536SViorel Suman static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream,
74*b86ef536SViorel Suman 				   struct snd_pcm_hw_params *params)
75*b86ef536SViorel Suman {
76*b86ef536SViorel Suman 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
77*b86ef536SViorel Suman 	struct device *dev = rtd->card->dev;
78*b86ef536SViorel Suman 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
79*b86ef536SViorel Suman 	unsigned int fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF;
80*b86ef536SViorel Suman 	u32 channels = params_channels(params);
81*b86ef536SViorel Suman 	int ret, dir;
82*b86ef536SViorel Suman 
83*b86ef536SViorel Suman 	/* For playback the AUDMIX is slave, and for record is master */
84*b86ef536SViorel Suman 	fmt |= tx ? SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
85*b86ef536SViorel Suman 	dir  = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN;
86*b86ef536SViorel Suman 
87*b86ef536SViorel Suman 	/* set DAI configuration */
88*b86ef536SViorel Suman 	ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
89*b86ef536SViorel Suman 	if (ret) {
90*b86ef536SViorel Suman 		dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
91*b86ef536SViorel Suman 		return ret;
92*b86ef536SViorel Suman 	}
93*b86ef536SViorel Suman 
94*b86ef536SViorel Suman 	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, FSL_SAI_CLK_MAST1, 0, dir);
95*b86ef536SViorel Suman 	if (ret) {
96*b86ef536SViorel Suman 		dev_err(dev, "failed to set cpu sysclk: %d\n", ret);
97*b86ef536SViorel Suman 		return ret;
98*b86ef536SViorel Suman 	}
99*b86ef536SViorel Suman 
100*b86ef536SViorel Suman 	/*
101*b86ef536SViorel Suman 	 * Per datasheet, AUDMIX expects 8 slots and 32 bits
102*b86ef536SViorel Suman 	 * for every slot in TDM mode.
103*b86ef536SViorel Suman 	 */
104*b86ef536SViorel Suman 	ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, BIT(channels) - 1,
105*b86ef536SViorel Suman 				       BIT(channels) - 1, 8, 32);
106*b86ef536SViorel Suman 	if (ret)
107*b86ef536SViorel Suman 		dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
108*b86ef536SViorel Suman 
109*b86ef536SViorel Suman 	return ret;
110*b86ef536SViorel Suman }
111*b86ef536SViorel Suman 
112*b86ef536SViorel Suman static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream,
113*b86ef536SViorel Suman 				   struct snd_pcm_hw_params *params)
114*b86ef536SViorel Suman {
115*b86ef536SViorel Suman 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
116*b86ef536SViorel Suman 	struct device *dev = rtd->card->dev;
117*b86ef536SViorel Suman 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
118*b86ef536SViorel Suman 	unsigned int fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF;
119*b86ef536SViorel Suman 	int ret;
120*b86ef536SViorel Suman 
121*b86ef536SViorel Suman 	if (!tx)
122*b86ef536SViorel Suman 		return 0;
123*b86ef536SViorel Suman 
124*b86ef536SViorel Suman 	/* For playback the AUDMIX is slave */
125*b86ef536SViorel Suman 	fmt |= SND_SOC_DAIFMT_CBM_CFM;
126*b86ef536SViorel Suman 
127*b86ef536SViorel Suman 	/* set AUDMIX DAI configuration */
128*b86ef536SViorel Suman 	ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
129*b86ef536SViorel Suman 	if (ret)
130*b86ef536SViorel Suman 		dev_err(dev, "failed to set AUDMIX DAI fmt: %d\n", ret);
131*b86ef536SViorel Suman 
132*b86ef536SViorel Suman 	return ret;
133*b86ef536SViorel Suman }
134*b86ef536SViorel Suman 
135*b86ef536SViorel Suman static struct snd_soc_ops imx_audmix_fe_ops = {
136*b86ef536SViorel Suman 	.startup = imx_audmix_fe_startup,
137*b86ef536SViorel Suman 	.hw_params = imx_audmix_fe_hw_params,
138*b86ef536SViorel Suman };
139*b86ef536SViorel Suman 
140*b86ef536SViorel Suman static struct snd_soc_ops imx_audmix_be_ops = {
141*b86ef536SViorel Suman 	.hw_params = imx_audmix_be_hw_params,
142*b86ef536SViorel Suman };
143*b86ef536SViorel Suman 
144*b86ef536SViorel Suman static int imx_audmix_probe(struct platform_device *pdev)
145*b86ef536SViorel Suman {
146*b86ef536SViorel Suman 	struct device_node *np = pdev->dev.of_node;
147*b86ef536SViorel Suman 	struct device_node *audmix_np = NULL, *out_cpu_np = NULL;
148*b86ef536SViorel Suman 	struct platform_device *audmix_pdev = NULL;
149*b86ef536SViorel Suman 	struct platform_device *cpu_pdev;
150*b86ef536SViorel Suman 	struct of_phandle_args args;
151*b86ef536SViorel Suman 	struct imx_audmix *priv;
152*b86ef536SViorel Suman 	int i, num_dai, ret;
153*b86ef536SViorel Suman 	const char *fe_name_pref = "HiFi-AUDMIX-FE-";
154*b86ef536SViorel Suman 	char *be_name, *be_pb, *be_cp, *dai_name, *capture_dai_name;
155*b86ef536SViorel Suman 
156*b86ef536SViorel Suman 	if (pdev->dev.parent) {
157*b86ef536SViorel Suman 		audmix_np = pdev->dev.parent->of_node;
158*b86ef536SViorel Suman 	} else {
159*b86ef536SViorel Suman 		dev_err(&pdev->dev, "Missing parent device.\n");
160*b86ef536SViorel Suman 		return -EINVAL;
161*b86ef536SViorel Suman 	}
162*b86ef536SViorel Suman 
163*b86ef536SViorel Suman 	if (!audmix_np) {
164*b86ef536SViorel Suman 		dev_err(&pdev->dev, "Missign DT node for parent device.\n");
165*b86ef536SViorel Suman 		return -EINVAL;
166*b86ef536SViorel Suman 	}
167*b86ef536SViorel Suman 
168*b86ef536SViorel Suman 	audmix_pdev = of_find_device_by_node(audmix_np);
169*b86ef536SViorel Suman 	if (!audmix_pdev) {
170*b86ef536SViorel Suman 		dev_err(&pdev->dev, "Missing AUDMIX platform device for %s\n",
171*b86ef536SViorel Suman 			np->full_name);
172*b86ef536SViorel Suman 		return -EINVAL;
173*b86ef536SViorel Suman 	}
174*b86ef536SViorel Suman 
175*b86ef536SViorel Suman 	num_dai = of_count_phandle_with_args(audmix_np, "dais", NULL);
176*b86ef536SViorel Suman 	if (num_dai != FSL_AUDMIX_MAX_DAIS) {
177*b86ef536SViorel Suman 		dev_err(&pdev->dev, "Need 2 dais to be provided for %s\n",
178*b86ef536SViorel Suman 			audmix_np->full_name);
179*b86ef536SViorel Suman 		return -EINVAL;
180*b86ef536SViorel Suman 	}
181*b86ef536SViorel Suman 
182*b86ef536SViorel Suman 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
183*b86ef536SViorel Suman 	if (!priv)
184*b86ef536SViorel Suman 		return -ENOMEM;
185*b86ef536SViorel Suman 
186*b86ef536SViorel Suman 	priv->num_dai = 2 * num_dai;
187*b86ef536SViorel Suman 	priv->dai = devm_kzalloc(&pdev->dev, priv->num_dai *
188*b86ef536SViorel Suman 				 sizeof(struct snd_soc_dai_link), GFP_KERNEL);
189*b86ef536SViorel Suman 	if (!priv->dai)
190*b86ef536SViorel Suman 		return -ENOMEM;
191*b86ef536SViorel Suman 
192*b86ef536SViorel Suman 	priv->num_dai_conf = num_dai;
193*b86ef536SViorel Suman 	priv->dai_conf = devm_kzalloc(&pdev->dev, priv->num_dai_conf *
194*b86ef536SViorel Suman 				      sizeof(struct snd_soc_codec_conf),
195*b86ef536SViorel Suman 				      GFP_KERNEL);
196*b86ef536SViorel Suman 	if (!priv->dai_conf)
197*b86ef536SViorel Suman 		return -ENOMEM;
198*b86ef536SViorel Suman 
199*b86ef536SViorel Suman 	priv->num_dapm_routes = 3 * num_dai;
200*b86ef536SViorel Suman 	priv->dapm_routes = devm_kzalloc(&pdev->dev, priv->num_dapm_routes *
201*b86ef536SViorel Suman 					 sizeof(struct snd_soc_dapm_route),
202*b86ef536SViorel Suman 					 GFP_KERNEL);
203*b86ef536SViorel Suman 	if (!priv->dapm_routes)
204*b86ef536SViorel Suman 		return -ENOMEM;
205*b86ef536SViorel Suman 
206*b86ef536SViorel Suman 	for (i = 0; i < num_dai; i++) {
207*b86ef536SViorel Suman 		ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i,
208*b86ef536SViorel Suman 						 &args);
209*b86ef536SViorel Suman 		if (ret < 0) {
210*b86ef536SViorel Suman 			dev_err(&pdev->dev, "of_parse_phandle_with_args failed\n");
211*b86ef536SViorel Suman 			return ret;
212*b86ef536SViorel Suman 		}
213*b86ef536SViorel Suman 
214*b86ef536SViorel Suman 		cpu_pdev = of_find_device_by_node(args.np);
215*b86ef536SViorel Suman 		if (!cpu_pdev) {
216*b86ef536SViorel Suman 			dev_err(&pdev->dev, "failed to find SAI platform device\n");
217*b86ef536SViorel Suman 			return -EINVAL;
218*b86ef536SViorel Suman 		}
219*b86ef536SViorel Suman 
220*b86ef536SViorel Suman 		dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%s",
221*b86ef536SViorel Suman 					  fe_name_pref, args.np->full_name + 1);
222*b86ef536SViorel Suman 
223*b86ef536SViorel Suman 		dev_info(pdev->dev.parent, "DAI FE name:%s\n", dai_name);
224*b86ef536SViorel Suman 
225*b86ef536SViorel Suman 		if (i == 0) {
226*b86ef536SViorel Suman 			out_cpu_np = args.np;
227*b86ef536SViorel Suman 			capture_dai_name =
228*b86ef536SViorel Suman 				devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
229*b86ef536SViorel Suman 					       dai_name, "CPU-Capture");
230*b86ef536SViorel Suman 		}
231*b86ef536SViorel Suman 
232*b86ef536SViorel Suman 		priv->dai[i].name = dai_name;
233*b86ef536SViorel Suman 		priv->dai[i].stream_name = "HiFi-AUDMIX-FE";
234*b86ef536SViorel Suman 		priv->dai[i].codec_dai_name = "snd-soc-dummy-dai";
235*b86ef536SViorel Suman 		priv->dai[i].codec_name = "snd-soc-dummy";
236*b86ef536SViorel Suman 		priv->dai[i].cpu_of_node = args.np;
237*b86ef536SViorel Suman 		priv->dai[i].cpu_dai_name = dev_name(&cpu_pdev->dev);
238*b86ef536SViorel Suman 		priv->dai[i].platform_of_node = args.np;
239*b86ef536SViorel Suman 		priv->dai[i].dynamic = 1;
240*b86ef536SViorel Suman 		priv->dai[i].dpcm_playback = 1;
241*b86ef536SViorel Suman 		priv->dai[i].dpcm_capture = (i == 0 ? 1 : 0);
242*b86ef536SViorel Suman 		priv->dai[i].ignore_pmdown_time = 1;
243*b86ef536SViorel Suman 		priv->dai[i].ops = &imx_audmix_fe_ops;
244*b86ef536SViorel Suman 
245*b86ef536SViorel Suman 		/* Add AUDMIX Backend */
246*b86ef536SViorel Suman 		be_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
247*b86ef536SViorel Suman 					 "audmix-%d", i);
248*b86ef536SViorel Suman 		be_pb = devm_kasprintf(&pdev->dev, GFP_KERNEL,
249*b86ef536SViorel Suman 				       "AUDMIX-Playback-%d", i);
250*b86ef536SViorel Suman 		be_cp = devm_kasprintf(&pdev->dev, GFP_KERNEL,
251*b86ef536SViorel Suman 				       "AUDMIX-Capture-%d", i);
252*b86ef536SViorel Suman 
253*b86ef536SViorel Suman 		priv->dai[num_dai + i].name = be_name;
254*b86ef536SViorel Suman 		priv->dai[num_dai + i].codec_dai_name = "snd-soc-dummy-dai";
255*b86ef536SViorel Suman 		priv->dai[num_dai + i].codec_name = "snd-soc-dummy";
256*b86ef536SViorel Suman 		priv->dai[num_dai + i].cpu_of_node = audmix_np;
257*b86ef536SViorel Suman 		priv->dai[num_dai + i].cpu_dai_name = be_name;
258*b86ef536SViorel Suman 		priv->dai[num_dai + i].platform_name = "snd-soc-dummy";
259*b86ef536SViorel Suman 		priv->dai[num_dai + i].no_pcm = 1;
260*b86ef536SViorel Suman 		priv->dai[num_dai + i].dpcm_playback = 1;
261*b86ef536SViorel Suman 		priv->dai[num_dai + i].dpcm_capture  = 1;
262*b86ef536SViorel Suman 		priv->dai[num_dai + i].ignore_pmdown_time = 1;
263*b86ef536SViorel Suman 		priv->dai[num_dai + i].ops = &imx_audmix_be_ops;
264*b86ef536SViorel Suman 
265*b86ef536SViorel Suman 		priv->dai_conf[i].of_node = args.np;
266*b86ef536SViorel Suman 		priv->dai_conf[i].name_prefix = dai_name;
267*b86ef536SViorel Suman 
268*b86ef536SViorel Suman 		priv->dapm_routes[i].source =
269*b86ef536SViorel Suman 			devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
270*b86ef536SViorel Suman 				       dai_name, "CPU-Playback");
271*b86ef536SViorel Suman 		priv->dapm_routes[i].sink = be_pb;
272*b86ef536SViorel Suman 		priv->dapm_routes[num_dai + i].source   = be_pb;
273*b86ef536SViorel Suman 		priv->dapm_routes[num_dai + i].sink     = be_cp;
274*b86ef536SViorel Suman 		priv->dapm_routes[2 * num_dai + i].source = be_cp;
275*b86ef536SViorel Suman 		priv->dapm_routes[2 * num_dai + i].sink   = capture_dai_name;
276*b86ef536SViorel Suman 	}
277*b86ef536SViorel Suman 
278*b86ef536SViorel Suman 	cpu_pdev = of_find_device_by_node(out_cpu_np);
279*b86ef536SViorel Suman 	if (!cpu_pdev) {
280*b86ef536SViorel Suman 		dev_err(&pdev->dev, "failed to find SAI platform device\n");
281*b86ef536SViorel Suman 		return -EINVAL;
282*b86ef536SViorel Suman 	}
283*b86ef536SViorel Suman 	priv->cpu_mclk = devm_clk_get(&cpu_pdev->dev, "mclk1");
284*b86ef536SViorel Suman 	if (IS_ERR(priv->cpu_mclk)) {
285*b86ef536SViorel Suman 		ret = PTR_ERR(priv->cpu_mclk);
286*b86ef536SViorel Suman 		dev_err(&cpu_pdev->dev, "failed to get DAI mclk1: %d\n", ret);
287*b86ef536SViorel Suman 		return -EINVAL;
288*b86ef536SViorel Suman 	}
289*b86ef536SViorel Suman 
290*b86ef536SViorel Suman 	priv->audmix_pdev = audmix_pdev;
291*b86ef536SViorel Suman 	priv->out_pdev  = cpu_pdev;
292*b86ef536SViorel Suman 
293*b86ef536SViorel Suman 	priv->card.dai_link = priv->dai;
294*b86ef536SViorel Suman 	priv->card.num_links = priv->num_dai;
295*b86ef536SViorel Suman 	priv->card.codec_conf = priv->dai_conf;
296*b86ef536SViorel Suman 	priv->card.num_configs = priv->num_dai_conf;
297*b86ef536SViorel Suman 	priv->card.dapm_routes = priv->dapm_routes;
298*b86ef536SViorel Suman 	priv->card.num_dapm_routes = priv->num_dapm_routes;
299*b86ef536SViorel Suman 	priv->card.dev = pdev->dev.parent;
300*b86ef536SViorel Suman 	priv->card.owner = THIS_MODULE;
301*b86ef536SViorel Suman 	priv->card.name = "imx-audmix";
302*b86ef536SViorel Suman 
303*b86ef536SViorel Suman 	platform_set_drvdata(pdev, &priv->card);
304*b86ef536SViorel Suman 	snd_soc_card_set_drvdata(&priv->card, priv);
305*b86ef536SViorel Suman 
306*b86ef536SViorel Suman 	ret = devm_snd_soc_register_card(pdev->dev.parent, &priv->card);
307*b86ef536SViorel Suman 	if (ret) {
308*b86ef536SViorel Suman 		dev_err(&pdev->dev, "snd_soc_register_card failed\n");
309*b86ef536SViorel Suman 		return ret;
310*b86ef536SViorel Suman 	}
311*b86ef536SViorel Suman 
312*b86ef536SViorel Suman 	return ret;
313*b86ef536SViorel Suman }
314*b86ef536SViorel Suman 
315*b86ef536SViorel Suman static struct platform_driver imx_audmix_driver = {
316*b86ef536SViorel Suman 	.probe = imx_audmix_probe,
317*b86ef536SViorel Suman 	.driver = {
318*b86ef536SViorel Suman 		.name = "imx-audmix",
319*b86ef536SViorel Suman 		.pm = &snd_soc_pm_ops,
320*b86ef536SViorel Suman 	},
321*b86ef536SViorel Suman };
322*b86ef536SViorel Suman module_platform_driver(imx_audmix_driver);
323*b86ef536SViorel Suman 
324*b86ef536SViorel Suman MODULE_DESCRIPTION("NXP AUDMIX ASoC machine driver");
325*b86ef536SViorel Suman MODULE_AUTHOR("Viorel Suman <viorel.suman@nxp.com>");
326*b86ef536SViorel Suman MODULE_ALIAS("platform:imx-audmix");
327*b86ef536SViorel Suman MODULE_LICENSE("GPL v2");
328