2 * Alsa codec Driver for Siemens SX1 board.
3 * based on omap-alsa-tsc2101.c and cn_test.c example by Evgeniy Polyakov
5 * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
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.
13 #include <linux/delay.h>
14 #include <linux/soundcard.h>
15 #include <linux/platform_device.h>
16 #include <linux/clk.h>
18 #include <asm/arch/mcbsp.h>
20 #include <linux/slab.h>
22 #include <asm/arch/dma.h>
23 #include <asm/arch/clock.h>
24 #include <asm/arch/gpio.h>
26 #include <asm/arch/omap-alsa.h>
27 #include "omap-alsa-sx1.h"
29 #include <linux/connector.h>
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";
35 static void cn_sx1snd_callback(void *data)
37 struct cn_msg *msg = (struct cn_msg *)data;
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);
44 /* Send IPC message to sound server */
45 int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2)
48 unsigned short data[3];
51 m = kzalloc(sizeof(*m) + sizeof(data), gfp_any());
55 memcpy(&m->id, &cn_sx1snd_id, sizeof(m->id));
57 m->len = sizeof(data);
59 data[0] = (unsigned short)cmd;
60 data[1] = (unsigned short)arg1;
61 data[2] = (unsigned short)arg2;
63 memcpy(m + 1, data, m->len);
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);
70 return -1; /* there are no listeners on socket */
74 /* Hardware capabilities
76 * DAC USB-mode sampling rates (MCLK = 12 MHz)
77 * The rates and rate_reg_into MUST be in the same order
79 static unsigned int rates[] = {
85 static struct snd_pcm_hw_constraint_list egold_hw_constraints_rates = {
86 .count = ARRAY_SIZE(rates),
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 |
104 .buffer_bytes_max = 128 * 1024,
105 .period_bytes_min = 32,
106 .period_bytes_max = 8 * 1024,
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),
125 .buffer_bytes_max = 128 * 1024,
126 .period_bytes_min = 32,
127 .period_bytes_max = 8 * 1024,
133 static long current_rate = -1; /* current rate in egold format 0..8 */
135 * ALSA operations according to board file
139 * Sample rate changing
141 static void egold_set_samplerate(long sample_rate)
147 /* Set the sample rate */
149 /* fw15: 5005E490 - divs are different !!! */
150 clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
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;
164 srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
165 srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
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);
174 static void egold_configure(void)
179 * Omap MCBSP clock and Power Management configuration
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.
187 * Do clock framework mclk search
189 static void egold_clock_setup(void)
191 omap_request_gpio(OSC_EN);
192 omap_set_gpio_direction(OSC_EN, 0); /* output */
197 * Do some sanity check, set clock rate, starts it and turn codec audio on
199 static int egold_clock_on(void)
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);
210 * Do some sanity check, turn clock off and then turn codec audio off
212 static int egold_clock_off(void)
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);
221 static int egold_get_default_samplerate(void)
224 return DEFAULT_SAMPLE_RATE;
227 static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
230 struct omap_alsa_codec_config *codec_cfg;
232 codec_cfg = pdev->dev.platform_data;
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);
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,
257 .name = "omap_alsa_mcbsp",
261 static int __init omap_alsa_egold_init(void)
265 retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name, cn_sx1snd_callback);
267 printk(KERN_WARNING "cn_sx1snd failed to register\n");
268 return platform_driver_register(&omap_alsa_driver);
271 static void __exit omap_alsa_egold_exit(void)
273 cn_del_callback(&cn_sx1snd_id);
274 platform_driver_unregister(&omap_alsa_driver);
277 module_init(omap_alsa_egold_init);
278 module_exit(omap_alsa_egold_exit);