This source file includes following definitions.
- neo1973_hifi_hw_params
- neo1973_hifi_hw_free
- neo1973_voice_hw_params
- neo1973_voice_hw_free
- lm4853_set_spk
- lm4853_get_spk
- lm4853_event
- neo1973_wm8753_init
- neo1973_init
- neo1973_exit
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/gpio.h>
15
16 #include <sound/soc.h>
17
18 #include <mach/gpio-samsung.h>
19 #include <asm/mach-types.h>
20 #include "regs-iis.h"
21
22 #include "../codecs/wm8753.h"
23 #include "s3c24xx-i2s.h"
24
25 static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
26 struct snd_pcm_hw_params *params)
27 {
28 struct snd_soc_pcm_runtime *rtd = substream->private_data;
29 struct snd_soc_dai *codec_dai = rtd->codec_dai;
30 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
31 unsigned int pll_out = 0, bclk = 0;
32 int ret = 0;
33 unsigned long iis_clkrate;
34
35 iis_clkrate = s3c24xx_i2s_get_clockrate();
36
37 switch (params_rate(params)) {
38 case 8000:
39 case 16000:
40 pll_out = 12288000;
41 break;
42 case 48000:
43 bclk = WM8753_BCLK_DIV_4;
44 pll_out = 12288000;
45 break;
46 case 96000:
47 bclk = WM8753_BCLK_DIV_2;
48 pll_out = 12288000;
49 break;
50 case 11025:
51 bclk = WM8753_BCLK_DIV_16;
52 pll_out = 11289600;
53 break;
54 case 22050:
55 bclk = WM8753_BCLK_DIV_8;
56 pll_out = 11289600;
57 break;
58 case 44100:
59 bclk = WM8753_BCLK_DIV_4;
60 pll_out = 11289600;
61 break;
62 case 88200:
63 bclk = WM8753_BCLK_DIV_2;
64 pll_out = 11289600;
65 break;
66 }
67
68
69 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
70 SND_SOC_CLOCK_IN);
71 if (ret < 0)
72 return ret;
73
74
75 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
76 S3C2410_IISMOD_32FS);
77 if (ret < 0)
78 return ret;
79
80
81 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
82 if (ret < 0)
83 return ret;
84
85
86 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
87 S3C24XX_PRESCALE(4, 4));
88 if (ret < 0)
89 return ret;
90
91
92 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
93 iis_clkrate / 4, pll_out);
94 if (ret < 0)
95 return ret;
96
97 return 0;
98 }
99
100 static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
101 {
102 struct snd_soc_pcm_runtime *rtd = substream->private_data;
103 struct snd_soc_dai *codec_dai = rtd->codec_dai;
104
105
106 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
107 }
108
109
110
111
112 static struct snd_soc_ops neo1973_hifi_ops = {
113 .hw_params = neo1973_hifi_hw_params,
114 .hw_free = neo1973_hifi_hw_free,
115 };
116
117 static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
118 struct snd_pcm_hw_params *params)
119 {
120 struct snd_soc_pcm_runtime *rtd = substream->private_data;
121 struct snd_soc_dai *codec_dai = rtd->codec_dai;
122 unsigned int pcmdiv = 0;
123 int ret = 0;
124 unsigned long iis_clkrate;
125
126 iis_clkrate = s3c24xx_i2s_get_clockrate();
127
128 if (params_rate(params) != 8000)
129 return -EINVAL;
130 if (params_channels(params) != 1)
131 return -EINVAL;
132
133 pcmdiv = WM8753_PCM_DIV_6;
134
135
136 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
137 SND_SOC_CLOCK_IN);
138 if (ret < 0)
139 return ret;
140
141
142 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
143 if (ret < 0)
144 return ret;
145
146
147 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
148 iis_clkrate / 4, 12288000);
149 if (ret < 0)
150 return ret;
151
152 return 0;
153 }
154
155 static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
156 {
157 struct snd_soc_pcm_runtime *rtd = substream->private_data;
158 struct snd_soc_dai *codec_dai = rtd->codec_dai;
159
160
161 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
162 }
163
164 static struct snd_soc_ops neo1973_voice_ops = {
165 .hw_params = neo1973_voice_hw_params,
166 .hw_free = neo1973_voice_hw_free,
167 };
168
169 static int gta02_speaker_enabled;
170
171 static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
172 struct snd_ctl_elem_value *ucontrol)
173 {
174 gta02_speaker_enabled = ucontrol->value.integer.value[0];
175
176 gpio_set_value(S3C2410_GPJ(2), !gta02_speaker_enabled);
177
178 return 0;
179 }
180
181 static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
182 struct snd_ctl_elem_value *ucontrol)
183 {
184 ucontrol->value.integer.value[0] = gta02_speaker_enabled;
185 return 0;
186 }
187
188 static int lm4853_event(struct snd_soc_dapm_widget *w,
189 struct snd_kcontrol *k, int event)
190 {
191 gpio_set_value(S3C2410_GPJ(1), SND_SOC_DAPM_EVENT_OFF(event));
192
193 return 0;
194 }
195
196 static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
197 SND_SOC_DAPM_LINE("GSM Line Out", NULL),
198 SND_SOC_DAPM_LINE("GSM Line In", NULL),
199 SND_SOC_DAPM_MIC("Headset Mic", NULL),
200 SND_SOC_DAPM_MIC("Handset Mic", NULL),
201 SND_SOC_DAPM_SPK("Handset Spk", NULL),
202 SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
203 };
204
205 static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
206
207 {"GSM Line Out", NULL, "MONO1"},
208 {"GSM Line Out", NULL, "MONO2"},
209 {"RXP", NULL, "GSM Line In"},
210 {"RXN", NULL, "GSM Line In"},
211
212
213 {"MIC1", NULL, "Mic Bias"},
214 {"Mic Bias", NULL, "Headset Mic"},
215
216
217 {"MIC2", NULL, "Mic Bias"},
218 {"MIC2N", NULL, "Mic Bias"},
219 {"Mic Bias", NULL, "Handset Mic"},
220
221
222 {"ACIN", NULL, "ACOP"},
223
224
225 {"Stereo Out", NULL, "LOUT1"},
226 {"Stereo Out", NULL, "ROUT1"},
227
228
229 {"Handset Spk", NULL, "LOUT2"},
230 {"Handset Spk", NULL, "ROUT2"},
231 };
232
233 static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
234 SOC_DAPM_PIN_SWITCH("GSM Line Out"),
235 SOC_DAPM_PIN_SWITCH("GSM Line In"),
236 SOC_DAPM_PIN_SWITCH("Headset Mic"),
237 SOC_DAPM_PIN_SWITCH("Handset Mic"),
238 SOC_DAPM_PIN_SWITCH("Handset Spk"),
239 SOC_DAPM_PIN_SWITCH("Stereo Out"),
240
241 SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0,
242 lm4853_get_spk,
243 lm4853_set_spk),
244 };
245
246 static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
247 {
248 struct snd_soc_card *card = rtd->card;
249
250
251 snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out");
252 snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In");
253 snd_soc_dapm_disable_pin(&card->dapm, "Headset Mic");
254 snd_soc_dapm_disable_pin(&card->dapm, "Handset Mic");
255 snd_soc_dapm_disable_pin(&card->dapm, "Stereo Out");
256 snd_soc_dapm_disable_pin(&card->dapm, "Handset Spk");
257
258
259 snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line Out");
260 snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line In");
261 snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
262 snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Mic");
263 snd_soc_dapm_ignore_suspend(&card->dapm, "Stereo Out");
264 snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Spk");
265
266 return 0;
267 }
268
269 SND_SOC_DAILINK_DEFS(wm8753,
270 DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
271 DAILINK_COMP_ARRAY(COMP_CODEC("wm8753.0-001a", "wm8753-hifi")),
272 DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
273
274 SND_SOC_DAILINK_DEFS(bluetooth,
275 DAILINK_COMP_ARRAY(COMP_CPU("bt-sco-pcm")),
276 DAILINK_COMP_ARRAY(COMP_CODEC("wm8753.0-001a", "wm8753-voice")));
277
278 static struct snd_soc_dai_link neo1973_dai[] = {
279 {
280 .name = "WM8753",
281 .stream_name = "WM8753 HiFi",
282 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
283 SND_SOC_DAIFMT_CBM_CFM,
284 .init = neo1973_wm8753_init,
285 .ops = &neo1973_hifi_ops,
286 SND_SOC_DAILINK_REG(wm8753),
287 },
288 {
289 .name = "Bluetooth",
290 .stream_name = "Voice",
291 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
292 SND_SOC_DAIFMT_CBS_CFS,
293 .ops = &neo1973_voice_ops,
294 SND_SOC_DAILINK_REG(bluetooth),
295 },
296 };
297
298 static struct snd_soc_aux_dev neo1973_aux_devs[] = {
299 {
300 .dlc = COMP_AUX("dfbmcs320.0"),
301 },
302 };
303
304 static struct snd_soc_codec_conf neo1973_codec_conf[] = {
305 {
306 .dev_name = "lm4857.0-007c",
307 .name_prefix = "Amp",
308 },
309 };
310
311 static const struct gpio neo1973_gta02_gpios[] = {
312 { S3C2410_GPJ(2), GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" },
313 { S3C2410_GPJ(1), GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" },
314 };
315
316 static struct snd_soc_card neo1973 = {
317 .name = "neo1973",
318 .owner = THIS_MODULE,
319 .dai_link = neo1973_dai,
320 .num_links = ARRAY_SIZE(neo1973_dai),
321 .aux_dev = neo1973_aux_devs,
322 .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
323 .codec_conf = neo1973_codec_conf,
324 .num_configs = ARRAY_SIZE(neo1973_codec_conf),
325
326 .controls = neo1973_wm8753_controls,
327 .num_controls = ARRAY_SIZE(neo1973_wm8753_controls),
328 .dapm_widgets = neo1973_wm8753_dapm_widgets,
329 .num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets),
330 .dapm_routes = neo1973_wm8753_routes,
331 .num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes),
332 .fully_routed = true,
333 };
334
335 static struct platform_device *neo1973_snd_device;
336
337 static int __init neo1973_init(void)
338 {
339 int ret;
340
341 if (!machine_is_neo1973_gta02())
342 return -ENODEV;
343
344 if (machine_is_neo1973_gta02()) {
345 neo1973.name = "neo1973gta02";
346 neo1973.num_aux_devs = 1;
347
348 ret = gpio_request_array(neo1973_gta02_gpios,
349 ARRAY_SIZE(neo1973_gta02_gpios));
350 if (ret)
351 return ret;
352 }
353
354 neo1973_snd_device = platform_device_alloc("soc-audio", -1);
355 if (!neo1973_snd_device) {
356 ret = -ENOMEM;
357 goto err_gpio_free;
358 }
359
360 platform_set_drvdata(neo1973_snd_device, &neo1973);
361 ret = platform_device_add(neo1973_snd_device);
362
363 if (ret)
364 goto err_put_device;
365
366 return 0;
367
368 err_put_device:
369 platform_device_put(neo1973_snd_device);
370 err_gpio_free:
371 if (machine_is_neo1973_gta02()) {
372 gpio_free_array(neo1973_gta02_gpios,
373 ARRAY_SIZE(neo1973_gta02_gpios));
374 }
375 return ret;
376 }
377 module_init(neo1973_init);
378
379 static void __exit neo1973_exit(void)
380 {
381 platform_device_unregister(neo1973_snd_device);
382
383 if (machine_is_neo1973_gta02()) {
384 gpio_free_array(neo1973_gta02_gpios,
385 ARRAY_SIZE(neo1973_gta02_gpios));
386 }
387 }
388 module_exit(neo1973_exit);
389
390
391 MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
392 MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner");
393 MODULE_LICENSE("GPL");