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 <linux/connector.h>
19 #include <linux/slab.h>
22 #include <asm/arch/dma.h>
23 #include <asm/arch/clock.h>
24 #include <asm/arch/gpio.h>
25 #include <asm/arch/mcbsp.h>
26 #include <asm/arch/omap-alsa.h>
28 #include "omap-alsa-sx1.h"
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";
34 static void cn_sx1snd_callback(void *data)
36 struct cn_msg *msg = (struct cn_msg *)data;
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);
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) {
155 egold_rate = FRQ_8000;
159 egold_rate = FRQ_11025;
163 egold_rate = FRQ_12000;
167 egold_rate = FRQ_16000;
171 egold_rate = FRQ_22050;
175 egold_rate = FRQ_24000;
179 egold_rate = FRQ_32000;
183 egold_rate = FRQ_44100;
187 egold_rate = FRQ_48000;
191 srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
192 srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
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);
201 static void egold_configure(void)
206 * Omap MCBSP clock and Power Management configuration
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.
214 * Do clock framework mclk search
216 static void egold_clock_setup(void)
218 omap_request_gpio(OSC_EN);
219 omap_set_gpio_direction(OSC_EN, 0); /* output */
224 * Do some sanity check, set clock rate, starts it and turn codec audio on
226 static int egold_clock_on(void)
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);
237 * Do some sanity check, turn clock off and then turn codec audio off
239 static int egold_clock_off(void)
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);
248 static int egold_get_default_samplerate(void)
251 return DEFAULT_SAMPLE_RATE;
254 static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
257 struct omap_alsa_codec_config *codec_cfg;
259 codec_cfg = pdev->dev.platform_data;
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);
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,
284 .name = "omap_alsa_mcbsp",
288 static int __init omap_alsa_egold_init(void)
292 retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name,
295 printk(KERN_WARNING "cn_sx1snd failed to register\n");
296 return platform_driver_register(&omap_alsa_driver);
299 static void __exit omap_alsa_egold_exit(void)
301 cn_del_callback(&cn_sx1snd_id);
302 platform_driver_unregister(&omap_alsa_driver);
305 module_init(omap_alsa_egold_init);
306 module_exit(omap_alsa_egold_exit);