[ALSA] ASoC: Remove in-code changelogs
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / sound / soc / pxa / corgi.c
CommitLineData
a1eb4b3c
LG
1/*
2 * corgi.c -- SoC audio for Corgi
3 *
4 * Copyright 2005 Wolfson Microelectronics PLC.
5 * Copyright 2005 Openedhand Ltd.
6 *
7 * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
8 * Richard Purdie <richard@openedhand.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
a1eb4b3c
LG
14 */
15
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/timer.h>
19#include <linux/interrupt.h>
20#include <linux/platform_device.h>
a1eb4b3c
LG
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/soc.h>
24#include <sound/soc-dapm.h>
25
26#include <asm/mach-types.h>
27#include <asm/hardware/scoop.h>
28#include <asm/arch/pxa-regs.h>
29#include <asm/arch/hardware.h>
30#include <asm/arch/corgi.h>
31#include <asm/arch/audio.h>
32
33#include "../codecs/wm8731.h"
34#include "pxa2xx-pcm.h"
d928b25a 35#include "pxa2xx-i2s.h"
a1eb4b3c
LG
36
37#define CORGI_HP 0
38#define CORGI_MIC 1
39#define CORGI_LINE 2
40#define CORGI_HEADSET 3
41#define CORGI_HP_OFF 4
42#define CORGI_SPK_ON 0
43#define CORGI_SPK_OFF 1
44
45 /* audio clock in Hz - rounded from 12.235MHz */
46#define CORGI_AUDIO_CLOCK 12288000
47
48static int corgi_jack_func;
49static int corgi_spk_func;
50
51static void corgi_ext_control(struct snd_soc_codec *codec)
52{
53 int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
54
55 /* set up jack connection */
56 switch (corgi_jack_func) {
57 case CORGI_HP:
58 hp = 1;
59 /* set = unmute headphone */
60 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
61 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
62 break;
63 case CORGI_MIC:
64 mic = 1;
65 /* reset = mute headphone */
66 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
67 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
68 break;
69 case CORGI_LINE:
70 line = 1;
71 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
72 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
73 break;
74 case CORGI_HEADSET:
75 hs = 1;
76 mic = 1;
77 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
78 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
79 break;
80 }
81
82 if (corgi_spk_func == CORGI_SPK_ON)
83 spk = 1;
84
85 /* set the enpoints to their new connetion states */
86 snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
87 snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic);
88 snd_soc_dapm_set_endpoint(codec, "Line Jack", line);
89 snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
90 snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
91
92 /* signal a DAPM event */
93 snd_soc_dapm_sync_endpoints(codec);
94}
95
96static int corgi_startup(struct snd_pcm_substream *substream)
97{
98 struct snd_soc_pcm_runtime *rtd = substream->private_data;
99 struct snd_soc_codec *codec = rtd->socdev->codec;
100
101 /* check the jack status at stream startup */
102 corgi_ext_control(codec);
103 return 0;
104}
105
106/* we need to unmute the HP at shutdown as the mute burns power on corgi */
107static int corgi_shutdown(struct snd_pcm_substream *substream)
108{
109 struct snd_soc_pcm_runtime *rtd = substream->private_data;
110 struct snd_soc_codec *codec = rtd->socdev->codec;
111
112 /* set = unmute headphone */
113 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
114 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
115 return 0;
116}
117
d928b25a
LG
118static int corgi_hw_params(struct snd_pcm_substream *substream,
119 struct snd_pcm_hw_params *params)
120{
121 struct snd_soc_pcm_runtime *rtd = substream->private_data;
122 struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
123 struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
124 unsigned int clk = 0;
125 int ret = 0;
126
127 switch (params_rate(params)) {
128 case 8000:
129 case 16000:
130 case 48000:
131 case 96000:
132 clk = 12288000;
133 break;
134 case 11025:
135 case 22050:
136 case 44100:
137 clk = 11289600;
138 break;
139 }
140
141 /* set codec DAI configuration */
142 ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
143 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
144 if (ret < 0)
145 return ret;
146
147 /* set cpu DAI configuration */
148 ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
149 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
150 if (ret < 0)
151 return ret;
152
153 /* set the codec system clock for DAC and ADC */
154 ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
155 SND_SOC_CLOCK_IN);
156 if (ret < 0)
157 return ret;
158
159 /* set the I2S system clock as input (unused) */
160 ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
161 SND_SOC_CLOCK_IN);
162 if (ret < 0)
163 return ret;
164
165 return 0;
166}
167
a1eb4b3c
LG
168static struct snd_soc_ops corgi_ops = {
169 .startup = corgi_startup,
d928b25a 170 .hw_params = corgi_hw_params,
a1eb4b3c
LG
171 .shutdown = corgi_shutdown,
172};
173
174static int corgi_get_jack(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_value *ucontrol)
176{
177 ucontrol->value.integer.value[0] = corgi_jack_func;
178 return 0;
179}
180
181static int corgi_set_jack(struct snd_kcontrol *kcontrol,
182 struct snd_ctl_elem_value *ucontrol)
183{
184 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
185
186 if (corgi_jack_func == ucontrol->value.integer.value[0])
187 return 0;
188
189 corgi_jack_func = ucontrol->value.integer.value[0];
190 corgi_ext_control(codec);
191 return 1;
192}
193
194static int corgi_get_spk(struct snd_kcontrol *kcontrol,
195 struct snd_ctl_elem_value *ucontrol)
196{
197 ucontrol->value.integer.value[0] = corgi_spk_func;
198 return 0;
199}
200
201static int corgi_set_spk(struct snd_kcontrol *kcontrol,
202 struct snd_ctl_elem_value *ucontrol)
203{
204 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
205
206 if (corgi_spk_func == ucontrol->value.integer.value[0])
207 return 0;
208
209 corgi_spk_func = ucontrol->value.integer.value[0];
210 corgi_ext_control(codec);
211 return 1;
212}
213
338c7ed0
JN
214static int corgi_amp_event(struct snd_soc_dapm_widget *w,
215 struct snd_kcontrol *k, int event)
a1eb4b3c
LG
216{
217 if (SND_SOC_DAPM_EVENT_ON(event))
218 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
219 else
220 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
221
222 return 0;
223}
224
338c7ed0
JN
225static int corgi_mic_event(struct snd_soc_dapm_widget *w,
226 struct snd_kcontrol *k, int event)
a1eb4b3c
LG
227{
228 if (SND_SOC_DAPM_EVENT_ON(event))
229 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
230 else
231 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
232
233 return 0;
234}
235
236/* corgi machine dapm widgets */
237static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
238SND_SOC_DAPM_HP("Headphone Jack", NULL),
239SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event),
240SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event),
241SND_SOC_DAPM_LINE("Line Jack", NULL),
242SND_SOC_DAPM_HP("Headset Jack", NULL),
243};
244
245/* Corgi machine audio map (connections to the codec pins) */
25191c45 246static const struct snd_soc_dapm_route audio_map[] = {
a1eb4b3c
LG
247
248 /* headset Jack - in = micin, out = LHPOUT*/
249 {"Headset Jack", NULL, "LHPOUT"},
250
251 /* headphone connected to LHPOUT1, RHPOUT1 */
252 {"Headphone Jack", NULL, "LHPOUT"},
253 {"Headphone Jack", NULL, "RHPOUT"},
254
255 /* speaker connected to LOUT, ROUT */
256 {"Ext Spk", NULL, "ROUT"},
257 {"Ext Spk", NULL, "LOUT"},
258
259 /* mic is connected to MICIN (via right channel of headphone jack) */
260 {"MICIN", NULL, "Mic Jack"},
261
262 /* Same as the above but no mic bias for line signals */
263 {"MICIN", NULL, "Line Jack"},
a1eb4b3c
LG
264};
265
266static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
267 "Off"};
268static const char *spk_function[] = {"On", "Off"};
269static const struct soc_enum corgi_enum[] = {
270 SOC_ENUM_SINGLE_EXT(5, jack_function),
271 SOC_ENUM_SINGLE_EXT(2, spk_function),
272};
273
274static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
275 SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack,
276 corgi_set_jack),
277 SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk,
278 corgi_set_spk),
279};
280
281/*
282 * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
283 */
284static int corgi_wm8731_init(struct snd_soc_codec *codec)
285{
286 int i, err;
287
288 snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
289 snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
290
291 /* Add corgi specific controls */
292 for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
293 err = snd_ctl_add(codec->card,
1bfcd361 294 snd_soc_cnew(&wm8731_corgi_controls[i], codec, NULL));
a1eb4b3c
LG
295 if (err < 0)
296 return err;
297 }
298
299 /* Add corgi specific widgets */
25191c45
MB
300 snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
301 ARRAY_SIZE(wm8731_dapm_widgets));
a1eb4b3c
LG
302
303 /* Set up corgi specific audio path audio_map */
25191c45 304 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
a1eb4b3c
LG
305
306 snd_soc_dapm_sync_endpoints(codec);
307 return 0;
308}
309
a1eb4b3c
LG
310/* corgi digital audio interface glue - connects codec <--> CPU */
311static struct snd_soc_dai_link corgi_dai = {
312 .name = "WM8731",
313 .stream_name = "WM8731",
314 .cpu_dai = &pxa_i2s_dai,
315 .codec_dai = &wm8731_dai,
316 .init = corgi_wm8731_init,
d928b25a 317 .ops = &corgi_ops,
a1eb4b3c
LG
318};
319
320/* corgi audio machine driver */
321static struct snd_soc_machine snd_soc_machine_corgi = {
322 .name = "Corgi",
323 .dai_link = &corgi_dai,
324 .num_links = 1,
a1eb4b3c
LG
325};
326
327/* corgi audio private data */
328static struct wm8731_setup_data corgi_wm8731_setup = {
329 .i2c_address = 0x1b,
330};
331
332/* corgi audio subsystem */
333static struct snd_soc_device corgi_snd_devdata = {
334 .machine = &snd_soc_machine_corgi,
335 .platform = &pxa2xx_soc_platform,
336 .codec_dev = &soc_codec_dev_wm8731,
337 .codec_data = &corgi_wm8731_setup,
338};
339
340static struct platform_device *corgi_snd_device;
341
342static int __init corgi_init(void)
343{
344 int ret;
345
1bfcd361
MB
346 if (!(machine_is_corgi() || machine_is_shepherd() ||
347 machine_is_husky()))
a1eb4b3c
LG
348 return -ENODEV;
349
350 corgi_snd_device = platform_device_alloc("soc-audio", -1);
351 if (!corgi_snd_device)
352 return -ENOMEM;
353
354 platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata);
355 corgi_snd_devdata.dev = &corgi_snd_device->dev;
356 ret = platform_device_add(corgi_snd_device);
357
358 if (ret)
359 platform_device_put(corgi_snd_device);
360
361 return ret;
362}
363
364static void __exit corgi_exit(void)
365{
366 platform_device_unregister(corgi_snd_device);
367}
368
369module_init(corgi_init);
370module_exit(corgi_exit);
371
372/* Module information */
373MODULE_AUTHOR("Richard Purdie");
374MODULE_DESCRIPTION("ALSA SoC Corgi");
375MODULE_LICENSE("GPL");