]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa-sx1.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / sound / arm / omap / omap-alsa-sx1.c
1 /*
2  * Alsa codec Driver for Siemens SX1 board.
3  * based on omap-alsa-tsc2101.c and cn_test.c example by Evgeniy Polyakov
4  *
5  * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2 of the License, or (at your
10  * option) any later version.
11  */
12
13 #include <linux/delay.h>
14 #include <linux/soundcard.h>
15 #include <linux/platform_device.h>
16 #include <linux/clk.h>
17 #include <linux/io.h>
18 #include <linux/connector.h>
19 #include <linux/slab.h>
20 #include <linux/pm.h>
21
22 #include <mach/dma.h>
23 #include <mach/clock.h>
24 #include <mach/gpio.h>
25 #include <mach/mcbsp.h>
26 #include <mach/omap-alsa.h>
27
28 #include "omap-alsa-sx1.h"
29
30 /* Connector implementation */
31 static struct cb_id cn_sx1snd_id = { CN_IDX_SX1SND, CN_VAL_SX1SND };
32 static char cn_sx1snd_name[] = "cn_sx1snd";
33
34 static void cn_sx1snd_callback(void *data)
35 {
36         struct cn_msg *msg = (struct cn_msg *)data;
37
38         printk(KERN_INFO
39                 "%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
40                 __func__, jiffies, msg->id.idx, msg->id.val,
41                 msg->seq, msg->ack, msg->len, (char *)msg->data);
42 }
43
44 /* Send IPC message to sound server */
45 int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2)
46 {
47         struct cn_msg *m;
48         unsigned short data[3];
49         int err;
50
51         m = kzalloc(sizeof(*m) + sizeof(data), gfp_any());
52         if (!m)
53                 return -1;
54
55         memcpy(&m->id, &cn_sx1snd_id, sizeof(m->id));
56         m->seq = 1;
57         m->len = sizeof(data);
58
59         data[0] = (unsigned short)cmd;
60         data[1] = (unsigned short)arg1;
61         data[2] = (unsigned short)arg2;
62
63         memcpy(m + 1, data, m->len);
64
65         err = cn_netlink_send(m, CN_IDX_SX1SND, gfp_any());
66         snd_printd("sent= %02X %02X %02X, err=%d\n", cmd, arg1, arg2, err);
67         kfree(m);
68
69         if (err == -ESRCH)
70                 return -1;      /* there are no listeners on socket */
71         return 0;
72 }
73
74 /* Hardware capabilities
75  *
76  * DAC USB-mode sampling rates (MCLK = 12 MHz)
77  * The rates and rate_reg_into MUST be in the same order
78  */
79 static unsigned int rates[] = {
80          8000, 11025, 12000,
81          16000, 22050, 24000,
82          32000, 44100, 48000,
83 };
84
85 static struct snd_pcm_hw_constraint_list egold_hw_constraints_rates = {
86         .count  = ARRAY_SIZE(rates),
87         .list   = rates,
88         .mask   = 0,
89 };
90
91 static struct snd_pcm_hardware egold_snd_omap_alsa_playback = {
92         .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
93                  SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
94         .formats = (SNDRV_PCM_FMTBIT_S16_LE),
95         .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
96                   SNDRV_PCM_RATE_16000 |
97                   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
98                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
99                   SNDRV_PCM_RATE_KNOT),
100         .rate_min               = 8000,
101         .rate_max               = 48000,
102         .channels_min           = 2,
103         .channels_max           = 2,
104         .buffer_bytes_max       = 128 * 1024,
105         .period_bytes_min       = 32,
106         .period_bytes_max       = 8 * 1024,
107         .periods_min            = 16,
108         .periods_max            = 255,
109         .fifo_size              = 0,
110 };
111
112 static struct snd_pcm_hardware egold_snd_omap_alsa_capture = {
113         .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
114                  SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
115         .formats = (SNDRV_PCM_FMTBIT_S16_LE),
116         .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
117                   SNDRV_PCM_RATE_16000 |
118                   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
119                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
120                   SNDRV_PCM_RATE_KNOT),
121         .rate_min               = 8000,
122         .rate_max               = 48000,
123         .channels_min           = 2,
124         .channels_max           = 2,
125         .buffer_bytes_max       = 128 * 1024,
126         .period_bytes_min       = 32,
127         .period_bytes_max       = 8 * 1024,
128         .periods_min            = 16,
129         .periods_max            = 255,
130         .fifo_size              = 0,
131 };
132
133 static long current_rate = -1; /* current rate in egold format 0..8 */
134 /*
135  * ALSA operations according to board file
136  */
137
138 /*
139  * Sample rate changing
140  */
141 static void egold_set_samplerate(long sample_rate)
142 {
143         int egold_rate = 0;
144         int clkgdv = 0;
145         u16 srgr1, srgr2;
146
147         /* Set the sample rate */
148 #if 0
149         /* fw15: 5005E490 - divs are different !!! */
150         clkgdv  = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
151 #endif
152         switch (sample_rate) {
153         case 8000:
154                 clkgdv = 71;
155                 egold_rate = FRQ_8000;
156                 break;
157         case 11025:
158                 clkgdv = 51;
159                 egold_rate = FRQ_11025;
160                 break;
161         case 12000:
162                 clkgdv = 47;
163                 egold_rate = FRQ_12000;
164                 break;
165         case 16000:
166                 clkgdv = 35;
167                 egold_rate = FRQ_16000;
168                 break;
169         case 22050:
170                 clkgdv = 25;
171                 egold_rate = FRQ_22050;
172                 break;
173         case 24000:
174                 clkgdv = 23;
175                 egold_rate = FRQ_24000;
176                 break;
177         case 32000:
178                 clkgdv = 17;
179                 egold_rate = FRQ_32000;
180                 break;
181         case 44100:
182                 clkgdv = 12;
183                 egold_rate = FRQ_44100;
184                 break;
185         case 48000:
186                 clkgdv = 11;
187                 egold_rate = FRQ_48000;
188                 break;
189         }
190
191         srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
192         srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
193
194         OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
195         OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
196         current_rate = egold_rate;
197         snd_printd("set samplerate=%ld\n", sample_rate);
198
199 }
200
201 static void egold_configure(void)
202 {
203 }
204
205 /*
206  * Omap MCBSP clock and Power Management configuration
207  *
208  * Here we have some functions that allows clock to be enabled and
209  * disabled only when needed. Besides doing clock configuration
210  * it allows turn on/turn off audio when necessary.
211  */
212
213 /*
214  * Do clock framework mclk search
215  */
216 static void egold_clock_setup(void)
217 {
218         omap_request_gpio(OSC_EN);
219         omap_set_gpio_direction(OSC_EN, 0); /* output */
220         snd_printd("\n");
221 }
222
223 /*
224  * Do some sanity check, set clock rate, starts it and turn codec audio on
225  */
226 static int egold_clock_on(void)
227 {
228         omap_set_gpio_dataout(OSC_EN, 1);
229         egold_set_samplerate(44100); /* TODO */
230         cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
231         cn_sx1snd_send(DAC_OPEN_DEFAULT, current_rate , 4);
232         snd_printd("\n");
233         return 0;
234 }
235
236 /*
237  * Do some sanity check, turn clock off and then turn codec audio off
238  */
239 static int egold_clock_off(void)
240 {
241         cn_sx1snd_send(DAC_CLOSE, 0 , 0);
242         cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
243         omap_set_gpio_dataout(OSC_EN, 0);
244         snd_printd("\n");
245         return 0;
246 }
247
248 static int egold_get_default_samplerate(void)
249 {
250         snd_printd("\n");
251         return DEFAULT_SAMPLE_RATE;
252 }
253
254 static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
255 {
256         int ret;
257         struct omap_alsa_codec_config *codec_cfg;
258
259         codec_cfg = pdev->dev.platform_data;
260         if (!codec_cfg)
261                 return -ENODEV;
262
263         codec_cfg->hw_constraints_rates = &egold_hw_constraints_rates;
264         codec_cfg->snd_omap_alsa_playback = &egold_snd_omap_alsa_playback;
265         codec_cfg->snd_omap_alsa_capture = &egold_snd_omap_alsa_capture;
266         codec_cfg->codec_configure_dev  = egold_configure;
267         codec_cfg->codec_set_samplerate = egold_set_samplerate;
268         codec_cfg->codec_clock_setup    = egold_clock_setup;
269         codec_cfg->codec_clock_on       = egold_clock_on;
270         codec_cfg->codec_clock_off      = egold_clock_off;
271         codec_cfg->get_default_samplerate = egold_get_default_samplerate;
272         ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
273
274         snd_printd("\n");
275         return ret;
276 }
277
278 static struct platform_driver omap_alsa_driver = {
279         .probe          = snd_omap_alsa_egold_probe,
280         .remove         = snd_omap_alsa_remove,
281         .suspend        = snd_omap_alsa_suspend,
282         .resume         = snd_omap_alsa_resume,
283         .driver = {
284                 .name = "omap_alsa_mcbsp",
285         },
286 };
287
288 static int __init omap_alsa_egold_init(void)
289 {
290         int retval;
291
292         retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name,
293                                         cn_sx1snd_callback);
294         if (retval)
295                 printk(KERN_WARNING "cn_sx1snd failed to register\n");
296         return platform_driver_register(&omap_alsa_driver);
297 }
298
299 static void __exit omap_alsa_egold_exit(void)
300 {
301         cn_del_callback(&cn_sx1snd_id);
302         platform_driver_unregister(&omap_alsa_driver);
303 }
304
305 module_init(omap_alsa_egold_init);
306 module_exit(omap_alsa_egold_exit);