Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/soc/omap/sdp3430.c
10817 views
1
/*
2
* sdp3430.c -- SoC audio for TI OMAP3430 SDP
3
*
4
* Author: Misael Lopez Cruz <[email protected]>
5
*
6
* Based on:
7
* Author: Steve Sakoman <[email protected]>
8
*
9
* This program is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU General Public License
11
* version 2 as published by the Free Software Foundation.
12
*
13
* This program is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21
* 02110-1301 USA
22
*
23
*/
24
25
#include <linux/clk.h>
26
#include <linux/platform_device.h>
27
#include <linux/i2c/twl.h>
28
#include <sound/core.h>
29
#include <sound/pcm.h>
30
#include <sound/soc.h>
31
#include <sound/jack.h>
32
33
#include <asm/mach-types.h>
34
#include <mach/hardware.h>
35
#include <mach/gpio.h>
36
#include <plat/mcbsp.h>
37
38
/* Register descriptions for twl4030 codec part */
39
#include <linux/mfd/twl4030-codec.h>
40
41
#include "omap-mcbsp.h"
42
#include "omap-pcm.h"
43
44
/* TWL4030 PMBR1 Register */
45
#define TWL4030_INTBR_PMBR1 0x0D
46
/* TWL4030 PMBR1 Register GPIO6 mux bit */
47
#define TWL4030_GPIO6_PWM0_MUTE(value) (value << 2)
48
49
static struct snd_soc_card snd_soc_sdp3430;
50
51
static int sdp3430_hw_params(struct snd_pcm_substream *substream,
52
struct snd_pcm_hw_params *params)
53
{
54
struct snd_soc_pcm_runtime *rtd = substream->private_data;
55
struct snd_soc_dai *codec_dai = rtd->codec_dai;
56
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
57
int ret;
58
59
/* Set codec DAI configuration */
60
ret = snd_soc_dai_set_fmt(codec_dai,
61
SND_SOC_DAIFMT_I2S |
62
SND_SOC_DAIFMT_NB_NF |
63
SND_SOC_DAIFMT_CBM_CFM);
64
if (ret < 0) {
65
printk(KERN_ERR "can't set codec DAI configuration\n");
66
return ret;
67
}
68
69
/* Set cpu DAI configuration */
70
ret = snd_soc_dai_set_fmt(cpu_dai,
71
SND_SOC_DAIFMT_I2S |
72
SND_SOC_DAIFMT_NB_NF |
73
SND_SOC_DAIFMT_CBM_CFM);
74
if (ret < 0) {
75
printk(KERN_ERR "can't set cpu DAI configuration\n");
76
return ret;
77
}
78
79
/* Set the codec system clock for DAC and ADC */
80
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
81
SND_SOC_CLOCK_IN);
82
if (ret < 0) {
83
printk(KERN_ERR "can't set codec system clock\n");
84
return ret;
85
}
86
87
return 0;
88
}
89
90
static struct snd_soc_ops sdp3430_ops = {
91
.hw_params = sdp3430_hw_params,
92
};
93
94
static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream,
95
struct snd_pcm_hw_params *params)
96
{
97
struct snd_soc_pcm_runtime *rtd = substream->private_data;
98
struct snd_soc_dai *codec_dai = rtd->codec_dai;
99
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
100
int ret;
101
102
/* Set codec DAI configuration */
103
ret = snd_soc_dai_set_fmt(codec_dai,
104
SND_SOC_DAIFMT_DSP_A |
105
SND_SOC_DAIFMT_IB_NF |
106
SND_SOC_DAIFMT_CBM_CFM);
107
if (ret) {
108
printk(KERN_ERR "can't set codec DAI configuration\n");
109
return ret;
110
}
111
112
/* Set cpu DAI configuration */
113
ret = snd_soc_dai_set_fmt(cpu_dai,
114
SND_SOC_DAIFMT_DSP_A |
115
SND_SOC_DAIFMT_IB_NF |
116
SND_SOC_DAIFMT_CBM_CFM);
117
if (ret < 0) {
118
printk(KERN_ERR "can't set cpu DAI configuration\n");
119
return ret;
120
}
121
122
/* Set the codec system clock for DAC and ADC */
123
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
124
SND_SOC_CLOCK_IN);
125
if (ret < 0) {
126
printk(KERN_ERR "can't set codec system clock\n");
127
return ret;
128
}
129
130
return 0;
131
}
132
133
static struct snd_soc_ops sdp3430_voice_ops = {
134
.hw_params = sdp3430_hw_voice_params,
135
};
136
137
/* Headset jack */
138
static struct snd_soc_jack hs_jack;
139
140
/* Headset jack detection DAPM pins */
141
static struct snd_soc_jack_pin hs_jack_pins[] = {
142
{
143
.pin = "Headset Mic",
144
.mask = SND_JACK_MICROPHONE,
145
},
146
{
147
.pin = "Headset Stereophone",
148
.mask = SND_JACK_HEADPHONE,
149
},
150
};
151
152
/* Headset jack detection gpios */
153
static struct snd_soc_jack_gpio hs_jack_gpios[] = {
154
{
155
.gpio = (OMAP_MAX_GPIO_LINES + 2),
156
.name = "hsdet-gpio",
157
.report = SND_JACK_HEADSET,
158
.debounce_time = 200,
159
},
160
};
161
162
/* SDP3430 machine DAPM */
163
static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
164
SND_SOC_DAPM_MIC("Ext Mic", NULL),
165
SND_SOC_DAPM_SPK("Ext Spk", NULL),
166
SND_SOC_DAPM_MIC("Headset Mic", NULL),
167
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
168
};
169
170
static const struct snd_soc_dapm_route audio_map[] = {
171
/* External Mics: MAINMIC, SUBMIC with bias*/
172
{"MAINMIC", NULL, "Mic Bias 1"},
173
{"SUBMIC", NULL, "Mic Bias 2"},
174
{"Mic Bias 1", NULL, "Ext Mic"},
175
{"Mic Bias 2", NULL, "Ext Mic"},
176
177
/* External Speakers: HFL, HFR */
178
{"Ext Spk", NULL, "HFL"},
179
{"Ext Spk", NULL, "HFR"},
180
181
/* Headset Mic: HSMIC with bias */
182
{"HSMIC", NULL, "Headset Mic Bias"},
183
{"Headset Mic Bias", NULL, "Headset Mic"},
184
185
/* Headset Stereophone (Headphone): HSOL, HSOR */
186
{"Headset Stereophone", NULL, "HSOL"},
187
{"Headset Stereophone", NULL, "HSOR"},
188
};
189
190
static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
191
{
192
struct snd_soc_codec *codec = rtd->codec;
193
struct snd_soc_dapm_context *dapm = &codec->dapm;
194
int ret;
195
196
/* Add SDP3430 specific widgets */
197
ret = snd_soc_dapm_new_controls(dapm, sdp3430_twl4030_dapm_widgets,
198
ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
199
if (ret)
200
return ret;
201
202
/* Set up SDP3430 specific audio path audio_map */
203
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
204
205
/* SDP3430 connected pins */
206
snd_soc_dapm_enable_pin(dapm, "Ext Mic");
207
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
208
snd_soc_dapm_disable_pin(dapm, "Headset Mic");
209
snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
210
211
/* TWL4030 not connected pins */
212
snd_soc_dapm_nc_pin(dapm, "AUXL");
213
snd_soc_dapm_nc_pin(dapm, "AUXR");
214
snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
215
snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
216
snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
217
218
snd_soc_dapm_nc_pin(dapm, "OUTL");
219
snd_soc_dapm_nc_pin(dapm, "OUTR");
220
snd_soc_dapm_nc_pin(dapm, "EARPIECE");
221
snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
222
snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
223
snd_soc_dapm_nc_pin(dapm, "CARKITL");
224
snd_soc_dapm_nc_pin(dapm, "CARKITR");
225
226
ret = snd_soc_dapm_sync(dapm);
227
if (ret)
228
return ret;
229
230
/* Headset jack detection */
231
ret = snd_soc_jack_new(codec, "Headset Jack",
232
SND_JACK_HEADSET, &hs_jack);
233
if (ret)
234
return ret;
235
236
ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
237
hs_jack_pins);
238
if (ret)
239
return ret;
240
241
ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
242
hs_jack_gpios);
243
244
return ret;
245
}
246
247
static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
248
{
249
struct snd_soc_codec *codec = rtd->codec;
250
unsigned short reg;
251
252
/* Enable voice interface */
253
reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
254
reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
255
codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
256
257
return 0;
258
}
259
260
261
/* Digital audio interface glue - connects codec <--> CPU */
262
static struct snd_soc_dai_link sdp3430_dai[] = {
263
{
264
.name = "TWL4030 I2S",
265
.stream_name = "TWL4030 Audio",
266
.cpu_dai_name = "omap-mcbsp-dai.1",
267
.codec_dai_name = "twl4030-hifi",
268
.platform_name = "omap-pcm-audio",
269
.codec_name = "twl4030-codec",
270
.init = sdp3430_twl4030_init,
271
.ops = &sdp3430_ops,
272
},
273
{
274
.name = "TWL4030 PCM",
275
.stream_name = "TWL4030 Voice",
276
.cpu_dai_name = "omap-mcbsp-dai.2",
277
.codec_dai_name = "twl4030-voice",
278
.platform_name = "omap-pcm-audio",
279
.codec_name = "twl4030-codec",
280
.init = sdp3430_twl4030_voice_init,
281
.ops = &sdp3430_voice_ops,
282
},
283
};
284
285
/* Audio machine driver */
286
static struct snd_soc_card snd_soc_sdp3430 = {
287
.name = "SDP3430",
288
.dai_link = sdp3430_dai,
289
.num_links = ARRAY_SIZE(sdp3430_dai),
290
};
291
292
static struct platform_device *sdp3430_snd_device;
293
294
static int __init sdp3430_soc_init(void)
295
{
296
int ret;
297
u8 pin_mux;
298
299
if (!machine_is_omap_3430sdp())
300
return -ENODEV;
301
printk(KERN_INFO "SDP3430 SoC init\n");
302
303
sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
304
if (!sdp3430_snd_device) {
305
printk(KERN_ERR "Platform device allocation failed\n");
306
return -ENOMEM;
307
}
308
309
platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430);
310
311
/* Set TWL4030 GPIO6 as EXTMUTE signal */
312
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
313
TWL4030_INTBR_PMBR1);
314
pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03);
315
pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02);
316
twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux,
317
TWL4030_INTBR_PMBR1);
318
319
ret = platform_device_add(sdp3430_snd_device);
320
if (ret)
321
goto err1;
322
323
return 0;
324
325
err1:
326
printk(KERN_ERR "Unable to add platform device\n");
327
platform_device_put(sdp3430_snd_device);
328
329
return ret;
330
}
331
module_init(sdp3430_soc_init);
332
333
static void __exit sdp3430_soc_exit(void)
334
{
335
snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
336
hs_jack_gpios);
337
338
platform_device_unregister(sdp3430_snd_device);
339
}
340
module_exit(sdp3430_soc_exit);
341
342
MODULE_AUTHOR("Misael Lopez Cruz <[email protected]>");
343
MODULE_DESCRIPTION("ALSA SoC SDP3430");
344
MODULE_LICENSE("GPL");
345
346
347