2 * neo1973_wm8753.c -- SoC audio for Neo1973
4 * Copyright 2007 Wolfson Microelectronics PLC.
5 * Author: Graeme Gregory
6 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/timer.h>
18 #include <linux/interrupt.h>
19 #include <linux/platform_device.h>
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/soc.h>
24 #include <asm/mach-types.h>
25 #include <mach/regs-clock.h>
26 #include <mach/regs-gpio.h>
27 #include <mach/hardware.h>
29 #include <mach/spi-gpio.h>
31 #include <plat/regs-iis.h>
33 #include "../codecs/wm8753.h"
35 #include "s3c24xx-i2s.h"
37 static struct snd_soc_card neo1973;
39 static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
40 struct snd_pcm_hw_params *params)
42 struct snd_soc_pcm_runtime *rtd = substream->private_data;
43 struct snd_soc_dai *codec_dai = rtd->codec_dai;
44 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
45 unsigned int pll_out = 0, bclk = 0;
47 unsigned long iis_clkrate;
49 pr_debug("Entered %s\n", __func__);
51 iis_clkrate = s3c24xx_i2s_get_clockrate();
53 switch (params_rate(params)) {
59 bclk = WM8753_BCLK_DIV_4;
63 bclk = WM8753_BCLK_DIV_2;
67 bclk = WM8753_BCLK_DIV_16;
71 bclk = WM8753_BCLK_DIV_8;
75 bclk = WM8753_BCLK_DIV_4;
79 bclk = WM8753_BCLK_DIV_2;
84 /* set codec DAI configuration */
85 ret = snd_soc_dai_set_fmt(codec_dai,
86 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
87 SND_SOC_DAIFMT_CBM_CFM);
91 /* set cpu DAI configuration */
92 ret = snd_soc_dai_set_fmt(cpu_dai,
93 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
94 SND_SOC_DAIFMT_CBM_CFM);
98 /* set the codec system clock for DAC and ADC */
99 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
104 /* set MCLK division for sample rate */
105 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
106 S3C2410_IISMOD_32FS);
110 /* set codec BCLK division for sample rate */
111 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
115 /* set prescaler division for sample rate */
116 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
117 S3C24XX_PRESCALE(4, 4));
121 /* codec PLL input is PCLK/4 */
122 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
123 iis_clkrate / 4, pll_out);
130 static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
132 struct snd_soc_pcm_runtime *rtd = substream->private_data;
133 struct snd_soc_dai *codec_dai = rtd->codec_dai;
135 pr_debug("Entered %s\n", __func__);
137 /* disable the PLL */
138 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
142 * Neo1973 WM8753 HiFi DAI opserations.
144 static struct snd_soc_ops neo1973_hifi_ops = {
145 .hw_params = neo1973_hifi_hw_params,
146 .hw_free = neo1973_hifi_hw_free,
149 static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
150 struct snd_pcm_hw_params *params)
152 struct snd_soc_pcm_runtime *rtd = substream->private_data;
153 struct snd_soc_dai *codec_dai = rtd->codec_dai;
154 unsigned int pcmdiv = 0;
156 unsigned long iis_clkrate;
158 pr_debug("Entered %s\n", __func__);
160 iis_clkrate = s3c24xx_i2s_get_clockrate();
162 if (params_rate(params) != 8000)
164 if (params_channels(params) != 1)
167 pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
169 /* todo: gg check mode (DSP_B) against CSR datasheet */
170 /* set codec DAI configuration */
171 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
172 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
176 /* set the codec system clock for DAC and ADC */
177 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
182 /* set codec PCM division for sample rate */
183 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
187 /* configure and enable PLL for 12.288MHz output */
188 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
189 iis_clkrate / 4, 12288000);
196 static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
198 struct snd_soc_pcm_runtime *rtd = substream->private_data;
199 struct snd_soc_dai *codec_dai = rtd->codec_dai;
201 pr_debug("Entered %s\n", __func__);
203 /* disable the PLL */
204 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
207 static struct snd_soc_ops neo1973_voice_ops = {
208 .hw_params = neo1973_voice_hw_params,
209 .hw_free = neo1973_voice_hw_free,
212 static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
213 SND_SOC_DAPM_LINE("GSM Line Out", NULL),
214 SND_SOC_DAPM_LINE("GSM Line In", NULL),
215 SND_SOC_DAPM_MIC("Headset Mic", NULL),
216 SND_SOC_DAPM_MIC("Call Mic", NULL),
220 static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
221 /* Connections to the GSM Module */
222 {"GSM Line Out", NULL, "MONO1"},
223 {"GSM Line Out", NULL, "MONO2"},
224 {"RXP", NULL, "GSM Line In"},
225 {"RXN", NULL, "GSM Line In"},
227 /* Connections to Headset */
228 {"MIC1", NULL, "Mic Bias"},
229 {"Mic Bias", NULL, "Headset Mic"},
232 {"MIC2", NULL, "Mic Bias"},
233 {"MIC2N", NULL, "Mic Bias"},
234 {"Mic Bias", NULL, "Call Mic"},
236 /* Connect the ALC pins */
237 {"ACIN", NULL, "ACOP"},
240 static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
241 SOC_DAPM_PIN_SWITCH("GSM Line Out"),
242 SOC_DAPM_PIN_SWITCH("GSM Line In"),
243 SOC_DAPM_PIN_SWITCH("Headset Mic"),
244 SOC_DAPM_PIN_SWITCH("Call Mic"),
249 * This is an example machine initialisation for a wm8753 connected to a
250 * neo1973 II. It is missing logic to detect hp/mic insertions and logic
251 * to re-route the audio in such an event.
253 static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
255 struct snd_soc_codec *codec = rtd->codec;
256 struct snd_soc_dapm_context *dapm = &codec->dapm;
259 pr_debug("Entered %s\n", __func__);
261 /* set up NC codec pins */
262 snd_soc_dapm_nc_pin(dapm, "LOUT2");
263 snd_soc_dapm_nc_pin(dapm, "ROUT2");
264 snd_soc_dapm_nc_pin(dapm, "OUT3");
265 snd_soc_dapm_nc_pin(dapm, "OUT4");
266 snd_soc_dapm_nc_pin(dapm, "LINE1");
267 snd_soc_dapm_nc_pin(dapm, "LINE2");
269 /* Add neo1973 specific widgets */
270 snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
271 ARRAY_SIZE(wm8753_dapm_widgets));
273 /* set endpoints to default mode */
274 snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
275 snd_soc_dapm_disable_pin(dapm, "GSM Line In");
276 snd_soc_dapm_disable_pin(dapm, "Headset Mic");
277 snd_soc_dapm_disable_pin(dapm, "Call Mic");
279 /* add neo1973 specific controls */
280 err = snd_soc_add_controls(codec, neo1973_wm8753_controls,
281 ARRAY_SIZE(neo1973_wm8753_controls));
285 /* set up neo1973 specific audio routes */
286 err = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes,
287 ARRAY_SIZE(neo1973_wm8753_routes));
289 snd_soc_dapm_sync(dapm);
293 static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = {
294 {"Amp IN", NULL, "ROUT1"},
295 {"Amp IN", NULL, "LOUT1"},
297 {"Handset Spk", NULL, "Amp EP"},
298 {"Stereo Out", NULL, "Amp LS"},
299 {"Headphone", NULL, "Amp HP"},
302 static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = {
303 SND_SOC_DAPM_SPK("Handset Spk", NULL),
304 SND_SOC_DAPM_SPK("Stereo Out", NULL),
305 SND_SOC_DAPM_HP("Headphone", NULL),
308 static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm)
312 ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets,
313 ARRAY_SIZE(neo1973_lm4857_dapm_widgets));
317 ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes,
318 ARRAY_SIZE(neo1973_lm4857_routes));
322 snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
323 snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
324 snd_soc_dapm_ignore_suspend(dapm, "Headphone");
326 snd_soc_dapm_sync(dapm);
334 static struct snd_soc_dai bt_dai = {
335 .name = "bluetooth-dai",
339 .rates = SNDRV_PCM_RATE_8000,
340 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
344 .rates = SNDRV_PCM_RATE_8000,
345 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
348 static struct snd_soc_dai_link neo1973_dai[] = {
349 { /* Hifi Playback - for similatious use with voice below */
351 .stream_name = "WM8753 HiFi",
352 .platform_name = "samsung-audio",
353 .cpu_dai_name = "s3c24xx-iis",
354 .codec_dai_name = "wm8753-hifi",
355 .codec_name = "wm8753-codec.0-001a",
356 .init = neo1973_wm8753_init,
357 .ops = &neo1973_hifi_ops,
361 .stream_name = "Voice",
362 .platform_name = "samsung-audio",
363 .cpu_dai_name = "bluetooth-dai",
364 .codec_dai_name = "wm8753-voice",
365 .codec_name = "wm8753-codec.0-001a",
366 .ops = &neo1973_voice_ops,
370 static struct snd_soc_aux_dev neo1973_aux_devs[] = {
373 .codec_name = "lm4857.0-007c",
374 .init = neo1973_lm4857_init,
378 static struct snd_soc_codec_conf neo1973_codec_conf[] = {
380 .dev_name = "lm4857.0-007c",
381 .name_prefix = "Amp",
385 static struct snd_soc_card neo1973 = {
387 .dai_link = neo1973_dai,
388 .num_links = ARRAY_SIZE(neo1973_dai),
389 .aux_dev = neo1973_aux_devs,
390 .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
391 .codec_conf = neo1973_codec_conf,
392 .num_configs = ARRAY_SIZE(neo1973_codec_conf),
395 static struct platform_device *neo1973_snd_device;
397 static int __init neo1973_init(void)
401 pr_debug("Entered %s\n", __func__);
403 if (!machine_is_neo1973_gta01()) {
405 "Only GTA01 hardware supported by ASoC driver\n");
409 neo1973_snd_device = platform_device_alloc("soc-audio", -1);
410 if (!neo1973_snd_device)
413 platform_set_drvdata(neo1973_snd_device, &neo1973);
414 ret = platform_device_add(neo1973_snd_device);
417 platform_device_put(neo1973_snd_device);
422 platform_device_unregister(neo1973_snd_device);
427 static void __exit neo1973_exit(void)
429 pr_debug("Entered %s\n", __func__);
431 platform_device_unregister(neo1973_snd_device);
434 module_init(neo1973_init);
435 module_exit(neo1973_exit);
437 /* Module information */
438 MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
439 MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
440 MODULE_LICENSE("GPL");