xref: /openbmc/linux/sound/soc/samsung/bells.c (revision f4a2be1c559e53e31545bdea2c246dbce6b70e1c)
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 {
615015920aSMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
625015920aSMengdong Lin 	struct snd_soc_dai *codec_dai;
63*f4a2be1cSKuninori Morimoto 	struct snd_soc_component *component;
64b1387078SMark Brown 	struct bells_drvdata *bells = card->drvdata;
65b545dd92SMark Brown 	int ret;
66b545dd92SMark Brown 
675015920aSMengdong Lin 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
685015920aSMengdong Lin 	codec_dai = rtd->codec_dai;
69*f4a2be1cSKuninori Morimoto 	component = codec_dai->component;
705015920aSMengdong Lin 
71b545dd92SMark Brown 	if (dapm->dev != codec_dai->dev)
72b545dd92SMark Brown 		return 0;
73b545dd92SMark Brown 
74b545dd92SMark Brown 	switch (level) {
75b545dd92SMark Brown 	case SND_SOC_BIAS_PREPARE:
76b1387078SMark Brown 		if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
77b1387078SMark Brown 			break;
78b1387078SMark Brown 
79*f4a2be1cSKuninori Morimoto 		ret = snd_soc_component_set_pll(component, WM5102_FLL1,
80b545dd92SMark Brown 					    ARIZONA_FLL_SRC_MCLK1,
81b545dd92SMark Brown 					    MCLK_RATE,
82b1387078SMark Brown 					    bells->sysclk_rate);
83b545dd92SMark Brown 		if (ret < 0)
84b545dd92SMark Brown 			pr_err("Failed to start FLL: %d\n", ret);
85b545dd92SMark Brown 
86b1387078SMark Brown 		if (bells->asyncclk_rate) {
87*f4a2be1cSKuninori Morimoto 			ret = snd_soc_component_set_pll(component, WM5102_FLL2,
88b545dd92SMark Brown 						    ARIZONA_FLL_SRC_AIF2BCLK,
89b545dd92SMark Brown 						    BCLK2_RATE,
90b1387078SMark Brown 						    bells->asyncclk_rate);
91b545dd92SMark Brown 			if (ret < 0)
92b545dd92SMark Brown 				pr_err("Failed to start FLL: %d\n", ret);
93b545dd92SMark Brown 		}
94b545dd92SMark Brown 		break;
95b545dd92SMark Brown 
96b545dd92SMark Brown 	default:
97b545dd92SMark Brown 		break;
98b545dd92SMark Brown 	}
99b545dd92SMark Brown 
100b545dd92SMark Brown 	return 0;
101b545dd92SMark Brown }
102b545dd92SMark Brown 
103b545dd92SMark Brown static int bells_set_bias_level_post(struct snd_soc_card *card,
104b545dd92SMark Brown 				     struct snd_soc_dapm_context *dapm,
105b545dd92SMark Brown 				     enum snd_soc_bias_level level)
106b545dd92SMark Brown {
1075015920aSMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
1085015920aSMengdong Lin 	struct snd_soc_dai *codec_dai;
109*f4a2be1cSKuninori Morimoto 	struct snd_soc_component *component;
110b1387078SMark Brown 	struct bells_drvdata *bells = card->drvdata;
111b545dd92SMark Brown 	int ret;
112b545dd92SMark Brown 
1135015920aSMengdong Lin 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
1145015920aSMengdong Lin 	codec_dai = rtd->codec_dai;
115*f4a2be1cSKuninori Morimoto 	component = codec_dai->component;
1165015920aSMengdong Lin 
117b545dd92SMark Brown 	if (dapm->dev != codec_dai->dev)
118b545dd92SMark Brown 		return 0;
119b545dd92SMark Brown 
120b545dd92SMark Brown 	switch (level) {
121b545dd92SMark Brown 	case SND_SOC_BIAS_STANDBY:
122*f4a2be1cSKuninori Morimoto 		ret = snd_soc_component_set_pll(component, WM5102_FLL1, 0, 0, 0);
123b545dd92SMark Brown 		if (ret < 0) {
124b545dd92SMark Brown 			pr_err("Failed to stop FLL: %d\n", ret);
125b545dd92SMark Brown 			return ret;
126b545dd92SMark Brown 		}
127b545dd92SMark Brown 
128b1387078SMark Brown 		if (bells->asyncclk_rate) {
129*f4a2be1cSKuninori Morimoto 			ret = snd_soc_component_set_pll(component, WM5102_FLL2,
130b1387078SMark Brown 						    0, 0, 0);
131b545dd92SMark Brown 			if (ret < 0) {
132b545dd92SMark Brown 				pr_err("Failed to stop FLL: %d\n", ret);
133b545dd92SMark Brown 				return ret;
134b545dd92SMark Brown 			}
135b1387078SMark Brown 		}
136b545dd92SMark Brown 		break;
137b545dd92SMark Brown 
138b545dd92SMark Brown 	default:
139b545dd92SMark Brown 		break;
140b545dd92SMark Brown 	}
141b545dd92SMark Brown 
142b545dd92SMark Brown 	dapm->bias_level = level;
143b545dd92SMark Brown 
144b545dd92SMark Brown 	return 0;
145b545dd92SMark Brown }
146b545dd92SMark Brown 
147b545dd92SMark Brown static int bells_late_probe(struct snd_soc_card *card)
148b545dd92SMark Brown {
149b1387078SMark Brown 	struct bells_drvdata *bells = card->drvdata;
1505015920aSMengdong Lin 	struct snd_soc_pcm_runtime *rtd;
151*f4a2be1cSKuninori Morimoto 	struct snd_soc_component *wm0010;
152*f4a2be1cSKuninori Morimoto 	struct snd_soc_component *component;
1535015920aSMengdong Lin 	struct snd_soc_dai *aif1_dai;
154b1387078SMark Brown 	struct snd_soc_dai *aif2_dai;
155b1387078SMark Brown 	struct snd_soc_dai *aif3_dai;
156b1387078SMark Brown 	struct snd_soc_dai *wm9081_dai;
157b545dd92SMark Brown 	int ret;
158b545dd92SMark Brown 
1595015920aSMengdong Lin 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name);
160*f4a2be1cSKuninori Morimoto 	wm0010 = rtd->codec_dai->component;
1615015920aSMengdong Lin 
1625015920aSMengdong Lin 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
163*f4a2be1cSKuninori Morimoto 	component = rtd->codec_dai->component;
1645015920aSMengdong Lin 	aif1_dai = rtd->codec_dai;
1655015920aSMengdong Lin 
166*f4a2be1cSKuninori Morimoto 	ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
167b1387078SMark Brown 				       ARIZONA_CLK_SRC_FLL1,
168b1387078SMark Brown 				       bells->sysclk_rate,
169b1387078SMark Brown 				       SND_SOC_CLOCK_IN);
170b1387078SMark Brown 	if (ret != 0) {
171*f4a2be1cSKuninori Morimoto 		dev_err(component->dev, "Failed to set SYSCLK: %d\n", ret);
172b1387078SMark Brown 		return ret;
173b1387078SMark Brown 	}
174b1387078SMark Brown 
175*f4a2be1cSKuninori Morimoto 	ret = snd_soc_component_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0);
176344c5edeSMark Brown 	if (ret != 0) {
177344c5edeSMark Brown 		dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret);
178344c5edeSMark Brown 		return ret;
179344c5edeSMark Brown 	}
180344c5edeSMark Brown 
181b545dd92SMark Brown 	ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
182b1387078SMark Brown 	if (ret != 0)
183b545dd92SMark Brown 		dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
184b1387078SMark Brown 
185*f4a2be1cSKuninori Morimoto 	ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_OPCLK, 0,
186b1387078SMark Brown 				       SYS_MCLK_RATE, SND_SOC_CLOCK_OUT);
187b1387078SMark Brown 	if (ret != 0)
188*f4a2be1cSKuninori Morimoto 		dev_err(component->dev, "Failed to set OPCLK: %d\n", ret);
189b1387078SMark Brown 
190b1387078SMark Brown 	if (card->num_rtd == DAI_CODEC_CP)
191b1387078SMark Brown 		return 0;
192b1387078SMark Brown 
193*f4a2be1cSKuninori Morimoto 	ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK,
194b1387078SMark Brown 				       ARIZONA_CLK_SRC_FLL2,
195b1387078SMark Brown 				       bells->asyncclk_rate,
196b1387078SMark Brown 				       SND_SOC_CLOCK_IN);
197b1387078SMark Brown 	if (ret != 0) {
198*f4a2be1cSKuninori Morimoto 		dev_err(component->dev, "Failed to set ASYNCCLK: %d\n", ret);
199b545dd92SMark Brown 		return ret;
200b545dd92SMark Brown 	}
201b545dd92SMark Brown 
2025015920aSMengdong Lin 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_CP].name);
2035015920aSMengdong Lin 	aif2_dai = rtd->cpu_dai;
204b1387078SMark Brown 
205b545dd92SMark Brown 	ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
206b545dd92SMark Brown 	if (ret != 0) {
207b545dd92SMark Brown 		dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret);
208b545dd92SMark Brown 		return ret;
209b545dd92SMark Brown 	}
210b545dd92SMark Brown 
211b1387078SMark Brown 	if (card->num_rtd == DAI_CODEC_SUB)
212b1387078SMark Brown 		return 0;
213b1387078SMark Brown 
2145015920aSMengdong Lin 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_SUB].name);
2155015920aSMengdong Lin 	aif3_dai = rtd->cpu_dai;
2165015920aSMengdong Lin 	wm9081_dai = rtd->codec_dai;
217b1387078SMark Brown 
218b545dd92SMark Brown 	ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
219b545dd92SMark Brown 	if (ret != 0) {
220b545dd92SMark Brown 		dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
221b545dd92SMark Brown 		return ret;
222b545dd92SMark Brown 	}
223b545dd92SMark Brown 
224*f4a2be1cSKuninori Morimoto 	ret = snd_soc_component_set_sysclk(wm9081_dai->component, WM9081_SYSCLK_MCLK,
225344c5edeSMark Brown 				       0, SYS_MCLK_RATE, 0);
226b545dd92SMark Brown 	if (ret != 0) {
227b545dd92SMark Brown 		dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret);
228b545dd92SMark Brown 		return ret;
229b545dd92SMark Brown 	}
230b545dd92SMark Brown 
231b545dd92SMark Brown 	return 0;
232b545dd92SMark Brown }
233b545dd92SMark Brown 
234b545dd92SMark Brown static const struct snd_soc_pcm_stream baseband_params = {
235b545dd92SMark Brown 	.formats = SNDRV_PCM_FMTBIT_S32_LE,
236b545dd92SMark Brown 	.rate_min = 8000,
237b545dd92SMark Brown 	.rate_max = 8000,
238b545dd92SMark Brown 	.channels_min = 2,
239b545dd92SMark Brown 	.channels_max = 2,
240b545dd92SMark Brown };
241b545dd92SMark Brown 
242b545dd92SMark Brown static const struct snd_soc_pcm_stream sub_params = {
243b545dd92SMark Brown 	.formats = SNDRV_PCM_FMTBIT_S32_LE,
244344c5edeSMark Brown 	.rate_min = SYS_AUDIO_RATE,
245344c5edeSMark Brown 	.rate_max = SYS_AUDIO_RATE,
246b545dd92SMark Brown 	.channels_min = 2,
247b545dd92SMark Brown 	.channels_max = 2,
248b545dd92SMark Brown };
249b545dd92SMark Brown 
2508d47e8a5SMark Brown static struct snd_soc_dai_link bells_dai_wm2200[] = {
2518d47e8a5SMark Brown 	{
2528d47e8a5SMark Brown 		.name = "CPU-DSP",
2538d47e8a5SMark Brown 		.stream_name = "CPU-DSP",
2548d47e8a5SMark Brown 		.cpu_dai_name = "samsung-i2s.0",
2558d47e8a5SMark Brown 		.codec_dai_name = "wm0010-sdi1",
256a08485d8SPadmavathi Venna 		.platform_name = "samsung-i2s.0",
2578d47e8a5SMark Brown 		.codec_name = "spi0.0",
2588d47e8a5SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
2598d47e8a5SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
2608d47e8a5SMark Brown 	},
2618d47e8a5SMark Brown 	{
2628d47e8a5SMark Brown 		.name = "DSP-CODEC",
2638d47e8a5SMark Brown 		.stream_name = "DSP-CODEC",
2648d47e8a5SMark Brown 		.cpu_dai_name = "wm0010-sdi2",
2658d47e8a5SMark Brown 		.codec_dai_name = "wm2200",
2668d47e8a5SMark Brown 		.codec_name = "wm2200.1-003a",
2678d47e8a5SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
2688d47e8a5SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
2698d47e8a5SMark Brown 		.params = &sub_params,
2708d47e8a5SMark Brown 		.ignore_suspend = 1,
2718d47e8a5SMark Brown 	},
2728d47e8a5SMark Brown };
2738d47e8a5SMark Brown 
274b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5102[] = {
275b545dd92SMark Brown 	{
276344c5edeSMark Brown 		.name = "CPU-DSP",
277344c5edeSMark Brown 		.stream_name = "CPU-DSP",
278b545dd92SMark Brown 		.cpu_dai_name = "samsung-i2s.0",
279344c5edeSMark Brown 		.codec_dai_name = "wm0010-sdi1",
280a08485d8SPadmavathi Venna 		.platform_name = "samsung-i2s.0",
281344c5edeSMark Brown 		.codec_name = "spi0.0",
282344c5edeSMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
283344c5edeSMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
284344c5edeSMark Brown 	},
285344c5edeSMark Brown 	{
286344c5edeSMark Brown 		.name = "DSP-CODEC",
287344c5edeSMark Brown 		.stream_name = "DSP-CODEC",
288344c5edeSMark Brown 		.cpu_dai_name = "wm0010-sdi2",
289344c5edeSMark Brown 		.codec_dai_name = "wm5102-aif1",
290b545dd92SMark Brown 		.codec_name = "wm5102-codec",
291b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
292b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
293344c5edeSMark Brown 		.params = &sub_params,
294344c5edeSMark Brown 		.ignore_suspend = 1,
295b545dd92SMark Brown 	},
296b545dd92SMark Brown 	{
297b545dd92SMark Brown 		.name = "Baseband",
298b545dd92SMark Brown 		.stream_name = "Baseband",
299b545dd92SMark Brown 		.cpu_dai_name = "wm5102-aif2",
300b545dd92SMark Brown 		.codec_dai_name = "wm1250-ev1",
301b545dd92SMark Brown 		.codec_name = "wm1250-ev1.1-0027",
302b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
303b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
304b545dd92SMark Brown 		.ignore_suspend = 1,
305b545dd92SMark Brown 		.params = &baseband_params,
306b545dd92SMark Brown 	},
307b545dd92SMark Brown 	{
308b545dd92SMark Brown 		.name = "Sub",
309b545dd92SMark Brown 		.stream_name = "Sub",
310b545dd92SMark Brown 		.cpu_dai_name = "wm5102-aif3",
311b545dd92SMark Brown 		.codec_dai_name = "wm9081-hifi",
312b545dd92SMark Brown 		.codec_name = "wm9081.1-006c",
313b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
314b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBS_CFS,
315b545dd92SMark Brown 		.ignore_suspend = 1,
316b545dd92SMark Brown 		.params = &sub_params,
317b545dd92SMark Brown 	},
318b545dd92SMark Brown };
319b545dd92SMark Brown 
320b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5110[] = {
321b545dd92SMark Brown 	{
322344c5edeSMark Brown 		.name = "CPU-DSP",
323344c5edeSMark Brown 		.stream_name = "CPU-DSP",
324b545dd92SMark Brown 		.cpu_dai_name = "samsung-i2s.0",
325344c5edeSMark Brown 		.codec_dai_name = "wm0010-sdi1",
326a08485d8SPadmavathi Venna 		.platform_name = "samsung-i2s.0",
327344c5edeSMark Brown 		.codec_name = "spi0.0",
328344c5edeSMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
329344c5edeSMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
330344c5edeSMark Brown 	},
331344c5edeSMark Brown 	{
332344c5edeSMark Brown 		.name = "DSP-CODEC",
333344c5edeSMark Brown 		.stream_name = "DSP-CODEC",
334344c5edeSMark Brown 		.cpu_dai_name = "wm0010-sdi2",
335344c5edeSMark Brown 		.codec_dai_name = "wm5110-aif1",
336b545dd92SMark Brown 		.codec_name = "wm5110-codec",
337b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
338b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
339344c5edeSMark Brown 		.params = &sub_params,
340344c5edeSMark Brown 		.ignore_suspend = 1,
341b545dd92SMark Brown 	},
342b545dd92SMark Brown 	{
343b545dd92SMark Brown 		.name = "Baseband",
344b545dd92SMark Brown 		.stream_name = "Baseband",
345b545dd92SMark Brown 		.cpu_dai_name = "wm5110-aif2",
346b545dd92SMark Brown 		.codec_dai_name = "wm1250-ev1",
347b545dd92SMark Brown 		.codec_name = "wm1250-ev1.1-0027",
348b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
349b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBM_CFM,
350b545dd92SMark Brown 		.ignore_suspend = 1,
351b545dd92SMark Brown 		.params = &baseband_params,
352b545dd92SMark Brown 	},
353b545dd92SMark Brown 	{
354b545dd92SMark Brown 		.name = "Sub",
355b545dd92SMark Brown 		.stream_name = "Sub",
356ffaa839bSMark Brown 		.cpu_dai_name = "wm5110-aif3",
357b545dd92SMark Brown 		.codec_dai_name = "wm9081-hifi",
358b545dd92SMark Brown 		.codec_name = "wm9081.1-006c",
359b545dd92SMark Brown 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
360b545dd92SMark Brown 				| SND_SOC_DAIFMT_CBS_CFS,
361b545dd92SMark Brown 		.ignore_suspend = 1,
362b545dd92SMark Brown 		.params = &sub_params,
363b545dd92SMark Brown 	},
364b545dd92SMark Brown };
365b545dd92SMark Brown 
366b545dd92SMark Brown static struct snd_soc_codec_conf bells_codec_conf[] = {
367b545dd92SMark Brown 	{
368b545dd92SMark Brown 		.dev_name = "wm9081.1-006c",
369b545dd92SMark Brown 		.name_prefix = "Sub",
370b545dd92SMark Brown 	},
371b545dd92SMark Brown };
372b545dd92SMark Brown 
373939d3c6aSCharles Keepax static struct snd_soc_dapm_widget bells_widgets[] = {
374939d3c6aSCharles Keepax 	SND_SOC_DAPM_MIC("DMIC", NULL),
375939d3c6aSCharles Keepax };
376939d3c6aSCharles Keepax 
377b545dd92SMark Brown static struct snd_soc_dapm_route bells_routes[] = {
378b545dd92SMark Brown 	{ "Sub CLK_SYS", NULL, "OPCLK" },
379b3a6006eSCharles Keepax 	{ "CLKIN", NULL, "OPCLK" },
380939d3c6aSCharles Keepax 
381939d3c6aSCharles Keepax 	{ "DMIC", NULL, "MICBIAS2" },
382939d3c6aSCharles Keepax 	{ "IN2L", NULL, "DMIC" },
383939d3c6aSCharles Keepax 	{ "IN2R", NULL, "DMIC" },
384b545dd92SMark Brown };
385b545dd92SMark Brown 
386b545dd92SMark Brown static struct snd_soc_card bells_cards[] = {
387b545dd92SMark Brown 	{
3888d47e8a5SMark Brown 		.name = "Bells WM2200",
3898d47e8a5SMark Brown 		.owner = THIS_MODULE,
3908d47e8a5SMark Brown 		.dai_link = bells_dai_wm2200,
3918d47e8a5SMark Brown 		.num_links = ARRAY_SIZE(bells_dai_wm2200),
3928d47e8a5SMark Brown 		.codec_conf = bells_codec_conf,
3938d47e8a5SMark Brown 		.num_configs = ARRAY_SIZE(bells_codec_conf),
3948d47e8a5SMark Brown 
3958d47e8a5SMark Brown 		.late_probe = bells_late_probe,
3968d47e8a5SMark Brown 
397939d3c6aSCharles Keepax 		.dapm_widgets = bells_widgets,
398939d3c6aSCharles Keepax 		.num_dapm_widgets = ARRAY_SIZE(bells_widgets),
3998d47e8a5SMark Brown 		.dapm_routes = bells_routes,
4008d47e8a5SMark Brown 		.num_dapm_routes = ARRAY_SIZE(bells_routes),
4018d47e8a5SMark Brown 
4028d47e8a5SMark Brown 		.set_bias_level = bells_set_bias_level,
4038d47e8a5SMark Brown 		.set_bias_level_post = bells_set_bias_level_post,
4048d47e8a5SMark Brown 
4058d47e8a5SMark Brown 		.drvdata = &wm2200_drvdata,
4068d47e8a5SMark Brown 	},
4078d47e8a5SMark Brown 	{
408b545dd92SMark Brown 		.name = "Bells WM5102",
409b545dd92SMark Brown 		.owner = THIS_MODULE,
410b545dd92SMark Brown 		.dai_link = bells_dai_wm5102,
411b545dd92SMark Brown 		.num_links = ARRAY_SIZE(bells_dai_wm5102),
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 = &wm5102_drvdata,
426b545dd92SMark Brown 	},
427b545dd92SMark Brown 	{
428b545dd92SMark Brown 		.name = "Bells WM5110",
429b545dd92SMark Brown 		.owner = THIS_MODULE,
430b545dd92SMark Brown 		.dai_link = bells_dai_wm5110,
431b545dd92SMark Brown 		.num_links = ARRAY_SIZE(bells_dai_wm5110),
432b545dd92SMark Brown 		.codec_conf = bells_codec_conf,
433b545dd92SMark Brown 		.num_configs = ARRAY_SIZE(bells_codec_conf),
434b545dd92SMark Brown 
435b545dd92SMark Brown 		.late_probe = bells_late_probe,
436b545dd92SMark Brown 
437939d3c6aSCharles Keepax 		.dapm_widgets = bells_widgets,
438939d3c6aSCharles Keepax 		.num_dapm_widgets = ARRAY_SIZE(bells_widgets),
439b545dd92SMark Brown 		.dapm_routes = bells_routes,
440b545dd92SMark Brown 		.num_dapm_routes = ARRAY_SIZE(bells_routes),
441b545dd92SMark Brown 
442b545dd92SMark Brown 		.set_bias_level = bells_set_bias_level,
443b545dd92SMark Brown 		.set_bias_level_post = bells_set_bias_level_post,
444b1387078SMark Brown 
445b1387078SMark Brown 		.drvdata = &wm5110_drvdata,
446b545dd92SMark Brown 	},
447b545dd92SMark Brown };
448b545dd92SMark Brown 
449fdca21adSBill Pemberton static int bells_probe(struct platform_device *pdev)
450b545dd92SMark Brown {
451b545dd92SMark Brown 	int ret;
452b545dd92SMark Brown 
453b545dd92SMark Brown 	bells_cards[pdev->id].dev = &pdev->dev;
454b545dd92SMark Brown 
455c583883eSTushar Behera 	ret = devm_snd_soc_register_card(&pdev->dev, &bells_cards[pdev->id]);
456c583883eSTushar Behera 	if (ret)
457b545dd92SMark Brown 		dev_err(&pdev->dev,
458b545dd92SMark Brown 			"snd_soc_register_card(%s) failed: %d\n",
459b545dd92SMark Brown 			bells_cards[pdev->id].name, ret);
460c583883eSTushar Behera 
461b545dd92SMark Brown 	return ret;
462b545dd92SMark Brown }
463b545dd92SMark Brown 
464b545dd92SMark Brown static struct platform_driver bells_driver = {
465b545dd92SMark Brown 	.driver = {
466b545dd92SMark Brown 		.name = "bells",
467b545dd92SMark Brown 		.pm = &snd_soc_pm_ops,
468b545dd92SMark Brown 	},
469b545dd92SMark Brown 	.probe = bells_probe,
470b545dd92SMark Brown };
471b545dd92SMark Brown 
472b545dd92SMark Brown module_platform_driver(bells_driver);
473b545dd92SMark Brown 
474b545dd92SMark Brown MODULE_DESCRIPTION("Bells audio support");
475b545dd92SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
476b545dd92SMark Brown MODULE_LICENSE("GPL");
477b545dd92SMark Brown MODULE_ALIAS("platform:bells");
478