~ubuntu-branches/ubuntu/maverick/linux-backports-modules-2.6.32/maverick

« back to all changes in this revision

Viewing changes to updates/alsa-driver/alsa-kernel/soc/omap/n810.c

  • Committer: Bazaar Package Importer
  • Author(s): Andy Whitcroft, Andy Whitcroft
  • Date: 2010-02-04 23:15:51 UTC
  • Revision ID: james.westby@ubuntu.com-20100204231551-vjz5pkvxclukjxm1
Tags: 2.6.32-12.1
[ Andy Whitcroft ]

* initial LBM for lucid
* drop generated files
* printchanges -- rebase tree does not have stable tags use changelog
* printenv -- add revisions to printenv output
* formally rename compat-wireless to linux-backports-modules-wireless
* Update to compat-wireless-2.6.33-rc5
* update nouveau to mainline 2.6.33-rc4
* add new LBM package for nouveau
* nouveau -- fix major numbers and proc entry names
* fix up firmware installs for -wireless
* clean up UPDATE-NOVEAU
* update Nouveau to v2.6.33-rc6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * n810.c  --  SoC audio for Nokia N810
 
3
 *
 
4
 * Copyright (C) 2008 Nokia Corporation
 
5
 *
 
6
 * Contact: Jarkko Nikula <jhnikula@gmail.com>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License
 
10
 * version 2 as published by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
20
 * 02110-1301 USA
 
21
 *
 
22
 */
 
23
 
 
24
#include <linux/clk.h>
 
25
#include <linux/i2c.h>
 
26
#include <linux/platform_device.h>
 
27
#include <sound/core.h>
 
28
#include <sound/pcm.h>
 
29
#include <sound/soc.h>
 
30
#include <sound/soc-dapm.h>
 
31
 
 
32
#include <asm/mach-types.h>
 
33
#include <mach/hardware.h>
 
34
#include <linux/gpio.h>
 
35
#include <plat/mcbsp.h>
 
36
 
 
37
#include "omap-mcbsp.h"
 
38
#include "omap-pcm.h"
 
39
#include "../codecs/tlv320aic3x.h"
 
40
 
 
41
#define N810_HEADSET_AMP_GPIO   10
 
42
#define N810_SPEAKER_AMP_GPIO   101
 
43
 
 
44
enum {
 
45
        N810_JACK_DISABLED,
 
46
        N810_JACK_HP,
 
47
        N810_JACK_HS,
 
48
        N810_JACK_MIC,
 
49
};
 
50
 
 
51
static struct clk *sys_clkout2;
 
52
static struct clk *sys_clkout2_src;
 
53
static struct clk *func96m_clk;
 
54
 
 
55
static int n810_spk_func;
 
56
static int n810_jack_func;
 
57
static int n810_dmic_func;
 
58
 
 
59
static void n810_ext_control(struct snd_soc_codec *codec)
 
60
{
 
61
        int hp = 0, line1l = 0;
 
62
 
 
63
        switch (n810_jack_func) {
 
64
        case N810_JACK_HS:
 
65
                line1l = 1;
 
66
        case N810_JACK_HP:
 
67
                hp = 1;
 
68
                break;
 
69
        case N810_JACK_MIC:
 
70
                line1l = 1;
 
71
                break;
 
72
        }
 
73
 
 
74
        if (n810_spk_func)
 
75
                snd_soc_dapm_enable_pin(codec, "Ext Spk");
 
76
        else
 
77
                snd_soc_dapm_disable_pin(codec, "Ext Spk");
 
78
 
 
79
        if (hp)
 
80
                snd_soc_dapm_enable_pin(codec, "Headphone Jack");
 
81
        else
 
82
                snd_soc_dapm_disable_pin(codec, "Headphone Jack");
 
83
        if (line1l)
 
84
                snd_soc_dapm_enable_pin(codec, "LINE1L");
 
85
        else
 
86
                snd_soc_dapm_disable_pin(codec, "LINE1L");
 
87
 
 
88
        if (n810_dmic_func)
 
89
                snd_soc_dapm_enable_pin(codec, "DMic");
 
90
        else
 
91
                snd_soc_dapm_disable_pin(codec, "DMic");
 
92
 
 
93
        snd_soc_dapm_sync(codec);
 
94
}
 
95
 
 
96
static int n810_startup(struct snd_pcm_substream *substream)
 
97
{
 
98
        struct snd_pcm_runtime *runtime = substream->runtime;
 
99
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
100
        struct snd_soc_codec *codec = rtd->socdev->card->codec;
 
101
 
 
102
        snd_pcm_hw_constraint_minmax(runtime,
 
103
                                     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
 
104
 
 
105
        n810_ext_control(codec);
 
106
        return clk_enable(sys_clkout2);
 
107
}
 
108
 
 
109
static void n810_shutdown(struct snd_pcm_substream *substream)
 
110
{
 
111
        clk_disable(sys_clkout2);
 
112
}
 
113
 
 
114
static int n810_hw_params(struct snd_pcm_substream *substream,
 
115
        struct snd_pcm_hw_params *params)
 
116
{
 
117
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
118
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
 
119
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
120
        int err;
 
121
 
 
122
        /* Set codec DAI configuration */
 
123
        err = snd_soc_dai_set_fmt(codec_dai,
 
124
                                         SND_SOC_DAIFMT_I2S |
 
125
                                         SND_SOC_DAIFMT_NB_NF |
 
126
                                         SND_SOC_DAIFMT_CBM_CFM);
 
127
        if (err < 0)
 
128
                return err;
 
129
 
 
130
        /* Set cpu DAI configuration */
 
131
        err = snd_soc_dai_set_fmt(cpu_dai,
 
132
                                       SND_SOC_DAIFMT_I2S |
 
133
                                       SND_SOC_DAIFMT_NB_NF |
 
134
                                       SND_SOC_DAIFMT_CBM_CFM);
 
135
        if (err < 0)
 
136
                return err;
 
137
 
 
138
        /* Set the codec system clock for DAC and ADC */
 
139
        err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
 
140
                                            SND_SOC_CLOCK_IN);
 
141
 
 
142
        return err;
 
143
}
 
144
 
 
145
static struct snd_soc_ops n810_ops = {
 
146
        .startup = n810_startup,
 
147
        .hw_params = n810_hw_params,
 
148
        .shutdown = n810_shutdown,
 
149
};
 
150
 
 
151
static int n810_get_spk(struct snd_kcontrol *kcontrol,
 
152
                        struct snd_ctl_elem_value *ucontrol)
 
153
{
 
154
        ucontrol->value.integer.value[0] = n810_spk_func;
 
155
 
 
156
        return 0;
 
157
}
 
158
 
 
159
static int n810_set_spk(struct snd_kcontrol *kcontrol,
 
160
                        struct snd_ctl_elem_value *ucontrol)
 
161
{
 
162
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
 
163
 
 
164
        if (n810_spk_func == ucontrol->value.integer.value[0])
 
165
                return 0;
 
166
 
 
167
        n810_spk_func = ucontrol->value.integer.value[0];
 
168
        n810_ext_control(codec);
 
169
 
 
170
        return 1;
 
171
}
 
172
 
 
173
static int n810_get_jack(struct snd_kcontrol *kcontrol,
 
174
                         struct snd_ctl_elem_value *ucontrol)
 
175
{
 
176
        ucontrol->value.integer.value[0] = n810_jack_func;
 
177
 
 
178
        return 0;
 
179
}
 
180
 
 
181
static int n810_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 (n810_jack_func == ucontrol->value.integer.value[0])
 
187
                return 0;
 
188
 
 
189
        n810_jack_func = ucontrol->value.integer.value[0];
 
190
        n810_ext_control(codec);
 
191
 
 
192
        return 1;
 
193
}
 
194
 
 
195
static int n810_get_input(struct snd_kcontrol *kcontrol,
 
196
                          struct snd_ctl_elem_value *ucontrol)
 
197
{
 
198
        ucontrol->value.integer.value[0] = n810_dmic_func;
 
199
 
 
200
        return 0;
 
201
}
 
202
 
 
203
static int n810_set_input(struct snd_kcontrol *kcontrol,
 
204
                          struct snd_ctl_elem_value *ucontrol)
 
205
{
 
206
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
 
207
 
 
208
        if (n810_dmic_func == ucontrol->value.integer.value[0])
 
209
                return 0;
 
210
 
 
211
        n810_dmic_func = ucontrol->value.integer.value[0];
 
212
        n810_ext_control(codec);
 
213
 
 
214
        return 1;
 
215
}
 
216
 
 
217
static int n810_spk_event(struct snd_soc_dapm_widget *w,
 
218
                          struct snd_kcontrol *k, int event)
 
219
{
 
220
        if (SND_SOC_DAPM_EVENT_ON(event))
 
221
                gpio_set_value(N810_SPEAKER_AMP_GPIO, 1);
 
222
        else
 
223
                gpio_set_value(N810_SPEAKER_AMP_GPIO, 0);
 
224
 
 
225
        return 0;
 
226
}
 
227
 
 
228
static int n810_jack_event(struct snd_soc_dapm_widget *w,
 
229
                           struct snd_kcontrol *k, int event)
 
230
{
 
231
        if (SND_SOC_DAPM_EVENT_ON(event))
 
232
                gpio_set_value(N810_HEADSET_AMP_GPIO, 1);
 
233
        else
 
234
                gpio_set_value(N810_HEADSET_AMP_GPIO, 0);
 
235
 
 
236
        return 0;
 
237
}
 
238
 
 
239
static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
 
240
        SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
 
241
        SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
 
242
        SND_SOC_DAPM_MIC("DMic", NULL),
 
243
};
 
244
 
 
245
static const struct snd_soc_dapm_route audio_map[] = {
 
246
        {"Headphone Jack", NULL, "HPLOUT"},
 
247
        {"Headphone Jack", NULL, "HPROUT"},
 
248
 
 
249
        {"Ext Spk", NULL, "LLOUT"},
 
250
        {"Ext Spk", NULL, "RLOUT"},
 
251
 
 
252
        {"DMic Rate 64", NULL, "Mic Bias 2V"},
 
253
        {"Mic Bias 2V", NULL, "DMic"},
 
254
};
 
255
 
 
256
static const char *spk_function[] = {"Off", "On"};
 
257
static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"};
 
258
static const char *input_function[] = {"ADC", "Digital Mic"};
 
259
static const struct soc_enum n810_enum[] = {
 
260
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
 
261
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
 
262
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
 
263
};
 
264
 
 
265
static const struct snd_kcontrol_new aic33_n810_controls[] = {
 
266
        SOC_ENUM_EXT("Speaker Function", n810_enum[0],
 
267
                     n810_get_spk, n810_set_spk),
 
268
        SOC_ENUM_EXT("Jack Function", n810_enum[1],
 
269
                     n810_get_jack, n810_set_jack),
 
270
        SOC_ENUM_EXT("Input Select",  n810_enum[2],
 
271
                     n810_get_input, n810_set_input),
 
272
};
 
273
 
 
274
static int n810_aic33_init(struct snd_soc_codec *codec)
 
275
{
 
276
        int err;
 
277
 
 
278
        /* Not connected */
 
279
        snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
 
280
        snd_soc_dapm_nc_pin(codec, "HPLCOM");
 
281
        snd_soc_dapm_nc_pin(codec, "HPRCOM");
 
282
        snd_soc_dapm_nc_pin(codec, "MIC3L");
 
283
        snd_soc_dapm_nc_pin(codec, "MIC3R");
 
284
        snd_soc_dapm_nc_pin(codec, "LINE1R");
 
285
        snd_soc_dapm_nc_pin(codec, "LINE2L");
 
286
        snd_soc_dapm_nc_pin(codec, "LINE2R");
 
287
 
 
288
        /* Add N810 specific controls */
 
289
        err = snd_soc_add_controls(codec, aic33_n810_controls,
 
290
                                ARRAY_SIZE(aic33_n810_controls));
 
291
        if (err < 0)
 
292
                return err;
 
293
 
 
294
        /* Add N810 specific widgets */
 
295
        snd_soc_dapm_new_controls(codec, aic33_dapm_widgets,
 
296
                                  ARRAY_SIZE(aic33_dapm_widgets));
 
297
 
 
298
        /* Set up N810 specific audio path audio_map */
 
299
        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
300
 
 
301
        snd_soc_dapm_sync(codec);
 
302
 
 
303
        return 0;
 
304
}
 
305
 
 
306
/* Digital audio interface glue - connects codec <--> CPU */
 
307
static struct snd_soc_dai_link n810_dai = {
 
308
        .name = "TLV320AIC33",
 
309
        .stream_name = "AIC33",
 
310
        .cpu_dai = &omap_mcbsp_dai[0],
 
311
        .codec_dai = &aic3x_dai,
 
312
        .init = n810_aic33_init,
 
313
        .ops = &n810_ops,
 
314
};
 
315
 
 
316
/* Audio machine driver */
 
317
static struct snd_soc_card snd_soc_n810 = {
 
318
        .name = "N810",
 
319
        .platform = &omap_soc_platform,
 
320
        .dai_link = &n810_dai,
 
321
        .num_links = 1,
 
322
};
 
323
 
 
324
/* Audio private data */
 
325
static struct aic3x_setup_data n810_aic33_setup = {
 
326
        .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
 
327
        .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
 
328
};
 
329
 
 
330
/* Audio subsystem */
 
331
static struct snd_soc_device n810_snd_devdata = {
 
332
        .card = &snd_soc_n810,
 
333
        .codec_dev = &soc_codec_dev_aic3x,
 
334
        .codec_data = &n810_aic33_setup,
 
335
};
 
336
 
 
337
static struct platform_device *n810_snd_device;
 
338
 
 
339
/* temporary i2c device creation until this can be moved into the machine
 
340
 * support file.
 
341
*/
 
342
static struct i2c_board_info i2c_device[] = {
 
343
        { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }
 
344
};
 
345
 
 
346
static int __init n810_soc_init(void)
 
347
{
 
348
        int err;
 
349
        struct device *dev;
 
350
 
 
351
        if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
 
352
                return -ENODEV;
 
353
 
 
354
        i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device));
 
355
 
 
356
        n810_snd_device = platform_device_alloc("soc-audio", -1);
 
357
        if (!n810_snd_device)
 
358
                return -ENOMEM;
 
359
 
 
360
        platform_set_drvdata(n810_snd_device, &n810_snd_devdata);
 
361
        n810_snd_devdata.dev = &n810_snd_device->dev;
 
362
        *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */
 
363
        err = platform_device_add(n810_snd_device);
 
364
        if (err)
 
365
                goto err1;
 
366
 
 
367
        dev = &n810_snd_device->dev;
 
368
 
 
369
        sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
 
370
        if (IS_ERR(sys_clkout2_src)) {
 
371
                dev_err(dev, "Could not get sys_clkout2_src clock\n");
 
372
                err = PTR_ERR(sys_clkout2_src);
 
373
                goto err2;
 
374
        }
 
375
        sys_clkout2 = clk_get(dev, "sys_clkout2");
 
376
        if (IS_ERR(sys_clkout2)) {
 
377
                dev_err(dev, "Could not get sys_clkout2\n");
 
378
                err = PTR_ERR(sys_clkout2);
 
379
                goto err3;
 
380
        }
 
381
        /*
 
382
         * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
 
383
         * 96 MHz as its parent in order to get 12 MHz
 
384
         */
 
385
        func96m_clk = clk_get(dev, "func_96m_ck");
 
386
        if (IS_ERR(func96m_clk)) {
 
387
                dev_err(dev, "Could not get func 96M clock\n");
 
388
                err = PTR_ERR(func96m_clk);
 
389
                goto err4;
 
390
        }
 
391
        clk_set_parent(sys_clkout2_src, func96m_clk);
 
392
        clk_set_rate(sys_clkout2, 12000000);
 
393
 
 
394
        BUG_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
 
395
               (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0));
 
396
 
 
397
        gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
 
398
        gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
 
399
 
 
400
        return 0;
 
401
err4:
 
402
        clk_put(sys_clkout2);
 
403
err3:
 
404
        clk_put(sys_clkout2_src);
 
405
err2:
 
406
        platform_device_del(n810_snd_device);
 
407
err1:
 
408
        platform_device_put(n810_snd_device);
 
409
 
 
410
        return err;
 
411
}
 
412
 
 
413
static void __exit n810_soc_exit(void)
 
414
{
 
415
        gpio_free(N810_SPEAKER_AMP_GPIO);
 
416
        gpio_free(N810_HEADSET_AMP_GPIO);
 
417
        clk_put(sys_clkout2_src);
 
418
        clk_put(sys_clkout2);
 
419
        clk_put(func96m_clk);
 
420
 
 
421
        platform_device_unregister(n810_snd_device);
 
422
}
 
423
 
 
424
module_init(n810_soc_init);
 
425
module_exit(n810_soc_exit);
 
426
 
 
427
MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
 
428
MODULE_DESCRIPTION("ALSA SoC Nokia N810");
 
429
MODULE_LICENSE("GPL");