xref: /openbmc/linux/sound/soc/samsung/bells.c (revision b3a6006e1d106fddcfc121d0ccfa9b7faeeb8f3e)
1b545dd92SMark Brown /*
2b545dd92SMark Brown  * Bells audio support
3b545dd92SMark Brown  *
4b545dd92SMark Brown  * Copyright 2012 Wolfson Microelectronics
5b545dd92SMark Brown  *
6b545dd92SMark Brown  * This program is free software; you can redistribute  it and/or modify it
7b545dd92SMark Brown  * under  the terms of  the GNU General  Public License as published by the
8b545dd92SMark Brown  * Free Software Foundation;  either version 2 of the  License, or (at your
9b545dd92SMark Brown  * option) any later version.
10b545dd92SMark Brown  */
11b545dd92SMark Brown 
12b545dd92SMark Brown #include <sound/soc.h>
13b545dd92SMark Brown #include <sound/soc-dapm.h>
14b545dd92SMark Brown #include <sound/jack.h>
15b545dd92SMark Brown #include <linux/gpio.h>
16b545dd92SMark Brown #include <linux/module.h>
17b545dd92SMark Brown 
18b545dd92SMark Brown #include "../codecs/wm5102.h"
19b545dd92SMark Brown #include "../codecs/wm9081.h"
20b545dd92SMark Brown 
21b545dd92SMark Brown /* BCLK2 is fixed at this currently */
22b545dd92SMark Brown #define BCLK2_RATE (64 * 8000)
23b545dd92SMark Brown 
24b545dd92SMark Brown /*
25b545dd92SMark Brown  * Expect a 24.576MHz crystal if one is fitted (the driver will function
26b545dd92SMark Brown  * if this is not fitted).
27b545dd92SMark Brown  */
28b545dd92SMark Brown #define MCLK_RATE 24576000
29b545dd92SMark Brown 
30344c5edeSMark Brown #define SYS_AUDIO_RATE 44100
31208229ecSDimitris Papastamos #define SYS_MCLK_RATE  (SYS_AUDIO_RATE * 512)
32344c5edeSMark Brown 
33344c5edeSMark Brown #define DAI_AP_DSP    0
34344c5edeSMark Brown #define DAI_DSP_CODEC 1
35344c5edeSMark Brown #define DAI_CODEC_CP  2
36344c5edeSMark Brown #define DAI_CODEC_SUB 3
37b545dd92SMark Brown 
38b1387078SMark Brown struct bells_drvdata {
39b1387078SMark Brown 	int sysclk_rate;
40b1387078SMark Brown 	int asyncclk_rate;
41b1387078SMark Brown };
42b1387078SMark Brown 
438d47e8a5SMark Brown static struct bells_drvdata wm2200_drvdata = {
448d47e8a5SMark Brown 	.sysclk_rate = 22579200,
458d47e8a5SMark Brown };
468d47e8a5SMark Brown 
47b1387078SMark Brown static struct bells_drvdata wm5102_drvdata = {
48b1387078SMark Brown 	.sysclk_rate = 45158400,
49b1387078SMark Brown 	.asyncclk_rate = 49152000,
50b1387078SMark Brown };
51b1387078SMark Brown 
52b1387078SMark Brown static struct bells_drvdata wm5110_drvdata = {
53b1387078SMark Brown 	.sysclk_rate = 135475200,
54b1387078SMark Brown 	.asyncclk_rate = 147456000,
55b1387078SMark Brown };
56b1387078SMark Brown 
57b545dd92SMark Brown static int bells_set_bias_level(struct snd_soc_card *card,
58b545dd92SMark Brown 				struct snd_soc_dapm_context *dapm,
59b545dd92SMark Brown 				enum snd_soc_bias_level level)
60b545dd92SMark Brown {
61344c5edeSMark Brown 	struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
62b545dd92SMark Brown 	struct snd_soc_codec *codec = codec_dai->codec;
63b1387078SMark Brown 	struct bells_drvdata *bells = card->drvdata;
64b545dd92SMark Brown 	int ret;
65b545dd92SMark Brown 
66b545dd92SMark Brown 	if (dapm->dev != codec_dai->dev)
67b545dd92SMark Brown 		return 0;
68b545dd92SMark Brown 
69b545dd92SMark Brown 	switch (level) {
70b545dd92SMark Brown 	case SND_SOC_BIAS_PREPARE:
71b1387078SMark Brown 		if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
72b1387078SMark Brown 			break;
73b1387078SMark Brown 
74b545dd92SMark Brown 		ret = snd_soc_codec_set_pll(codec, WM5102_FLL1,
75b545dd92SMark Brown 					    ARIZONA_FLL_SRC_MCLK1,
76b545dd92SMark Brown 					    MCLK_RATE,
77b1387078SMark Brown 					    bells->sysclk_rate);
78b545dd92SMark Brown 		if (ret < 0)
79b545dd92SMark Brown 			pr_err("Failed to start FLL: %d\n", ret);
80b545dd92SMark Brown 
81b1387078SMark Brown 		if (bells->asyncclk_rate) {
82b545dd92SMark Brown 			ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
83b545dd92SMark Brown 						    ARIZONA_FLL_SRC_AIF2BCLK,
84b545dd92SMark Brown 						    BCLK2_RATE,
85b1387078SMark Brown 						    bells->asyncclk_rate);
86b545dd92SMark Brown 			if (ret < 0)
87b545dd92SMark Brown 				pr_err("Failed to start FLL: %d\n", ret);
88b545dd92SMark Brown 		}
89b545dd92SMark Brown 		break;
90b545dd92SMark Brown 
91b545dd92SMark Brown 	default:
92b545dd92SMark Brown 		break;
93b545dd92SMark Brown 	}
94b545dd92SMark Brown 
95b545dd92SMark Brown 	return 0;
96b545dd92SMark Brown }
97b545dd92SMark Brown 
98b545dd92SMark Brown static int bells_set_bias_level_post(struct snd_soc_card *card,
99b545dd92SMark Brown 				     struct snd_soc_dapm_context *dapm,
100b545dd92SMark Brown 				     enum snd_soc_bias_level level)
101b545dd92SMark Brown {
102344c5edeSMark Brown 	struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
103b545dd92SMark Brown 	struct snd_soc_codec *codec = codec_dai->codec;
104b1387078SMark Brown 	struct bells_drvdata *bells = card->drvdata;
105b545dd92SMark Brown 	int ret;
106b545dd92SMark Brown 
107b545dd92SMark Brown 	if (dapm->dev != codec_dai->dev)
108b545dd92SMark Brown 		return 0;
109b545dd92SMark Brown 
110b545dd92SMark Brown 	switch (level) {
111b545dd92SMark Brown 	case SND_SOC_BIAS_STANDBY:
112b545dd92SMark Brown 		ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0);
113b545dd92SMark Brown 		if (ret < 0) {
114b545dd92SMark Brown 			pr_err("Failed to stop FLL: %d\n", ret);
115b545dd92SMark Brown 			return ret;
116b545dd92SMark Brown 		}
117b545dd92SMark Brown 
118b1387078SMark Brown 		if (bells->asyncclk_rate) {
119b1387078SMark Brown 			ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
120b1387078SMark Brown 						    0, 0, 0);
121b545dd92SMark Brown 			if (ret < 0) {
122b545dd92SMark Brown 				pr_err("Failed to stop FLL: %d\n", ret);
123b545dd92SMark Brown 				return ret;
124b545dd92SMark Brown 			}
125b1387078SMark Brown 		}
126b545dd92SMark Brown 		break;
127b545dd92SMark Brown 
128b545dd92SMark Brown 	default:
129b545dd92SMark Brown 		break;
130b545dd92SMark Brown 	}
131b545dd92SMark Brown 
132b545dd92SMark Brown 	dapm->bias_level = level;
133b545dd92SMark Brown 
134b545dd92SMark Brown 	return 0;
135b545dd92SMark Brown }
136b545dd92SMark Brown 
137b545dd92SMark Brown static int bells_late_probe(struct snd_soc_card *card)
138b545dd92SMark Brown {
139b1387078SMark Brown 	struct bells_drvdata *bells = card->drvdata;
140344c5edeSMark Brown 	struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec;
141344c5edeSMark Brown 	struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec;
142344c5edeSMark Brown 	struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
143b1387078SMark Brown 	struct snd_soc_dai *aif2_dai;
144b1387078SMark Brown 	struct snd_soc_dai *aif3_dai;
145b1387078SMark Brown 	struct snd_soc_dai *wm9081_dai;
146b545dd92SMark Brown 	int ret;
147b545dd92SMark Brown 
148b1387078SMark Brown 	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
149b1387078SMark Brown 				       ARIZONA_CLK_SRC_FLL1,
150b1387078SMark Brown 				       bells->sysclk_rate,
151b1387078SMark Brown 				       SND_SOC_CLOCK_IN);
152b1387078SMark Brown 	if (ret != 0) {
153b1387078SMark Brown 		dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
154b1387078SMark Brown 		return ret;
155b1387078SMark Brown 	}
156b1387078SMark Brown 
157344c5edeSMark Brown 	ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0);
158344c5edeSMark Brown 	if (ret != 0) {
159344c5edeSMark Brown 		dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret);
160344c5edeSMark Brown 		return ret;
161344c5edeSMark Brown 	}
162344c5edeSMark Brown 
163b545dd92SMark Brown 	ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
164b1387078SMark Brown 	if (ret != 0)
165b545dd92SMark Brown 		dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
166b1387078SMark Brown 
167b1387078SMark Brown 	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0,
168b1387078SMark Brown 				       SYS_MCLK_RATE, SND_SOC_CLOCK_OUT);
169b1387078SMark Brown 	if (ret != 0)
170b1387078SMark Brown 		dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret);
171b1387078SMark Brown 
172b1387078SMark Brown 	if (card->num_rtd == DAI_CODEC_CP)
173b1387078SMark Brown 		return 0;
174b1387078SMark Brown 
175b1387078SMark Brown 	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
176b1387078SMark Brown 				       ARIZONA_CLK_SRC_FLL2,
177b1387078SMark Brown 				       bells->asyncclk_rate,
178b1387078SMark Brown 				       SND_SOC_CLOCK_IN);
179b1387078SMark Brown 	if (ret != 0) {
180b1387078SMark Brown 		dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret);
181b545dd92SMark Brown 		return ret;
182b545dd92SMark Brown 	}
183b545dd92SMark Brown 
184b1387078SMark Brown 	aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai;
185b1387078SMark Brown 
186b545dd92SMark Brown 	ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
187b545dd92SMark Brown 	if (ret != 0) {
188b545dd92SMark Brown 		dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret);
189b545dd92SMark Brown 		return ret;
190b545dd92SMark Brown 	}
191b545dd92SMark Brown 
192b1387078SMark Brown 	if (card->num_rtd == DAI_CODEC_SUB)
193b1387078SMark Brown 		return 0;
194b1387078SMark Brown 
195b1387078SMark Brown 	aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai;
196b1387078SMark Brown 	wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai;
197b1387078SMark Brown 
198b545dd92SMark Brown 	ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
199b545dd92SMark Brown 	if (ret != 0) {
200b545dd92SMark Brown 		dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
201b545dd92SMark Brown 		return ret;
202b545dd92SMark Brown 	}
203b545dd92SMark Brown 
204b545dd92SMark Brown 	ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK,
205344c5edeSMark Brown 				       0, SYS_MCLK_RATE, 0);
206b545dd92SMark Brown 	if (ret != 0) {
207b545dd92SMark Brown 		dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret);
208b545dd92SMark Brown 		return ret;
209b545dd92SMark Brown 	}
210b545dd92SMark Brown 
211b545dd92SMark Brown 	return 0;
212b545dd92SMark Brown }
213b545dd92SMark Brown 
214b545dd92SMark Brown static const struct snd_soc_pcm_stream baseband_params = {
215b545dd92SMark Brown 	.formats = SNDRV_PCM_FMTBIT_S32_LE,
216b545dd92SMark Brown 	.rate_min = 8000,
217b545dd92SMark Brown 	.rate_max = 8000,
218b545dd92SMark Brown 	.channels_min = 2,
219b545dd92SMark Brown 	.channels_max = 2,
220b545dd92SMark Brown };
221b545dd92SMark Brown 
222b545dd92SMark Brown static const struct snd_soc_pcm_stream sub_params = {
223b545dd92SMark Brown 	.formats = SNDRV_PCM_FMTBIT_S32_LE,
224344c5edeSMark Brown 	.rate_min = SYS_AUDIO_RATE,
225344c5edeSMark Brown 	.rate_max = SYS_AUDIO_RATE,
226b545dd92SMark Brown 	.channels_min = 2,
227b545dd92SMark Brown 	.channels_max = 2,
228b545dd92SMark Brown };
229b545dd92SMark Brown 
2308d47e8a5SMark Brown static struct snd_soc_dai_link bells_dai_wm2200[] = {
2318d47e8a5SMark Brown 	{
2328d47e8a5SMark Brown 		.name = "CPU-DSP",
2338d47e8a5SMark Brown 		.stream_name = "CPU-DSP",
2348d47e8a5SMark Brown 		.cpu_dai_name = "samsung-i2s.0",
2358d47e8a5SMark Brown 		.codec_dai_name = "wm0010-sdi1",
236a08485d8SPadmavathi Venna 		.platform_name = "samsung-i2s.0",
2378d47e8a5SMark Brown 		.codec_name = "spi0.0",
2388d47e8a5SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
2398d47e8a5SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
2408d47e8a5SMark Brown 	},
2418d47e8a5SMark Brown 	{
2428d47e8a5SMark Brown 		.name = "DSP-CODEC",
2438d47e8a5SMark Brown 		.stream_name = "DSP-CODEC",
2448d47e8a5SMark Brown 		.cpu_dai_name = "wm0010-sdi2",
2458d47e8a5SMark Brown 		.codec_dai_name = "wm2200",
2468d47e8a5SMark Brown 		.codec_name = "wm2200.1-003a",
2478d47e8a5SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
2488d47e8a5SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
2498d47e8a5SMark Brown 		.params = &sub_params,
2508d47e8a5SMark Brown 		.ignore_suspend = 1,
2518d47e8a5SMark Brown 	},
2528d47e8a5SMark Brown };
2538d47e8a5SMark Brown 
254b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5102[] = {
255b545dd92SMark Brown 	{
256344c5edeSMark Brown 		.name = "CPU-DSP",
257344c5edeSMark Brown 		.stream_name = "CPU-DSP",
258b545dd92SMark Brown 		.cpu_dai_name = "samsung-i2s.0",
259344c5edeSMark Brown 		.codec_dai_name = "wm0010-sdi1",
260a08485d8SPadmavathi Venna 		.platform_name = "samsung-i2s.0",
261344c5edeSMark Brown 		.codec_name = "spi0.0",
262344c5edeSMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
263344c5edeSMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
264344c5edeSMark Brown 	},
265344c5edeSMark Brown 	{
266344c5edeSMark Brown 		.name = "DSP-CODEC",
267344c5edeSMark Brown 		.stream_name = "DSP-CODEC",
268344c5edeSMark Brown 		.cpu_dai_name = "wm0010-sdi2",
269344c5edeSMark Brown 		.codec_dai_name = "wm5102-aif1",
270b545dd92SMark Brown 		.codec_name = "wm5102-codec",
271b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
272b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
273344c5edeSMark Brown 		.params = &sub_params,
274344c5edeSMark Brown 		.ignore_suspend = 1,
275b545dd92SMark Brown 	},
276b545dd92SMark Brown 	{
277b545dd92SMark Brown 		.name = "Baseband",
278b545dd92SMark Brown 		.stream_name = "Baseband",
279b545dd92SMark Brown 		.cpu_dai_name = "wm5102-aif2",
280b545dd92SMark Brown 		.codec_dai_name = "wm1250-ev1",
281b545dd92SMark Brown 		.codec_name = "wm1250-ev1.1-0027",
282b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
283b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
284b545dd92SMark Brown 		.ignore_suspend = 1,
285b545dd92SMark Brown 		.params = &baseband_params,
286b545dd92SMark Brown 	},
287b545dd92SMark Brown 	{
288b545dd92SMark Brown 		.name = "Sub",
289b545dd92SMark Brown 		.stream_name = "Sub",
290b545dd92SMark Brown 		.cpu_dai_name = "wm5102-aif3",
291b545dd92SMark Brown 		.codec_dai_name = "wm9081-hifi",
292b545dd92SMark Brown 		.codec_name = "wm9081.1-006c",
293b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
294b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBS_CFS,
295b545dd92SMark Brown 		.ignore_suspend = 1,
296b545dd92SMark Brown 		.params = &sub_params,
297b545dd92SMark Brown 	},
298b545dd92SMark Brown };
299b545dd92SMark Brown 
300b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5110[] = {
301b545dd92SMark Brown 	{
302344c5edeSMark Brown 		.name = "CPU-DSP",
303344c5edeSMark Brown 		.stream_name = "CPU-DSP",
304b545dd92SMark Brown 		.cpu_dai_name = "samsung-i2s.0",
305344c5edeSMark Brown 		.codec_dai_name = "wm0010-sdi1",
306a08485d8SPadmavathi Venna 		.platform_name = "samsung-i2s.0",
307344c5edeSMark Brown 		.codec_name = "spi0.0",
308344c5edeSMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
309344c5edeSMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
310344c5edeSMark Brown 	},
311344c5edeSMark Brown 	{
312344c5edeSMark Brown 		.name = "DSP-CODEC",
313344c5edeSMark Brown 		.stream_name = "DSP-CODEC",
314344c5edeSMark Brown 		.cpu_dai_name = "wm0010-sdi2",
315344c5edeSMark Brown 		.codec_dai_name = "wm5110-aif1",
316b545dd92SMark Brown 		.codec_name = "wm5110-codec",
317b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
318b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
319344c5edeSMark Brown 		.params = &sub_params,
320344c5edeSMark Brown 		.ignore_suspend = 1,
321b545dd92SMark Brown 	},
322b545dd92SMark Brown 	{
323b545dd92SMark Brown 		.name = "Baseband",
324b545dd92SMark Brown 		.stream_name = "Baseband",
325b545dd92SMark Brown 		.cpu_dai_name = "wm5110-aif2",
326b545dd92SMark Brown 		.codec_dai_name = "wm1250-ev1",
327b545dd92SMark Brown 		.codec_name = "wm1250-ev1.1-0027",
328b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
329b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
330b545dd92SMark Brown 		.ignore_suspend = 1,
331b545dd92SMark Brown 		.params = &baseband_params,
332b545dd92SMark Brown 	},
333b545dd92SMark Brown 	{
334b545dd92SMark Brown 		.name = "Sub",
335b545dd92SMark Brown 		.stream_name = "Sub",
336ffaa839bSMark Brown 		.cpu_dai_name = "wm5110-aif3",
337b545dd92SMark Brown 		.codec_dai_name = "wm9081-hifi",
338b545dd92SMark Brown 		.codec_name = "wm9081.1-006c",
339b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
340b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBS_CFS,
341b545dd92SMark Brown 		.ignore_suspend = 1,
342b545dd92SMark Brown 		.params = &sub_params,
343b545dd92SMark Brown 	},
344b545dd92SMark Brown };
345b545dd92SMark Brown 
346b545dd92SMark Brown static struct snd_soc_codec_conf bells_codec_conf[] = {
347b545dd92SMark Brown 	{
348b545dd92SMark Brown 		.dev_name = "wm9081.1-006c",
349b545dd92SMark Brown 		.name_prefix = "Sub",
350b545dd92SMark Brown 	},
351b545dd92SMark Brown };
352b545dd92SMark Brown 
353939d3c6aSCharles Keepax static struct snd_soc_dapm_widget bells_widgets[] = {
354939d3c6aSCharles Keepax 	SND_SOC_DAPM_MIC("DMIC", NULL),
355939d3c6aSCharles Keepax };
356939d3c6aSCharles Keepax 
357b545dd92SMark Brown static struct snd_soc_dapm_route bells_routes[] = {
358b545dd92SMark Brown 	{ "Sub CLK_SYS", NULL, "OPCLK" },
359*b3a6006eSCharles Keepax 	{ "CLKIN", NULL, "OPCLK" },
360939d3c6aSCharles Keepax 
361939d3c6aSCharles Keepax 	{ "DMIC", NULL, "MICBIAS2" },
362939d3c6aSCharles Keepax 	{ "IN2L", NULL, "DMIC" },
363939d3c6aSCharles Keepax 	{ "IN2R", NULL, "DMIC" },
364b545dd92SMark Brown };
365b545dd92SMark Brown 
366b545dd92SMark Brown static struct snd_soc_card bells_cards[] = {
367b545dd92SMark Brown 	{
3688d47e8a5SMark Brown 		.name = "Bells WM2200",
3698d47e8a5SMark Brown 		.owner = THIS_MODULE,
3708d47e8a5SMark Brown 		.dai_link = bells_dai_wm2200,
3718d47e8a5SMark Brown 		.num_links = ARRAY_SIZE(bells_dai_wm2200),
3728d47e8a5SMark Brown 		.codec_conf = bells_codec_conf,
3738d47e8a5SMark Brown 		.num_configs = ARRAY_SIZE(bells_codec_conf),
3748d47e8a5SMark Brown 
3758d47e8a5SMark Brown 		.late_probe = bells_late_probe,
3768d47e8a5SMark Brown 
377939d3c6aSCharles Keepax 		.dapm_widgets = bells_widgets,
378939d3c6aSCharles Keepax 		.num_dapm_widgets = ARRAY_SIZE(bells_widgets),
3798d47e8a5SMark Brown 		.dapm_routes = bells_routes,
3808d47e8a5SMark Brown 		.num_dapm_routes = ARRAY_SIZE(bells_routes),
3818d47e8a5SMark Brown 
3828d47e8a5SMark Brown 		.set_bias_level = bells_set_bias_level,
3838d47e8a5SMark Brown 		.set_bias_level_post = bells_set_bias_level_post,
3848d47e8a5SMark Brown 
3858d47e8a5SMark Brown 		.drvdata = &wm2200_drvdata,
3868d47e8a5SMark Brown 	},
3878d47e8a5SMark Brown 	{
388b545dd92SMark Brown 		.name = "Bells WM5102",
389b545dd92SMark Brown 		.owner = THIS_MODULE,
390b545dd92SMark Brown 		.dai_link = bells_dai_wm5102,
391b545dd92SMark Brown 		.num_links = ARRAY_SIZE(bells_dai_wm5102),
392b545dd92SMark Brown 		.codec_conf = bells_codec_conf,
393b545dd92SMark Brown 		.num_configs = ARRAY_SIZE(bells_codec_conf),
394b545dd92SMark Brown 
395b545dd92SMark Brown 		.late_probe = bells_late_probe,
396b545dd92SMark Brown 
397939d3c6aSCharles Keepax 		.dapm_widgets = bells_widgets,
398939d3c6aSCharles Keepax 		.num_dapm_widgets = ARRAY_SIZE(bells_widgets),
399b545dd92SMark Brown 		.dapm_routes = bells_routes,
400b545dd92SMark Brown 		.num_dapm_routes = ARRAY_SIZE(bells_routes),
401b545dd92SMark Brown 
402b545dd92SMark Brown 		.set_bias_level = bells_set_bias_level,
403b545dd92SMark Brown 		.set_bias_level_post = bells_set_bias_level_post,
404b1387078SMark Brown 
405b1387078SMark Brown 		.drvdata = &wm5102_drvdata,
406b545dd92SMark Brown 	},
407b545dd92SMark Brown 	{
408b545dd92SMark Brown 		.name = "Bells WM5110",
409b545dd92SMark Brown 		.owner = THIS_MODULE,
410b545dd92SMark Brown 		.dai_link = bells_dai_wm5110,
411b545dd92SMark Brown 		.num_links = ARRAY_SIZE(bells_dai_wm5110),
412b545dd92SMark Brown 		.codec_conf = bells_codec_conf,
413b545dd92SMark Brown 		.num_configs = ARRAY_SIZE(bells_codec_conf),
414b545dd92SMark Brown 
415b545dd92SMark Brown 		.late_probe = bells_late_probe,
416b545dd92SMark Brown 
417939d3c6aSCharles Keepax 		.dapm_widgets = bells_widgets,
418939d3c6aSCharles Keepax 		.num_dapm_widgets = ARRAY_SIZE(bells_widgets),
419b545dd92SMark Brown 		.dapm_routes = bells_routes,
420b545dd92SMark Brown 		.num_dapm_routes = ARRAY_SIZE(bells_routes),
421b545dd92SMark Brown 
422b545dd92SMark Brown 		.set_bias_level = bells_set_bias_level,
423b545dd92SMark Brown 		.set_bias_level_post = bells_set_bias_level_post,
424b1387078SMark Brown 
425b1387078SMark Brown 		.drvdata = &wm5110_drvdata,
426b545dd92SMark Brown 	},
427b545dd92SMark Brown };
428b545dd92SMark Brown 
429b545dd92SMark Brown 
430fdca21adSBill Pemberton static int bells_probe(struct platform_device *pdev)
431b545dd92SMark Brown {
432b545dd92SMark Brown 	int ret;
433b545dd92SMark Brown 
434b545dd92SMark Brown 	bells_cards[pdev->id].dev = &pdev->dev;
435b545dd92SMark Brown 
436b545dd92SMark Brown 	ret = snd_soc_register_card(&bells_cards[pdev->id]);
437b545dd92SMark Brown 	if (ret) {
438b545dd92SMark Brown 		dev_err(&pdev->dev,
439b545dd92SMark Brown 			"snd_soc_register_card(%s) failed: %d\n",
440b545dd92SMark Brown 			bells_cards[pdev->id].name, ret);
441b545dd92SMark Brown 		return ret;
442b545dd92SMark Brown 	}
443b545dd92SMark Brown 
444b545dd92SMark Brown 	return 0;
445b545dd92SMark Brown }
446b545dd92SMark Brown 
447fdca21adSBill Pemberton static int bells_remove(struct platform_device *pdev)
448b545dd92SMark Brown {
449b545dd92SMark Brown 	snd_soc_unregister_card(&bells_cards[pdev->id]);
450b545dd92SMark Brown 
451b545dd92SMark Brown 	return 0;
452b545dd92SMark Brown }
453b545dd92SMark Brown 
454b545dd92SMark Brown static struct platform_driver bells_driver = {
455b545dd92SMark Brown 	.driver = {
456b545dd92SMark Brown 		.name = "bells",
457b545dd92SMark Brown 		.owner = THIS_MODULE,
458b545dd92SMark Brown 		.pm = &snd_soc_pm_ops,
459b545dd92SMark Brown 	},
460b545dd92SMark Brown 	.probe = bells_probe,
461fdca21adSBill Pemberton 	.remove = bells_remove,
462b545dd92SMark Brown };
463b545dd92SMark Brown 
464b545dd92SMark Brown module_platform_driver(bells_driver);
465b545dd92SMark Brown 
466b545dd92SMark Brown MODULE_DESCRIPTION("Bells audio support");
467b545dd92SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
468b545dd92SMark Brown MODULE_LICENSE("GPL");
469b545dd92SMark Brown MODULE_ALIAS("platform:bells");
470