Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/soc/pxa/tosa.c
10817 views
1
/*
2
* tosa.c -- SoC audio for Tosa
3
*
4
* Copyright 2005 Wolfson Microelectronics PLC.
5
* Copyright 2005 Openedhand Ltd.
6
*
7
* Authors: Liam Girdwood <[email protected]>
8
* Richard Purdie <[email protected]>
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.
14
*
15
* GPIO's
16
* 1 - Jack Insertion
17
* 5 - Hookswitch (headset answer/hang up switch)
18
*
19
*/
20
21
#include <linux/module.h>
22
#include <linux/moduleparam.h>
23
#include <linux/device.h>
24
#include <linux/gpio.h>
25
26
#include <sound/core.h>
27
#include <sound/pcm.h>
28
#include <sound/soc.h>
29
30
#include <asm/mach-types.h>
31
#include <mach/tosa.h>
32
#include <mach/audio.h>
33
34
#include "../codecs/wm9712.h"
35
#include "pxa2xx-ac97.h"
36
37
static struct snd_soc_card tosa;
38
39
#define TOSA_HP 0
40
#define TOSA_MIC_INT 1
41
#define TOSA_HEADSET 2
42
#define TOSA_HP_OFF 3
43
#define TOSA_SPK_ON 0
44
#define TOSA_SPK_OFF 1
45
46
static int tosa_jack_func;
47
static int tosa_spk_func;
48
49
static void tosa_ext_control(struct snd_soc_codec *codec)
50
{
51
struct snd_soc_dapm_context *dapm = &codec->dapm;
52
53
/* set up jack connection */
54
switch (tosa_jack_func) {
55
case TOSA_HP:
56
snd_soc_dapm_disable_pin(dapm, "Mic (Internal)");
57
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
58
snd_soc_dapm_disable_pin(dapm, "Headset Jack");
59
break;
60
case TOSA_MIC_INT:
61
snd_soc_dapm_enable_pin(dapm, "Mic (Internal)");
62
snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
63
snd_soc_dapm_disable_pin(dapm, "Headset Jack");
64
break;
65
case TOSA_HEADSET:
66
snd_soc_dapm_disable_pin(dapm, "Mic (Internal)");
67
snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
68
snd_soc_dapm_enable_pin(dapm, "Headset Jack");
69
break;
70
}
71
72
if (tosa_spk_func == TOSA_SPK_ON)
73
snd_soc_dapm_enable_pin(dapm, "Speaker");
74
else
75
snd_soc_dapm_disable_pin(dapm, "Speaker");
76
77
snd_soc_dapm_sync(dapm);
78
}
79
80
static int tosa_startup(struct snd_pcm_substream *substream)
81
{
82
struct snd_soc_pcm_runtime *rtd = substream->private_data;
83
struct snd_soc_codec *codec = rtd->codec;
84
85
mutex_lock(&codec->mutex);
86
87
/* check the jack status at stream startup */
88
tosa_ext_control(codec);
89
90
mutex_unlock(&codec->mutex);
91
92
return 0;
93
}
94
95
static struct snd_soc_ops tosa_ops = {
96
.startup = tosa_startup,
97
};
98
99
static int tosa_get_jack(struct snd_kcontrol *kcontrol,
100
struct snd_ctl_elem_value *ucontrol)
101
{
102
ucontrol->value.integer.value[0] = tosa_jack_func;
103
return 0;
104
}
105
106
static int tosa_set_jack(struct snd_kcontrol *kcontrol,
107
struct snd_ctl_elem_value *ucontrol)
108
{
109
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
110
111
if (tosa_jack_func == ucontrol->value.integer.value[0])
112
return 0;
113
114
tosa_jack_func = ucontrol->value.integer.value[0];
115
tosa_ext_control(codec);
116
return 1;
117
}
118
119
static int tosa_get_spk(struct snd_kcontrol *kcontrol,
120
struct snd_ctl_elem_value *ucontrol)
121
{
122
ucontrol->value.integer.value[0] = tosa_spk_func;
123
return 0;
124
}
125
126
static int tosa_set_spk(struct snd_kcontrol *kcontrol,
127
struct snd_ctl_elem_value *ucontrol)
128
{
129
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
130
131
if (tosa_spk_func == ucontrol->value.integer.value[0])
132
return 0;
133
134
tosa_spk_func = ucontrol->value.integer.value[0];
135
tosa_ext_control(codec);
136
return 1;
137
}
138
139
/* tosa dapm event handlers */
140
static int tosa_hp_event(struct snd_soc_dapm_widget *w,
141
struct snd_kcontrol *k, int event)
142
{
143
gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 :0);
144
return 0;
145
}
146
147
/* tosa machine dapm widgets */
148
static const struct snd_soc_dapm_widget tosa_dapm_widgets[] = {
149
SND_SOC_DAPM_HP("Headphone Jack", tosa_hp_event),
150
SND_SOC_DAPM_HP("Headset Jack", NULL),
151
SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
152
SND_SOC_DAPM_SPK("Speaker", NULL),
153
};
154
155
/* tosa audio map */
156
static const struct snd_soc_dapm_route audio_map[] = {
157
158
/* headphone connected to HPOUTL, HPOUTR */
159
{"Headphone Jack", NULL, "HPOUTL"},
160
{"Headphone Jack", NULL, "HPOUTR"},
161
162
/* ext speaker connected to LOUT2, ROUT2 */
163
{"Speaker", NULL, "LOUT2"},
164
{"Speaker", NULL, "ROUT2"},
165
166
/* internal mic is connected to mic1, mic2 differential - with bias */
167
{"MIC1", NULL, "Mic Bias"},
168
{"MIC2", NULL, "Mic Bias"},
169
{"Mic Bias", NULL, "Mic (Internal)"},
170
171
/* headset is connected to HPOUTR, and LINEINR with bias */
172
{"Headset Jack", NULL, "HPOUTR"},
173
{"LINEINR", NULL, "Mic Bias"},
174
{"Mic Bias", NULL, "Headset Jack"},
175
};
176
177
static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
178
"Off"};
179
static const char *spk_function[] = {"On", "Off"};
180
static const struct soc_enum tosa_enum[] = {
181
SOC_ENUM_SINGLE_EXT(5, jack_function),
182
SOC_ENUM_SINGLE_EXT(2, spk_function),
183
};
184
185
static const struct snd_kcontrol_new tosa_controls[] = {
186
SOC_ENUM_EXT("Jack Function", tosa_enum[0], tosa_get_jack,
187
tosa_set_jack),
188
SOC_ENUM_EXT("Speaker Function", tosa_enum[1], tosa_get_spk,
189
tosa_set_spk),
190
};
191
192
static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
193
{
194
struct snd_soc_codec *codec = rtd->codec;
195
struct snd_soc_dapm_context *dapm = &codec->dapm;
196
int err;
197
198
snd_soc_dapm_nc_pin(dapm, "OUT3");
199
snd_soc_dapm_nc_pin(dapm, "MONOOUT");
200
201
/* add tosa specific controls */
202
err = snd_soc_add_controls(codec, tosa_controls,
203
ARRAY_SIZE(tosa_controls));
204
if (err < 0)
205
return err;
206
207
/* add tosa specific widgets */
208
snd_soc_dapm_new_controls(dapm, tosa_dapm_widgets,
209
ARRAY_SIZE(tosa_dapm_widgets));
210
211
/* set up tosa specific audio path audio_map */
212
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
213
214
snd_soc_dapm_sync(dapm);
215
return 0;
216
}
217
218
static struct snd_soc_dai_link tosa_dai[] = {
219
{
220
.name = "AC97",
221
.stream_name = "AC97 HiFi",
222
.cpu_dai_name = "pxa2xx-ac97",
223
.codec_dai_name = "wm9712-hifi",
224
.platform_name = "pxa-pcm-audio",
225
.codec_name = "wm9712-codec",
226
.init = tosa_ac97_init,
227
.ops = &tosa_ops,
228
},
229
{
230
.name = "AC97 Aux",
231
.stream_name = "AC97 Aux",
232
.cpu_dai_name = "pxa2xx-ac97-aux",
233
.codec_dai_name = "wm9712-aux",
234
.platform_name = "pxa-pcm-audio",
235
.codec_name = "wm9712-codec",
236
.ops = &tosa_ops,
237
},
238
};
239
240
static int tosa_probe(struct snd_soc_card *card)
241
{
242
int ret;
243
244
ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack");
245
if (ret)
246
return ret;
247
ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0);
248
if (ret)
249
gpio_free(TOSA_GPIO_L_MUTE);
250
251
return ret;
252
}
253
254
static int tosa_remove(struct snd_soc_card *card)
255
{
256
gpio_free(TOSA_GPIO_L_MUTE);
257
return 0;
258
}
259
260
static struct snd_soc_card tosa = {
261
.name = "Tosa",
262
.dai_link = tosa_dai,
263
.num_links = ARRAY_SIZE(tosa_dai),
264
.probe = tosa_probe,
265
.remove = tosa_remove,
266
};
267
268
static struct platform_device *tosa_snd_device;
269
270
static int __init tosa_init(void)
271
{
272
int ret;
273
274
if (!machine_is_tosa())
275
return -ENODEV;
276
277
tosa_snd_device = platform_device_alloc("soc-audio", -1);
278
if (!tosa_snd_device) {
279
ret = -ENOMEM;
280
goto err_alloc;
281
}
282
283
platform_set_drvdata(tosa_snd_device, &tosa);
284
ret = platform_device_add(tosa_snd_device);
285
286
if (!ret)
287
return 0;
288
289
platform_device_put(tosa_snd_device);
290
291
err_alloc:
292
return ret;
293
}
294
295
static void __exit tosa_exit(void)
296
{
297
platform_device_unregister(tosa_snd_device);
298
}
299
300
module_init(tosa_init);
301
module_exit(tosa_exit);
302
303
/* Module information */
304
MODULE_AUTHOR("Richard Purdie");
305
MODULE_DESCRIPTION("ALSA SoC Tosa");
306
MODULE_LICENSE("GPL");
307
308