]> 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 <asm/io.h>
18 #include <asm/arch/mcbsp.h>
19
20 #include <linux/slab.h>
21 #include <linux/pm.h>
22 #include <asm/arch/dma.h>
23 #include <asm/arch/clock.h>
24 #include <asm/arch/gpio.h>
25
26 #include <asm/arch/omap-alsa.h>
27 #include "omap-alsa-sx1.h"
28
29 #include <linux/connector.h>
30
31 /* Connector implementation */
32 static struct cb_id cn_sx1snd_id = { CN_IDX_SX1SND, CN_VAL_SX1SND };
33 static char cn_sx1snd_name[] = "cn_sx1snd";
34
35 static void cn_sx1snd_callback(void *data)
36 {
37         struct cn_msg *msg = (struct cn_msg *)data;
38
39         printk("%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:      clkgdv = 71; egold_rate = FRQ_8000; break;
154                 case 11025:     clkgdv = 51; egold_rate = FRQ_11025; break;
155                 case 12000:     clkgdv = 47; egold_rate = FRQ_12000; break;
156                 case 16000:     clkgdv = 35; egold_rate = FRQ_16000; break;
157                 case 22050:     clkgdv = 25; egold_rate = FRQ_22050; break;
158                 case 24000:     clkgdv = 23; egold_rate = FRQ_24000; break;
159                 case 32000:     clkgdv = 17; egold_rate = FRQ_32000; break;
160                 case 44100:     clkgdv = 12; egold_rate = FRQ_44100; break;
161                 case 48000:     clkgdv = 11; egold_rate = FRQ_48000; break;
162         }
163
164         srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
165         srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
166
167         OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
168         OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
169         current_rate = egold_rate;
170         snd_printd("set samplerate=%ld\n", sample_rate);
171
172 }
173
174 static void egold_configure(void)
175 {
176 }
177
178 /*
179  * Omap MCBSP clock and Power Management configuration
180  *
181  * Here we have some functions that allows clock to be enabled and
182  * disabled only when needed. Besides doing clock configuration
183  * it allows turn on/turn off audio when necessary.
184  */
185
186 /*
187  * Do clock framework mclk search
188  */
189 static void egold_clock_setup(void)
190 {
191         omap_request_gpio(OSC_EN);
192         omap_set_gpio_direction(OSC_EN, 0); /* output */
193         snd_printd("\n");
194 }
195
196 /*
197  * Do some sanity check, set clock rate, starts it and turn codec audio on
198  */
199 static int egold_clock_on(void)
200 {
201         omap_set_gpio_dataout(OSC_EN, 1);
202         egold_set_samplerate(44100); /* TODO */
203         cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
204         cn_sx1snd_send(DAC_OPEN_DEFAULT, current_rate , 4);
205         snd_printd("\n");
206         return 0;
207 }
208
209 /*
210  * Do some sanity check, turn clock off and then turn codec audio off
211  */
212 static int egold_clock_off(void)
213 {
214         cn_sx1snd_send(DAC_CLOSE, 0 , 0);
215         cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
216         omap_set_gpio_dataout(OSC_EN, 0);
217         snd_printd("\n");
218         return 0;
219 }
220
221 static int egold_get_default_samplerate(void)
222 {
223         snd_printd("\n");
224         return DEFAULT_SAMPLE_RATE;
225 }
226
227 static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
228 {
229         int ret;
230         struct omap_alsa_codec_config *codec_cfg;
231
232         codec_cfg = pdev->dev.platform_data;
233         if (!codec_cfg)
234                 return -ENODEV;
235
236         codec_cfg->hw_constraints_rates = &egold_hw_constraints_rates;
237         codec_cfg->snd_omap_alsa_playback= &egold_snd_omap_alsa_playback;
238         codec_cfg->snd_omap_alsa_capture  = &egold_snd_omap_alsa_capture;
239         codec_cfg->codec_configure_dev  = egold_configure;
240         codec_cfg->codec_set_samplerate = egold_set_samplerate;
241         codec_cfg->codec_clock_setup    = egold_clock_setup;
242         codec_cfg->codec_clock_on       = egold_clock_on;
243         codec_cfg->codec_clock_off      = egold_clock_off;
244         codec_cfg->get_default_samplerate = egold_get_default_samplerate;
245         ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
246
247         snd_printd("\n");
248         return ret;
249 }
250
251 static struct platform_driver omap_alsa_driver = {
252         .probe          = snd_omap_alsa_egold_probe,
253         .remove         = snd_omap_alsa_remove,
254         .suspend        = snd_omap_alsa_suspend,
255         .resume         = snd_omap_alsa_resume,
256         .driver = {
257                 .name = "omap_alsa_mcbsp",
258         },
259 };
260
261 static int __init omap_alsa_egold_init(void)
262 {
263         int retval;
264
265         retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name, cn_sx1snd_callback);
266         if (retval)
267                 printk(KERN_WARNING "cn_sx1snd failed to register\n");
268         return platform_driver_register(&omap_alsa_driver);
269 }
270
271 static void __exit omap_alsa_egold_exit(void)
272 {
273         cn_del_callback(&cn_sx1snd_id);
274         platform_driver_unregister(&omap_alsa_driver);
275 }
276
277 module_init(omap_alsa_egold_init);
278 module_exit(omap_alsa_egold_exit);