diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/at91/Kconfig | 17 | ||||
-rw-r--r-- | sound/soc/at91/Makefile | 5 | ||||
-rw-r--r-- | sound/soc/at91/eti_b1_wm8731.c | 349 |
3 files changed, 0 insertions, 371 deletions
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig index 905186502e00..85a883299c2e 100644 --- a/sound/soc/at91/Kconfig +++ b/sound/soc/at91/Kconfig | |||
@@ -8,20 +8,3 @@ config SND_AT91_SOC | |||
8 | 8 | ||
9 | config SND_AT91_SOC_SSC | 9 | config SND_AT91_SOC_SSC |
10 | tristate | 10 | tristate |
11 | |||
12 | config SND_AT91_SOC_ETI_B1_WM8731 | ||
13 | tristate "SoC Audio support for WM8731-based Endrelia ETI-B1 boards" | ||
14 | depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1) | ||
15 | select SND_AT91_SOC_SSC | ||
16 | select SND_SOC_WM8731 | ||
17 | help | ||
18 | Say Y if you want to add support for SoC audio on WM8731-based | ||
19 | Endrelia Technologies Inc ETI-B1 or ETI-C1 boards. | ||
20 | |||
21 | config SND_AT91_SOC_ETI_SLAVE | ||
22 | bool "Run codec in slave Mode on Endrelia boards" | ||
23 | depends on SND_AT91_SOC_ETI_B1_WM8731 | ||
24 | default n | ||
25 | help | ||
26 | Say Y if you want to run with the AT91 SSC generating the BCLK | ||
27 | and LRC signals on Endrelia boards. | ||
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile index f23da17cc328..b817f11df286 100644 --- a/sound/soc/at91/Makefile +++ b/sound/soc/at91/Makefile | |||
@@ -4,8 +4,3 @@ snd-soc-at91-ssc-objs := at91-ssc.o | |||
4 | 4 | ||
5 | obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o | 5 | obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o |
6 | obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o | 6 | obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o |
7 | |||
8 | # AT91 Machine Support | ||
9 | snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o | ||
10 | |||
11 | obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o | ||
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c deleted file mode 100644 index 684781e4088b..000000000000 --- a/sound/soc/at91/eti_b1_wm8731.c +++ /dev/null | |||
@@ -1,349 +0,0 @@ | |||
1 | /* | ||
2 | * eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board. | ||
3 | * | ||
4 | * Author: Frank Mandarino <fmandarino@endrelia.com> | ||
5 | * Endrelia Technologies Inc. | ||
6 | * Created: Mar 29, 2006 | ||
7 | * | ||
8 | * Based on corgi.c by: | ||
9 | * | ||
10 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
11 | * Copyright 2005 Openedhand Ltd. | ||
12 | * | ||
13 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
14 | * Richard Purdie <richard@openedhand.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify it | ||
17 | * under the terms of the GNU General Public License as published by the | ||
18 | * Free Software Foundation; either version 2 of the License, or (at your | ||
19 | * option) any later version. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/timer.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/soc.h> | ||
33 | #include <sound/soc-dapm.h> | ||
34 | |||
35 | #include <mach/hardware.h> | ||
36 | #include <mach/gpio.h> | ||
37 | |||
38 | #include "../codecs/wm8731.h" | ||
39 | #include "at91-pcm.h" | ||
40 | #include "at91-ssc.h" | ||
41 | |||
42 | #if 0 | ||
43 | #define DBG(x...) printk(KERN_INFO "eti_b1_wm8731: " x) | ||
44 | #else | ||
45 | #define DBG(x...) | ||
46 | #endif | ||
47 | |||
48 | static struct clk *pck1_clk; | ||
49 | static struct clk *pllb_clk; | ||
50 | |||
51 | |||
52 | static int eti_b1_startup(struct snd_pcm_substream *substream) | ||
53 | { | ||
54 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
55 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
56 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
57 | int ret; | ||
58 | |||
59 | /* cpu clock is the AT91 master clock sent to the SSC */ | ||
60 | ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK, | ||
61 | 60000000, SND_SOC_CLOCK_IN); | ||
62 | if (ret < 0) | ||
63 | return ret; | ||
64 | |||
65 | /* codec system clock is supplied by PCK1, set to 12MHz */ | ||
66 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, | ||
67 | 12000000, SND_SOC_CLOCK_IN); | ||
68 | if (ret < 0) | ||
69 | return ret; | ||
70 | |||
71 | /* Start PCK1 clock. */ | ||
72 | clk_enable(pck1_clk); | ||
73 | DBG("pck1 started\n"); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static void eti_b1_shutdown(struct snd_pcm_substream *substream) | ||
79 | { | ||
80 | /* Stop PCK1 clock. */ | ||
81 | clk_disable(pck1_clk); | ||
82 | DBG("pck1 stopped\n"); | ||
83 | } | ||
84 | |||
85 | static int eti_b1_hw_params(struct snd_pcm_substream *substream, | ||
86 | struct snd_pcm_hw_params *params) | ||
87 | { | ||
88 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
89 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
90 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
91 | int ret; | ||
92 | |||
93 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE | ||
94 | unsigned int rate; | ||
95 | int cmr_div, period; | ||
96 | |||
97 | /* set codec DAI configuration */ | ||
98 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
99 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
100 | if (ret < 0) | ||
101 | return ret; | ||
102 | |||
103 | /* set cpu DAI configuration */ | ||
104 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
105 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
106 | if (ret < 0) | ||
107 | return ret; | ||
108 | |||
109 | /* | ||
110 | * The SSC clock dividers depend on the sample rate. The CMR.DIV | ||
111 | * field divides the system master clock MCK to drive the SSC TK | ||
112 | * signal which provides the codec BCLK. The TCMR.PERIOD and | ||
113 | * RCMR.PERIOD fields further divide the BCLK signal to drive | ||
114 | * the SSC TF and RF signals which provide the codec DACLRC and | ||
115 | * ADCLRC clocks. | ||
116 | * | ||
117 | * The dividers were determined through trial and error, where a | ||
118 | * CMR.DIV value is chosen such that the resulting BCLK value is | ||
119 | * divisible, or almost divisible, by (2 * sample rate), and then | ||
120 | * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. | ||
121 | */ | ||
122 | rate = params_rate(params); | ||
123 | |||
124 | switch (rate) { | ||
125 | case 8000: | ||
126 | cmr_div = 25; /* BCLK = 60MHz/(2*25) = 1.2MHz */ | ||
127 | period = 74; /* LRC = BCLK/(2*(74+1)) = 8000Hz */ | ||
128 | break; | ||
129 | case 32000: | ||
130 | cmr_div = 7; /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */ | ||
131 | period = 66; /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */ | ||
132 | break; | ||
133 | case 48000: | ||
134 | cmr_div = 13; /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */ | ||
135 | period = 23; /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */ | ||
136 | break; | ||
137 | default: | ||
138 | printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | /* set the MCK divider for BCLK */ | ||
143 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); | ||
144 | if (ret < 0) | ||
145 | return ret; | ||
146 | |||
147 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
148 | /* set the BCLK divider for DACLRC */ | ||
149 | ret = snd_soc_dai_set_clkdiv(cpu_dai, | ||
150 | AT91SSC_TCMR_PERIOD, period); | ||
151 | } else { | ||
152 | /* set the BCLK divider for ADCLRC */ | ||
153 | ret = snd_soc_dai_set_clkdiv(cpu_dai, | ||
154 | AT91SSC_RCMR_PERIOD, period); | ||
155 | } | ||
156 | if (ret < 0) | ||
157 | return ret; | ||
158 | |||
159 | #else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */ | ||
160 | /* | ||
161 | * Codec in Master Mode. | ||
162 | */ | ||
163 | |||
164 | /* set codec DAI configuration */ | ||
165 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
166 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
167 | if (ret < 0) | ||
168 | return ret; | ||
169 | |||
170 | /* set cpu DAI configuration */ | ||
171 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
172 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
173 | if (ret < 0) | ||
174 | return ret; | ||
175 | |||
176 | #endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */ | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static struct snd_soc_ops eti_b1_ops = { | ||
182 | .startup = eti_b1_startup, | ||
183 | .hw_params = eti_b1_hw_params, | ||
184 | .shutdown = eti_b1_shutdown, | ||
185 | }; | ||
186 | |||
187 | |||
188 | static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = { | ||
189 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
190 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
191 | }; | ||
192 | |||
193 | static const struct snd_soc_dapm_route intercon[] = { | ||
194 | |||
195 | /* speaker connected to LHPOUT */ | ||
196 | {"Ext Spk", NULL, "LHPOUT"}, | ||
197 | |||
198 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ | ||
199 | {"MICIN", NULL, "Mic Bias"}, | ||
200 | {"Mic Bias", NULL, "Int Mic"}, | ||
201 | }; | ||
202 | |||
203 | /* | ||
204 | * Logic for a wm8731 as connected on a Endrelia ETI-B1 board. | ||
205 | */ | ||
206 | static int eti_b1_wm8731_init(struct snd_soc_codec *codec) | ||
207 | { | ||
208 | DBG("eti_b1_wm8731_init() called\n"); | ||
209 | |||
210 | /* Add specific widgets */ | ||
211 | snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets, | ||
212 | ARRAY_SIZE(eti_b1_dapm_widgets)); | ||
213 | |||
214 | /* Set up specific audio path interconnects */ | ||
215 | snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon)); | ||
216 | |||
217 | /* not connected */ | ||
218 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); | ||
219 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); | ||
220 | |||
221 | /* always connected */ | ||
222 | snd_soc_dapm_enable_pin(codec, "Int Mic"); | ||
223 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
224 | |||
225 | snd_soc_dapm_sync(codec); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static struct snd_soc_dai_link eti_b1_dai = { | ||
231 | .name = "WM8731", | ||
232 | .stream_name = "WM8731 PCM", | ||
233 | .cpu_dai = &at91_ssc_dai[1], | ||
234 | .codec_dai = &wm8731_dai, | ||
235 | .init = eti_b1_wm8731_init, | ||
236 | .ops = &eti_b1_ops, | ||
237 | }; | ||
238 | |||
239 | static struct snd_soc_machine snd_soc_machine_eti_b1 = { | ||
240 | .name = "ETI_B1_WM8731", | ||
241 | .dai_link = &eti_b1_dai, | ||
242 | .num_links = 1, | ||
243 | }; | ||
244 | |||
245 | static struct wm8731_setup_data eti_b1_wm8731_setup = { | ||
246 | .i2c_bus = 0, | ||
247 | .i2c_address = 0x1a, | ||
248 | }; | ||
249 | |||
250 | static struct snd_soc_device eti_b1_snd_devdata = { | ||
251 | .machine = &snd_soc_machine_eti_b1, | ||
252 | .platform = &at91_soc_platform, | ||
253 | .codec_dev = &soc_codec_dev_wm8731, | ||
254 | .codec_data = &eti_b1_wm8731_setup, | ||
255 | }; | ||
256 | |||
257 | static struct platform_device *eti_b1_snd_device; | ||
258 | |||
259 | static int __init eti_b1_init(void) | ||
260 | { | ||
261 | int ret; | ||
262 | struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; | ||
263 | |||
264 | if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) { | ||
265 | DBG("SSC1 memory region is busy\n"); | ||
266 | return -EBUSY; | ||
267 | } | ||
268 | |||
269 | ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K); | ||
270 | if (!ssc->base) { | ||
271 | DBG("SSC1 memory ioremap failed\n"); | ||
272 | ret = -ENOMEM; | ||
273 | goto fail_release_mem; | ||
274 | } | ||
275 | |||
276 | ssc->pid = AT91RM9200_ID_SSC1; | ||
277 | |||
278 | eti_b1_snd_device = platform_device_alloc("soc-audio", -1); | ||
279 | if (!eti_b1_snd_device) { | ||
280 | DBG("platform device allocation failed\n"); | ||
281 | ret = -ENOMEM; | ||
282 | goto fail_io_unmap; | ||
283 | } | ||
284 | |||
285 | platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata); | ||
286 | eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev; | ||
287 | |||
288 | ret = platform_device_add(eti_b1_snd_device); | ||
289 | if (ret) { | ||
290 | DBG("platform device add failed\n"); | ||
291 | platform_device_put(eti_b1_snd_device); | ||
292 | goto fail_io_unmap; | ||
293 | } | ||
294 | |||
295 | at91_set_A_periph(AT91_PIN_PB6, 0); /* TF1 */ | ||
296 | at91_set_A_periph(AT91_PIN_PB7, 0); /* TK1 */ | ||
297 | at91_set_A_periph(AT91_PIN_PB8, 0); /* TD1 */ | ||
298 | at91_set_A_periph(AT91_PIN_PB9, 0); /* RD1 */ | ||
299 | /* at91_set_A_periph(AT91_PIN_PB10, 0);*/ /* RK1 */ | ||
300 | at91_set_A_periph(AT91_PIN_PB11, 0); /* RF1 */ | ||
301 | |||
302 | /* | ||
303 | * Set PCK1 parent to PLLB and its rate to 12 Mhz. | ||
304 | */ | ||
305 | pllb_clk = clk_get(NULL, "pllb"); | ||
306 | pck1_clk = clk_get(NULL, "pck1"); | ||
307 | |||
308 | clk_set_parent(pck1_clk, pllb_clk); | ||
309 | clk_set_rate(pck1_clk, 12000000); | ||
310 | |||
311 | DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk)); | ||
312 | |||
313 | /* assign the GPIO pin to PCK1 */ | ||
314 | at91_set_B_periph(AT91_PIN_PA24, 0); | ||
315 | |||
316 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE | ||
317 | printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n"); | ||
318 | #else | ||
319 | printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n"); | ||
320 | #endif | ||
321 | return ret; | ||
322 | |||
323 | fail_io_unmap: | ||
324 | iounmap(ssc->base); | ||
325 | fail_release_mem: | ||
326 | release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static void __exit eti_b1_exit(void) | ||
331 | { | ||
332 | struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; | ||
333 | |||
334 | clk_put(pck1_clk); | ||
335 | clk_put(pllb_clk); | ||
336 | |||
337 | platform_device_unregister(eti_b1_snd_device); | ||
338 | |||
339 | iounmap(ssc->base); | ||
340 | release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K); | ||
341 | } | ||
342 | |||
343 | module_init(eti_b1_init); | ||
344 | module_exit(eti_b1_exit); | ||
345 | |||
346 | /* Module information */ | ||
347 | MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>"); | ||
348 | MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731"); | ||
349 | MODULE_LICENSE("GPL"); | ||