* [PATCH] Alsa modularisations and support for tsc2101 5/7
@ 2006-02-20 18:27 lamikr
0 siblings, 0 replies; only message in thread
From: lamikr @ 2006-02-20 18:27 UTC (permalink / raw)
To: OMAP-Linux
[-- Attachment #1: Type: text/plain, Size: 387 bytes --]
ALSA Omap Patch
This patch only moves all alsa files from sound/arm to sound/arm/omap
as recomended in "writing an alsa driver" documentation at
http://www.alsa-project.org/~iwai/writing-an-alsa-driver/index.html
if the driver contains several source files.
signed-off by Daniel Petrini <d.pensator@gmail.com>
signed-off by Mika Laitio <lamikr@cc.jyu.fi>
----------------
Mika Laitio
[-- Attachment #2: alsa5-20060214.patch --]
[-- Type: text/x-patch, Size: 100702 bytes --]
ALSA Omap Patch
This patch only moves all the alsa files from sound/arm to sound/arm/omap
as recomended in alsa documentation, as pointed by Mika Laitio.
signed-off by Daniel Petrini <d.pensator@gmail.com>
signed-off by Mika Laitio <lamikr@cc.jyu.fi>
Index: linux-omap-2.6.git-q/sound/arm/omap/omap-alsa.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-omap-2.6.git-q/sound/arm/omap/omap-alsa.c 2006-02-16 08:40:57.000000000 -0400
@@ -0,0 +1,714 @@
+/*
+ * sound/arm/omap/omap-alsa.c
+ *
+ * Alsa Driver for AIC23 codec on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Based on sa11xx-uda1341.c,
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-07-29 INdT Kernel Team - Alsa driver for omap osk. Creation of new
+ * file omap-aic23.c
+ *
+ * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ *
+ * 2006-02-07 Daniel Petrini - Codec specific function separated. File renamed to
+ * omap-alsa.c
+ * 2006-02-10 Mika Laitio - Codec specific function pointers are set in the codec.
+ * Default samplerate queried from the codec.
+ */
+
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+#include <sound/driver.h>
+#include <sound/core.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-dma.h"
+
+MODULE_AUTHOR("Mika Laitio, Daniel Petrini, David Cohen, Anderson Briglia - INdT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP driver for ALSA");
+MODULE_ALIAS("omap_alsa_mcbsp.1");
+
+static char *id = NULL;
+static struct snd_card_omap_codec *alsa_codec = NULL;
+static struct omap_alsa_codec_config *alsa_codec_config = NULL;
+
+/*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+ 4000, 8000, 16000, 22050,
+ 24000, 32000, 44100,
+ 48000, 88200, 96000,
+};
+
+static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+ omap_mcbsp_start(AUDIO_MCBSP);
+ return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ return 0;
+}
+
+static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
+{
+ /* Setup DMA stuff */
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
+ SNDRV_PCM_STREAM_PLAYBACK;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
+ OMAP_DMA_MCBSP1_TX;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
+ audio_ifc_start;
+ omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
+ audio_ifc_stop;
+
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
+ SNDRV_PCM_STREAM_CAPTURE;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
+ OMAP_DMA_MCBSP1_RX;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
+ audio_ifc_start;
+ omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
+ audio_ifc_stop;
+}
+
+/*
+ * DMA functions
+ * Depends on omap-alsa-dma.c functions and (omap) dma.c
+ *
+ */
+#define DMA_BUF_SIZE 1024 * 8
+
+static int audio_dma_request(struct audio_stream *s,
+ void (*callback) (void *))
+{
+ int err;
+ ADEBUG();
+
+ err = omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "unable to grab audio dma 0x%x\n",
+ s->dma_dev);
+ return err;
+}
+
+static int audio_dma_free(struct audio_stream *s)
+{
+ int err = 0;
+ ADEBUG();
+
+ err = omap_free_sound_dma(s, &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "Unable to free audio dma channels!\n");
+ return err;
+}
+
+/*
+ * This function should calculate the current position of the dma in the
+ * buffer. It will help alsa middle layer to continue update the buffer.
+ * Its correctness is crucial for good functioning.
+ */
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ unsigned int offset;
+ unsigned long flags;
+ dma_addr_t count;
+ ADEBUG();
+
+ /* this must be called w/ interrupts locked as requested in dma.c */
+ spin_lock_irqsave(&s->dma_lock, flags);
+
+ /* For the current period let's see where we are */
+ count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+
+ /* Now, the position related to the end of that period */
+ offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
+
+ if (offset >= runtime->buffer_size || offset < 0)
+ offset = 0;
+
+ return offset;
+}
+
+/*
+ * this stops the dma and clears the dma ptrs
+ */
+static void audio_stop_dma(struct audio_stream *s)
+{
+ unsigned long flags;
+ ADEBUG();
+
+ spin_lock_irqsave(&s->dma_lock, flags);
+ s->active = 0;
+ s->period = 0;
+ s->periods = 0;
+
+ /* this stops the dma channel and clears the buffer ptrs */
+ omap_audio_stop_dma(s);
+
+ omap_clear_sound_dma(s);
+
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+/*
+ * Main dma routine, requests dma according where you are in main alsa buffer
+ */
+static void audio_process_dma(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime;
+ unsigned int dma_size;
+ unsigned int offset;
+ int ret;
+#ifdef CONFIG_MACH_OMAP_H6300
+ unsigned long flags;
+#endif
+
+ ADEBUG();
+ runtime = substream->runtime;
+ if (s->active) {
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ offset = dma_size * s->period;
+ snd_assert(dma_size <= DMA_BUF_SIZE,);
+#ifdef CONFIG_MACH_OMAP_H6300
+ spin_lock_irqsave(&s->dma_lock, flags);
+ omap_audio_stop_dma(s);
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+#endif
+ ret = omap_start_sound_dma(s,
+ (dma_addr_t) runtime->dma_area +
+ offset, dma_size);
+ if (ret) {
+ printk(KERN_ERR
+ "audio_process_dma: cannot queue DMA buffer (%i)\n",
+ ret);
+ return;
+ }
+
+ s->period++;
+ s->period %= runtime->periods;
+ s->periods++;
+ s->offset = offset;
+ }
+}
+
+/*
+ * This is called when dma IRQ occurs at the end of each transmited block
+ */
+void audio_dma_callback(void *data)
+{
+ struct audio_stream *s = data;
+ ADEBUG();
+
+ /*
+ * If we are getting a callback for an active stream then we inform
+ * the PCM middle layer we've finished a period
+ */
+ if (s->active)
+ snd_pcm_period_elapsed(s->stream);
+
+ spin_lock(&s->dma_lock);
+ if (s->periods > 0) {
+ s->periods--;
+ }
+ audio_process_dma(s);
+ spin_unlock(&s->dma_lock);
+}
+
+/*
+ * Alsa section
+ * PCM settings and callbacks
+ */
+
+static int snd_omap_alsa_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ int stream_id = substream->pstr->stream;
+ struct audio_stream *s = &chip->s[stream_id];
+ int err = 0;
+ ADEBUG();
+
+ /* note local interrupts are already disabled in the midlevel code */
+ spin_lock(&s->dma_lock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* requested stream startup */
+ s->active = 1;
+ audio_process_dma(s);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* requested stream shutdown */
+ audio_stop_dma(s);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ spin_unlock(&s->dma_lock);
+
+ return err;
+}
+
+static int snd_omap_alsa_prepare(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct audio_stream *s = &chip->s[substream->pstr->stream];
+ ADEBUG();
+
+ /* set requested samplerate */
+ alsa_codec_config->codec_set_samplerate(runtime->rate);
+ chip->samplerate = runtime->rate;
+
+ s->period = 0;
+ s->periods = 0;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t snd_omap_alsa_pointer(snd_pcm_substream_t *substream)
+{
+ struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+
+ ADEBUG();
+ return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+/* Hardware capabilities */
+
+static snd_pcm_hardware_t snd_omap_alsa_capture = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static snd_pcm_hardware_t snd_omap_alsa_playback = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static int snd_card_omap_alsa_open(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int stream_id = substream->pstr->stream;
+ int err;
+
+ ADEBUG();
+ chip->s[stream_id].stream = substream;
+ alsa_codec_config->codec_clock_on();
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = snd_omap_alsa_playback;
+ }
+ else {
+ runtime->hw = snd_omap_alsa_capture;
+ }
+ if ((err = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {
+ return err;
+ }
+ if ((err = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_constraints_rates)) < 0) {
+ return err;
+ }
+ return 0;
+}
+
+static int snd_card_omap_alsa_close(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_codec *chip =
+ snd_pcm_substream_chip(substream);
+ ADEBUG();
+
+ alsa_codec_config->codec_clock_off();
+ chip->s[substream->pstr->stream].stream = NULL;
+
+ return 0;
+}
+
+/* HW params & free */
+
+static int snd_omap_alsa_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int snd_omap_alsa_hw_free(snd_pcm_substream_t * substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+
+static snd_pcm_ops_t snd_card_omap_alsa_playback_ops = {
+ .open = snd_card_omap_alsa_open,
+ .close = snd_card_omap_alsa_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_alsa_hw_params,
+ .hw_free = snd_omap_alsa_hw_free,
+ .prepare = snd_omap_alsa_prepare,
+ .trigger = snd_omap_alsa_trigger,
+ .pointer = snd_omap_alsa_pointer,
+};
+
+static snd_pcm_ops_t snd_card_omap_alsa_capture_ops = {
+ .open = snd_card_omap_alsa_open,
+ .close = snd_card_omap_alsa_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_alsa_hw_params,
+ .hw_free = snd_omap_alsa_hw_free,
+ .prepare = snd_omap_alsa_prepare,
+ .trigger = snd_omap_alsa_trigger,
+ .pointer = snd_omap_alsa_pointer,
+};
+
+/*
+ * Alsa init and exit section
+ *
+ * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
+static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec
+ *omap_alsa, int device)
+{
+ snd_pcm_t *pcm;
+ int err;
+ ADEBUG();
+
+ if ((err =
+ snd_pcm_new(omap_alsa->card, "AIC23 PCM", device, 1, 1, &pcm)) < 0)
+ return err;
+
+ /* sets up initial buffer with continuous allocation */
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data
+ (GFP_KERNEL),
+ 128 * 1024, 128 * 1024);
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_card_omap_alsa_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_card_omap_alsa_capture_ops);
+ pcm->private_data = omap_alsa;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "omap aic23 pcm");
+
+ omap_alsa_audio_init(omap_alsa);
+
+ /* setup DMA controller */
+ audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
+ audio_dma_callback);
+ audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
+ audio_dma_callback);
+
+ omap_alsa->pcm = pcm;
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+static int snd_omap_alsa_suspend(snd_card_t * card, pm_message_t state)
+{
+ struct snd_card_omap_codec *chip = card->private_data;
+ ADEBUG();
+
+ if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ /* Mutes and turn clock off */
+ alsa_codec_config->codec_clock_off();
+ snd_omap_suspend_mixer();
+ }
+ return 0;
+}
+
+/*
+ * Prepare hardware for resume
+ */
+static int snd_omap_alsa_resume(snd_card_t * card)
+{
+ struct snd_card_omap_codec *chip = card->private_data;
+ ADEBUG();
+
+ if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+ alsa_codec_config->codec_clock_on();
+ snd_omap_resume_mixer();
+ }
+ return 0;
+}
+
+/*
+ * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
+ */
+static int omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+
+ if (card->power_state != SNDRV_CTL_POWER_D3hot) {
+ snd_omap_alsa_suspend(card, PMSG_SUSPEND);
+ }
+ return 0;
+}
+
+static int omap_alsa_resume(struct platform_device *pdev)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+
+ if (card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_omap_alsa_resume(card);
+ }
+ return 0;
+}
+
+#else
+#define snd_omap_alsa_suspend NULL
+#define snd_omap_alsa_resume NULL
+#define omap_alsa_suspend NULL
+#define omap_alsa_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*
+ */
+void snd_omap_alsa_free(snd_card_t * card)
+{
+ struct snd_card_omap_codec *chip = card->private_data;
+ ADEBUG();
+
+ /*
+ * Turn off codec after it is done.
+ * Can't do it immediately, since it may still have
+ * buffered data.
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2);
+
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+/* module init & exit */
+
+/*
+ * Inits alsa soudcard structure
+ */
+static int __init snd_omap_alsa_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ int def_rate;
+ snd_card_t *card;
+
+ ADEBUG();
+ alsa_codec_config = pdev->dev.platform_data;
+ if (alsa_codec_config == NULL) {
+ err = -ENODEV;
+ goto nodev1;
+ }
+
+ alsa_codec_config->codec_clock_setup();
+ alsa_codec_config->codec_clock_on();
+
+ omap_mcbsp_request(AUDIO_MCBSP);
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
+ omap_mcbsp_start(AUDIO_MCBSP);
+
+ if (alsa_codec_config && alsa_codec_config->codec_configure_dev) {
+ alsa_codec_config->codec_configure_dev();
+ }
+
+ alsa_codec_config->codec_clock_off();
+
+ /* register the soundcard */
+ card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
+ if (card == NULL) {
+ goto nodev2;
+ }
+
+ alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
+ if (alsa_codec == NULL) {
+ goto nodev3;
+ }
+
+ card->private_data = (void *)alsa_codec;
+ card->private_free = snd_omap_alsa_free;
+
+ alsa_codec->card = card;
+ def_rate = alsa_codec_config->get_default_samplerate();
+ alsa_codec->samplerate = def_rate;
+
+ spin_lock_init(&alsa_codec->s[0].dma_lock);
+ spin_lock_init(&alsa_codec->s[1].dma_lock);
+
+ /* mixer */
+ if ((err = snd_omap_mixer(alsa_codec)) < 0) {
+ goto nodev4;
+ }
+
+ /* PCM */
+ if ((err = snd_card_omap_alsa_pcm(alsa_codec, 0)) < 0) {
+ goto nodev4;
+ }
+
+ strcpy(card->driver, "OMAP_ALSA");
+ strcpy(card->shortname, alsa_codec_config->name);
+ sprintf(card->longname, alsa_codec_config->name);
+
+ snd_omap_init_mixer();
+ snd_card_set_dev(card, &pdev->dev);
+
+ if ((err = snd_card_register(card)) == 0) {
+ printk(KERN_INFO "audio support initialized\n");
+ platform_set_drvdata(pdev, card);
+ return 0;
+ }
+
+nodev4:
+ kfree(alsa_codec);
+nodev3:
+ snd_card_free(card);
+nodev2:
+ omap_mcbsp_stop(AUDIO_MCBSP);
+ omap_mcbsp_free(AUDIO_MCBSP);
+nodev1:
+ return err;
+}
+
+static int snd_omap_alsa_remove(struct platform_device *pdev)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+ struct snd_card_omap_codec *chip = card->private_data;
+
+ snd_card_free(card);
+
+ alsa_codec = NULL;
+ card->private_data = NULL;
+ kfree(chip);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+
+}
+
+static struct platform_driver omap_alsa_driver = {
+ .probe = snd_omap_alsa_probe,
+ .remove = snd_omap_alsa_remove,
+ .suspend = omap_alsa_suspend,
+ .resume = omap_alsa_resume,
+ .driver = {
+ .name = "omap_alsa_mcbsp",
+ },
+};
+
+static int __init omap_alsa_init(void)
+{
+ int err;
+ ADEBUG();
+
+ err = platform_driver_register(&omap_alsa_driver);
+
+ return err;
+}
+
+static void __exit omap_alsa_exit(void)
+{
+ ADEBUG();
+
+ platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_init);
+module_exit(omap_alsa_exit);
Index: linux-omap-2.6.git-q/sound/arm/omap-alsa.c
===================================================================
--- linux-omap-2.6.git-q.orig/sound/arm/omap-alsa.c 2006-02-16 08:34:58.000000000 -0400
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,714 +0,0 @@
-/*
- * sound/arm/omap-alsa.c
- *
- * Alsa Driver for AIC23 codec on OSK5912 platform board
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Written by Daniel Petrini, David Cohen, Anderson Briglia
- * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
- *
- * Based on sa11xx-uda1341.c,
- * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History:
- *
- * 2005-07-29 INdT Kernel Team - Alsa driver for omap osk. Creation of new
- * file omap-aic23.c
- *
- * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
- *
- * 2006-02-07 Daniel Petrini - Codec specific function separated. File renamed to
- * omap-alsa.c
- * 2006-02-10 Mika Laitio - Codec specific function pointers are set in the codec.
- * Default samplerate queried from the codec.
- */
-
-#include <linux/platform_device.h>
-#ifdef CONFIG_PM
-#include <linux/pm.h>
-#endif
-#include <sound/driver.h>
-#include <sound/core.h>
-
-#include <asm/arch/omap-alsa.h>
-#include "omap-alsa-dma.h"
-
-MODULE_AUTHOR("Mika Laitio, Daniel Petrini, David Cohen, Anderson Briglia - INdT");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("OMAP driver for ALSA");
-MODULE_ALIAS("omap_alsa_mcbsp.1");
-
-static char *id = NULL;
-static struct snd_card_omap_codec *alsa_codec = NULL;
-static struct omap_alsa_codec_config *alsa_codec_config = NULL;
-
-/*
- * DAC USB-mode sampling rates (MCLK = 12 MHz)
- * The rates and rate_reg_into MUST be in the same order
- */
-static unsigned int rates[] = {
- 4000, 8000, 16000, 22050,
- 24000, 32000, 44100,
- 48000, 88200, 96000,
-};
-
-static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-/*
- * HW interface start and stop helper functions
- */
-static int audio_ifc_start(void)
-{
- omap_mcbsp_start(AUDIO_MCBSP);
- return 0;
-}
-
-static int audio_ifc_stop(void)
-{
- omap_mcbsp_stop(AUDIO_MCBSP);
- return 0;
-}
-
-static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
-{
- /* Setup DMA stuff */
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
- SNDRV_PCM_STREAM_PLAYBACK;
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
- OMAP_DMA_MCBSP1_TX;
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
- audio_ifc_start;
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
- audio_ifc_stop;
-
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
- SNDRV_PCM_STREAM_CAPTURE;
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
- OMAP_DMA_MCBSP1_RX;
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
- audio_ifc_start;
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
- audio_ifc_stop;
-}
-
-/*
- * DMA functions
- * Depends on omap-alsa-dma.c functions and (omap) dma.c
- *
- */
-#define DMA_BUF_SIZE 1024 * 8
-
-static int audio_dma_request(struct audio_stream *s,
- void (*callback) (void *))
-{
- int err;
- ADEBUG();
-
- err = omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);
- if (err < 0)
- printk(KERN_ERR "unable to grab audio dma 0x%x\n",
- s->dma_dev);
- return err;
-}
-
-static int audio_dma_free(struct audio_stream *s)
-{
- int err = 0;
- ADEBUG();
-
- err = omap_free_sound_dma(s, &s->lch);
- if (err < 0)
- printk(KERN_ERR "Unable to free audio dma channels!\n");
- return err;
-}
-
-/*
- * This function should calculate the current position of the dma in the
- * buffer. It will help alsa middle layer to continue update the buffer.
- * Its correctness is crucial for good functioning.
- */
-static u_int audio_get_dma_pos(struct audio_stream *s)
-{
- snd_pcm_substream_t *substream = s->stream;
- snd_pcm_runtime_t *runtime = substream->runtime;
- unsigned int offset;
- unsigned long flags;
- dma_addr_t count;
- ADEBUG();
-
- /* this must be called w/ interrupts locked as requested in dma.c */
- spin_lock_irqsave(&s->dma_lock, flags);
-
- /* For the current period let's see where we are */
- count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
-
- spin_unlock_irqrestore(&s->dma_lock, flags);
-
- /* Now, the position related to the end of that period */
- offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
-
- if (offset >= runtime->buffer_size || offset < 0)
- offset = 0;
-
- return offset;
-}
-
-/*
- * this stops the dma and clears the dma ptrs
- */
-static void audio_stop_dma(struct audio_stream *s)
-{
- unsigned long flags;
- ADEBUG();
-
- spin_lock_irqsave(&s->dma_lock, flags);
- s->active = 0;
- s->period = 0;
- s->periods = 0;
-
- /* this stops the dma channel and clears the buffer ptrs */
- omap_audio_stop_dma(s);
-
- omap_clear_sound_dma(s);
-
- spin_unlock_irqrestore(&s->dma_lock, flags);
-}
-
-/*
- * Main dma routine, requests dma according where you are in main alsa buffer
- */
-static void audio_process_dma(struct audio_stream *s)
-{
- snd_pcm_substream_t *substream = s->stream;
- snd_pcm_runtime_t *runtime;
- unsigned int dma_size;
- unsigned int offset;
- int ret;
-#ifdef CONFIG_MACH_OMAP_H6300
- unsigned long flags;
-#endif
-
- ADEBUG();
- runtime = substream->runtime;
- if (s->active) {
- dma_size = frames_to_bytes(runtime, runtime->period_size);
- offset = dma_size * s->period;
- snd_assert(dma_size <= DMA_BUF_SIZE,);
-#ifdef CONFIG_MACH_OMAP_H6300
- spin_lock_irqsave(&s->dma_lock, flags);
- omap_audio_stop_dma(s);
- spin_unlock_irqrestore(&s->dma_lock, flags);
-#endif
- ret = omap_start_sound_dma(s,
- (dma_addr_t) runtime->dma_area +
- offset, dma_size);
- if (ret) {
- printk(KERN_ERR
- "audio_process_dma: cannot queue DMA buffer (%i)\n",
- ret);
- return;
- }
-
- s->period++;
- s->period %= runtime->periods;
- s->periods++;
- s->offset = offset;
- }
-}
-
-/*
- * This is called when dma IRQ occurs at the end of each transmited block
- */
-void audio_dma_callback(void *data)
-{
- struct audio_stream *s = data;
- ADEBUG();
-
- /*
- * If we are getting a callback for an active stream then we inform
- * the PCM middle layer we've finished a period
- */
- if (s->active)
- snd_pcm_period_elapsed(s->stream);
-
- spin_lock(&s->dma_lock);
- if (s->periods > 0) {
- s->periods--;
- }
- audio_process_dma(s);
- spin_unlock(&s->dma_lock);
-}
-
-/*
- * Alsa section
- * PCM settings and callbacks
- */
-
-static int snd_omap_alsa_trigger(snd_pcm_substream_t * substream, int cmd)
-{
- struct snd_card_omap_codec *chip =
- snd_pcm_substream_chip(substream);
- int stream_id = substream->pstr->stream;
- struct audio_stream *s = &chip->s[stream_id];
- int err = 0;
- ADEBUG();
-
- /* note local interrupts are already disabled in the midlevel code */
- spin_lock(&s->dma_lock);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- /* requested stream startup */
- s->active = 1;
- audio_process_dma(s);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- /* requested stream shutdown */
- audio_stop_dma(s);
- break;
- default:
- err = -EINVAL;
- break;
- }
- spin_unlock(&s->dma_lock);
-
- return err;
-}
-
-static int snd_omap_alsa_prepare(snd_pcm_substream_t * substream)
-{
- struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
- snd_pcm_runtime_t *runtime = substream->runtime;
- struct audio_stream *s = &chip->s[substream->pstr->stream];
- ADEBUG();
-
- /* set requested samplerate */
- alsa_codec_config->codec_set_samplerate(runtime->rate);
- chip->samplerate = runtime->rate;
-
- s->period = 0;
- s->periods = 0;
-
- return 0;
-}
-
-static snd_pcm_uframes_t snd_omap_alsa_pointer(snd_pcm_substream_t *substream)
-{
- struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
-
- ADEBUG();
- return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
-}
-
-/* Hardware capabilities */
-
-static snd_pcm_hardware_t snd_omap_alsa_capture = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
- .formats = (SNDRV_PCM_FMTBIT_S16_LE),
- .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_KNOT),
- .rate_min = 8000,
- .rate_max = 96000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 128 * 1024,
- .period_bytes_min = 32,
- .period_bytes_max = 8 * 1024,
- .periods_min = 16,
- .periods_max = 255,
- .fifo_size = 0,
-};
-
-static snd_pcm_hardware_t snd_omap_alsa_playback = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
- .formats = (SNDRV_PCM_FMTBIT_S16_LE),
- .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_KNOT),
- .rate_min = 8000,
- .rate_max = 96000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 128 * 1024,
- .period_bytes_min = 32,
- .period_bytes_max = 8 * 1024,
- .periods_min = 16,
- .periods_max = 255,
- .fifo_size = 0,
-};
-
-static int snd_card_omap_alsa_open(snd_pcm_substream_t * substream)
-{
- struct snd_card_omap_codec *chip =
- snd_pcm_substream_chip(substream);
- snd_pcm_runtime_t *runtime = substream->runtime;
- int stream_id = substream->pstr->stream;
- int err;
-
- ADEBUG();
- chip->s[stream_id].stream = substream;
- alsa_codec_config->codec_clock_on();
- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
- runtime->hw = snd_omap_alsa_playback;
- }
- else {
- runtime->hw = snd_omap_alsa_capture;
- }
- if ((err = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {
- return err;
- }
- if ((err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &hw_constraints_rates)) < 0) {
- return err;
- }
- return 0;
-}
-
-static int snd_card_omap_alsa_close(snd_pcm_substream_t * substream)
-{
- struct snd_card_omap_codec *chip =
- snd_pcm_substream_chip(substream);
- ADEBUG();
-
- alsa_codec_config->codec_clock_off();
- chip->s[substream->pstr->stream].stream = NULL;
-
- return 0;
-}
-
-/* HW params & free */
-
-static int snd_omap_alsa_hw_params(snd_pcm_substream_t * substream,
- snd_pcm_hw_params_t * hw_params)
-{
- return snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
-}
-
-static int snd_omap_alsa_hw_free(snd_pcm_substream_t * substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
-/* pcm operations */
-
-static snd_pcm_ops_t snd_card_omap_alsa_playback_ops = {
- .open = snd_card_omap_alsa_open,
- .close = snd_card_omap_alsa_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_omap_alsa_hw_params,
- .hw_free = snd_omap_alsa_hw_free,
- .prepare = snd_omap_alsa_prepare,
- .trigger = snd_omap_alsa_trigger,
- .pointer = snd_omap_alsa_pointer,
-};
-
-static snd_pcm_ops_t snd_card_omap_alsa_capture_ops = {
- .open = snd_card_omap_alsa_open,
- .close = snd_card_omap_alsa_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_omap_alsa_hw_params,
- .hw_free = snd_omap_alsa_hw_free,
- .prepare = snd_omap_alsa_prepare,
- .trigger = snd_omap_alsa_trigger,
- .pointer = snd_omap_alsa_pointer,
-};
-
-/*
- * Alsa init and exit section
- *
- * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
- */
-static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec
- *omap_alsa, int device)
-{
- snd_pcm_t *pcm;
- int err;
- ADEBUG();
-
- if ((err =
- snd_pcm_new(omap_alsa->card, "AIC23 PCM", device, 1, 1, &pcm)) < 0)
- return err;
-
- /* sets up initial buffer with continuous allocation */
- snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data
- (GFP_KERNEL),
- 128 * 1024, 128 * 1024);
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &snd_card_omap_alsa_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
- &snd_card_omap_alsa_capture_ops);
- pcm->private_data = omap_alsa;
- pcm->info_flags = 0;
- strcpy(pcm->name, "omap aic23 pcm");
-
- omap_alsa_audio_init(omap_alsa);
-
- /* setup DMA controller */
- audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
- audio_dma_callback);
- audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
- audio_dma_callback);
-
- omap_alsa->pcm = pcm;
-
- return 0;
-}
-
-
-#ifdef CONFIG_PM
-
-static int snd_omap_alsa_suspend(snd_card_t * card, pm_message_t state)
-{
- struct snd_card_omap_codec *chip = card->private_data;
- ADEBUG();
-
- if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
- snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
- snd_pcm_suspend_all(chip->pcm);
- /* Mutes and turn clock off */
- alsa_codec_config->codec_clock_off();
- snd_omap_suspend_mixer();
- }
- return 0;
-}
-
-/*
- * Prepare hardware for resume
- */
-static int snd_omap_alsa_resume(snd_card_t * card)
-{
- struct snd_card_omap_codec *chip = card->private_data;
- ADEBUG();
-
- if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
- snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
- alsa_codec_config->codec_clock_on();
- snd_omap_resume_mixer();
- }
- return 0;
-}
-
-/*
- * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
- */
-static int omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
-{
- snd_card_t *card = platform_get_drvdata(pdev);
-
- if (card->power_state != SNDRV_CTL_POWER_D3hot) {
- snd_omap_alsa_suspend(card, PMSG_SUSPEND);
- }
- return 0;
-}
-
-static int omap_alsa_resume(struct platform_device *pdev)
-{
- snd_card_t *card = platform_get_drvdata(pdev);
-
- if (card->power_state != SNDRV_CTL_POWER_D0) {
- snd_omap_alsa_resume(card);
- }
- return 0;
-}
-
-#else
-#define snd_omap_alsa_suspend NULL
-#define snd_omap_alsa_resume NULL
-#define omap_alsa_suspend NULL
-#define omap_alsa_resume NULL
-
-#endif /* CONFIG_PM */
-
-/*
- */
-void snd_omap_alsa_free(snd_card_t * card)
-{
- struct snd_card_omap_codec *chip = card->private_data;
- ADEBUG();
-
- /*
- * Turn off codec after it is done.
- * Can't do it immediately, since it may still have
- * buffered data.
- */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(2);
-
- omap_mcbsp_stop(AUDIO_MCBSP);
- omap_mcbsp_free(AUDIO_MCBSP);
-
- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
-}
-
-/* module init & exit */
-
-/*
- * Inits alsa soudcard structure
- */
-static int __init snd_omap_alsa_probe(struct platform_device *pdev)
-{
- int err = 0;
- int def_rate;
- snd_card_t *card;
-
- ADEBUG();
- alsa_codec_config = pdev->dev.platform_data;
- if (alsa_codec_config == NULL) {
- err = -ENODEV;
- goto nodev1;
- }
-
- alsa_codec_config->codec_clock_setup();
- alsa_codec_config->codec_clock_on();
-
- omap_mcbsp_request(AUDIO_MCBSP);
- omap_mcbsp_stop(AUDIO_MCBSP);
- omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
- omap_mcbsp_start(AUDIO_MCBSP);
-
- if (alsa_codec_config && alsa_codec_config->codec_configure_dev) {
- alsa_codec_config->codec_configure_dev();
- }
-
- alsa_codec_config->codec_clock_off();
-
- /* register the soundcard */
- card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
- if (card == NULL) {
- goto nodev2;
- }
-
- alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
- if (alsa_codec == NULL) {
- goto nodev3;
- }
-
- card->private_data = (void *)alsa_codec;
- card->private_free = snd_omap_alsa_free;
-
- alsa_codec->card = card;
- def_rate = alsa_codec_config->get_default_samplerate();
- alsa_codec->samplerate = def_rate;
-
- spin_lock_init(&alsa_codec->s[0].dma_lock);
- spin_lock_init(&alsa_codec->s[1].dma_lock);
-
- /* mixer */
- if ((err = snd_omap_mixer(alsa_codec)) < 0) {
- goto nodev4;
- }
-
- /* PCM */
- if ((err = snd_card_omap_alsa_pcm(alsa_codec, 0)) < 0) {
- goto nodev4;
- }
-
- strcpy(card->driver, "OMAP_ALSA");
- strcpy(card->shortname, alsa_codec_config->name);
- sprintf(card->longname, alsa_codec_config->name);
-
- snd_omap_init_mixer();
- snd_card_set_dev(card, &pdev->dev);
-
- if ((err = snd_card_register(card)) == 0) {
- printk(KERN_INFO "audio support initialized\n");
- platform_set_drvdata(pdev, card);
- return 0;
- }
-
-nodev4:
- kfree(alsa_codec);
-nodev3:
- snd_card_free(card);
-nodev2:
- omap_mcbsp_stop(AUDIO_MCBSP);
- omap_mcbsp_free(AUDIO_MCBSP);
-nodev1:
- return err;
-}
-
-static int snd_omap_alsa_remove(struct platform_device *pdev)
-{
- snd_card_t *card = platform_get_drvdata(pdev);
- struct snd_card_omap_codec *chip = card->private_data;
-
- snd_card_free(card);
-
- alsa_codec = NULL;
- card->private_data = NULL;
- kfree(chip);
-
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-
-}
-
-static struct platform_driver omap_alsa_driver = {
- .probe = snd_omap_alsa_probe,
- .remove = snd_omap_alsa_remove,
- .suspend = omap_alsa_suspend,
- .resume = omap_alsa_resume,
- .driver = {
- .name = "omap_alsa_mcbsp",
- },
-};
-
-static int __init omap_alsa_init(void)
-{
- int err;
- ADEBUG();
-
- err = platform_driver_register(&omap_alsa_driver);
-
- return err;
-}
-
-static void __exit omap_alsa_exit(void)
-{
- ADEBUG();
-
- platform_driver_unregister(&omap_alsa_driver);
-}
-
-module_init(omap_alsa_init);
-module_exit(omap_alsa_exit);
Index: linux-omap-2.6.git-q/sound/arm/omap/omap-alsa-mixer.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-omap-2.6.git-q/sound/arm/omap/omap-alsa-mixer.c 2006-02-16 08:40:57.000000000 -0400
@@ -0,0 +1,485 @@
+/*
+ * sound/arm/omap/omap-alsa-aic23-mixer.c
+ *
+ * Alsa Driver Mixer for generic codecs for omap boards
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by David Cohen, Daniel Petrini
+ * {david.cohen, daniel.petrini}@indt.org.br
+ *
+ * Based on es1688_lib.c,
+ * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-08-02 INdT Kernel Team - Alsa mixer driver for omap osk. Creation of new
+ * file omap-alsa-mixer.c. Initial version
+ * with aic23 codec for osk5912
+ */
+
+#include <linux/config.h>
+#include <sound/driver.h>
+#include <asm/arch/aic23.h>
+
+#include <asm/arch/omap-alsa.h>
+#include <../arch/arm/mach-omap1/omap-alsa-aic23.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+MODULE_AUTHOR("David Cohen, Daniel Petrini - INdT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
+
+/*
+ * Codec dependent region
+ */
+
+/* Codec AIC23 */
+#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
+
+extern void audio_aic23_write(u8, u16);
+
+#define MIXER_NAME "Mixer AIC23"
+#define SND_OMAP_WRITE(reg, val) audio_aic23_write(reg, val)
+
+#endif
+
+/* Callback Functions */
+#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_bool, \
+ .get = snd_omap_get_bool, \
+ .put = snd_omap_put_bool, \
+ .private_value = reg | (reg_index << 8) | (invert << 10) | (mask << 12) \
+}
+
+#define OMAP_MUX(xname, reg, reg_index, mask) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = snd_omap_info_mux, \
+ .get = snd_omap_get_mux, \
+ .put = snd_omap_put_mux, \
+ .private_value = reg | (reg_index << 8) | (mask << 10) \
+}
+
+#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_single, \
+ .get = snd_omap_get_single, \
+ .put = snd_omap_put_single, \
+ .private_value = reg | (reg_val << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_double, \
+ .get = snd_omap_get_double, \
+ .put = snd_omap_put_double, \
+ .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+/* Local Registers */
+enum snd_device_index {
+ PCM_INDEX = 0,
+ LINE_INDEX,
+ AAC_INDEX, /* Analog Audio Control: reg = l_reg */
+};
+
+struct {
+ u16 l_reg;
+ u16 r_reg;
+ u8 sw;
+} omap_regs[3];
+
+#ifdef CONFIG_PM
+struct {
+ u16 l_reg;
+ u16 r_reg;
+ u8 sw;
+} omap_pm_regs[3];
+#endif
+
+u16 snd_sidetone[6] = {
+ SIDETONE_18,
+ SIDETONE_12,
+ SIDETONE_9,
+ SIDETONE_6,
+ SIDETONE_0,
+ 0
+};
+
+/* Begin Bool Functions */
+
+static int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+
+ return 0;
+}
+
+static int snd_omap_get_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ int mic_index = (kcontrol->private_value >> 8) & 0x03;
+ u16 mask = (kcontrol->private_value >> 12) & 0xff;
+ int invert = (kcontrol->private_value >> 10) & 0x03;
+
+ if (invert)
+ ucontrol->value.integer.value[0] = (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
+ else
+ ucontrol->value.integer.value[0] = (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
+
+ return 0;
+}
+
+static int snd_omap_put_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ int mic_index = (kcontrol->private_value >> 8) & 0x03;
+ u16 mask = (kcontrol->private_value >> 12) & 0xff;
+ u16 reg = kcontrol->private_value & 0xff;
+ int invert = (kcontrol->private_value >> 10) & 0x03;
+
+ int changed = 1;
+
+ if (ucontrol->value.integer.value[0]) /* XOR */
+ if (invert)
+ omap_regs[mic_index].l_reg &= ~mask;
+ else
+ omap_regs[mic_index].l_reg |= mask;
+ else
+ if (invert)
+ omap_regs[mic_index].l_reg |= mask;
+ else
+ omap_regs[mic_index].l_reg &= ~mask;
+
+ SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
+
+ return changed;
+}
+
+/* End Bool Functions */
+
+/* Begin Mux Functions */
+
+static int snd_omap_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ /* Mic = 0
+ * Line = 1 */
+ static char *texts[2] = { "Mic", "Line" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_omap_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ u16 mask = (kcontrol->private_value >> 10) & 0xff;
+ int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+ ucontrol->value.enumerated.item[0] = (omap_regs[mux_index].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
+
+ return 0;
+}
+
+static int snd_omap_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ u16 reg = kcontrol->private_value & 0xff;
+ u16 mask = (kcontrol->private_value >> 10) & 0xff;
+ int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+ int changed = 1;
+
+ if (!ucontrol->value.integer.value[0])
+ omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
+ else
+ omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
+
+ SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
+
+ return changed;
+}
+
+/* End Mux Functions */
+
+/* Begin Single Functions */
+
+static int snd_omap_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER : SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = reg_val-1;
+
+ return 0;
+}
+
+static int snd_omap_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
+
+ return 0;
+}
+
+static int snd_omap_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
+ u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
+ u16 reg = kcontrol->private_value & 0xff;
+ u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ int changed = 0;
+
+ /* Volume */
+ if ((omap_regs[reg_index].l_reg != (ucontrol->value.integer.value[0] & mask)))
+ {
+ changed = 1;
+
+ omap_regs[reg_index].l_reg &= ~mask;
+ omap_regs[reg_index].l_reg |= snd_sidetone[ucontrol->value.integer.value[0]];
+
+ snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
+ SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
+ }
+ else
+ changed = 0;
+
+ return changed;
+}
+
+/* End Single Functions */
+
+/* Begin Double Functions */
+
+static int snd_omap_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ /* mask == 0 : Switch
+ * mask != 0 : Volume */
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+
+ uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER : SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = mask ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask ? mask : 1;
+
+ return 0;
+}
+
+static int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ /* mask == 0 : Switch
+ * mask != 0 : Volume */
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int vol_index = (kcontrol->private_value >> 16) & 0x03;
+
+ if (!mask)
+ /* Switch */
+ ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
+ else
+ {
+ /* Volume */
+ ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
+ ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
+ }
+
+ return 0;
+}
+
+static int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ /* mask == 0 : Switch
+ * mask != 0 : Volume */
+ int vol_index = (kcontrol->private_value >> 16) & 0x03;
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int left_reg = kcontrol->private_value & 0xff;
+ int right_reg = (kcontrol->private_value >> 8) & 0xff;
+
+ int changed = 0;
+
+ if (!mask)
+ {
+ /* Switch */
+ if (!ucontrol->value.integer.value[0])
+ {
+ SND_OMAP_WRITE(left_reg, 0x00);
+ SND_OMAP_WRITE(right_reg, 0x00);
+ }
+ else
+ {
+ SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+ SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+ }
+ changed = 1;
+ omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
+ }
+ else
+ {
+ /* Volume */
+ if ((omap_regs[vol_index].l_reg != (ucontrol->value.integer.value[0] & mask)) ||
+ (omap_regs[vol_index].r_reg != (ucontrol->value.integer.value[1] & mask)))
+ {
+ changed = 1;
+
+ omap_regs[vol_index].l_reg &= ~mask;
+ omap_regs[vol_index].r_reg &= ~mask;
+ omap_regs[vol_index].l_reg |= (ucontrol->value.integer.value[0] & mask);
+ omap_regs[vol_index].r_reg |= (ucontrol->value.integer.value[1] & mask);
+ if (omap_regs[vol_index].sw)
+ {
+ /* write to registers only if sw is actived */
+ SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+ SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+ }
+ }
+ else
+ changed = 0;
+ }
+
+ return changed;
+}
+
+/* End Double Functions */
+
+static snd_kcontrol_new_t snd_omap_controls[] = {
+ OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+ PCM_INDEX, 0x00),
+ OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+ PCM_INDEX, OUTPUT_VOLUME_MASK),
+ OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, BYPASS_ON, 0),
+ OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+ LINE_INDEX, 0x00),
+ OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+ LINE_INDEX, INPUT_VOLUME_MASK),
+ OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, STE_ENABLED, 0),
+ OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, 5, SIDETONE_MASK),
+ OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICM_MUTED, 1),
+ OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
+ OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+ /* Saves current values to wake-up correctly */
+ omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
+ omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
+ omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
+
+ omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
+
+ omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
+ omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
+ omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
+}
+
+void snd_omap_resume_mixer(void)
+{
+ /* Line's saved values */
+ omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
+ omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
+ omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
+ SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+ SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+
+ /* Analog Audio Control's saved values */
+ omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
+ SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
+
+ /* Headphone's saved values */
+ omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
+ omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
+ omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
+ SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].l_reg);
+ SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].r_reg);
+}
+#endif
+
+void snd_omap_init_mixer(void)
+{
+ u16 vol_reg;
+
+ /* Line's default values */
+ omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+ omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+ omap_regs[LINE_INDEX].sw = 0;
+ SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+ SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+
+ /* Analog Audio Control's default values */
+ omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
+
+ /* Headphone's default values */
+ vol_reg = LZC_ON;
+ vol_reg &= ~OUTPUT_VOLUME_MASK;
+ vol_reg |= DEFAULT_OUTPUT_VOLUME;
+ omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
+ omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
+ omap_regs[PCM_INDEX].sw = 1;
+ SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
+ SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
+}
+
+int snd_omap_mixer(struct snd_card_omap_codec *chip)
+{
+ snd_card_t *card;
+ unsigned int idx;
+ int err;
+
+ snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+
+ card = chip->card;
+
+ strcpy(card->mixername, MIXER_NAME);
+
+ /* Registering alsa mixer controls */
+ for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++)
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_omap_controls[idx], chip))) < 0)
+ return err;
+
+ return 0;
+}
Index: linux-omap-2.6.git-q/sound/arm/omap/omap-alsa-dma.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-omap-2.6.git-q/sound/arm/omap/omap-alsa-dma.c 2006-02-16 08:40:57.000000000 -0400
@@ -0,0 +1,456 @@
+/*
+ * sound/arm/omap/omap-alsa-dma.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c. This file
+ * will contain only the DMA interface and buffer handling of OMAP
+ * audio driver.
+ *
+ * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking of DMA logical channel.
+ *
+ * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support multi channel chaining.
+ *
+ * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
+ *
+ * 2005-07-19 INdT Kernel Team - Alsa port. Creation of new file omap-alsa-dma.c based in
+ * omap-audio-dma-intfc.c oss file. Support for aic23 codec.
+ * Removal of buffer handling (Alsa does that), modifications
+ * in dma handling and port to alsa structures.
+ *
+ * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+#include <asm/arch/dma.h>
+#include "omap-alsa-dma.h"
+
+#include <asm/arch/mcbsp.h>
+
+#include <asm/arch/omap-alsa.h>
+
+#undef DEBUG
+//#define DEBUG
+//#ifdef DEBUG
+//#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+//#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+//#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+//#else
+
+//#define DPRINTK( x... )
+//#define FN_IN
+//#define FN_OUT(x)
+//#endif
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+/* Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
+#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
+#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
+
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE 0x1000000 /* todo: sync with alsa */
+//#define CUT_DMA_SIZE 0x1000
+/* TODO: To be moved to more appropriate location */
+#define DCSR_ERROR 0x3
+#define DCSR_END_BLOCK (1 << 5)
+#define DCSR_SYNC_SET (1 << 6)
+
+#define DCCR_FS (1 << 5)
+#define DCCR_PRIO (1 << 6)
+#define DCCR_EN (1 << 7)
+#define DCCR_AI (1 << 8)
+#define DCCR_REPEAT (1 << 9)
+/* if 0 the channel works in 3.1 compatible mode*/
+#define DCCR_N31COMP (1 << 10)
+#define DCCR_EP (1 << 11)
+#define DCCR_SRC_AMODE_BIT 12
+#define DCCR_SRC_AMODE_MASK (0x3<<12)
+#define DCCR_DST_AMODE_BIT 14
+#define DCCR_DST_AMODE_MASK (0x3<<14)
+#define AMODE_CONST 0x0
+#define AMODE_POST_INC 0x1
+#define AMODE_SINGLE_INDEX 0x2
+#define AMODE_DOUBLE_INDEX 0x3
+
+/**************************** DATA STRUCTURES *****************************************/
+
+static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
+
+static char nr_linked_channels = 1;
+
+/*********************************** MODULE SPECIFIC FUNCTIONS ***********************/
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_start_dma_chain(struct audio_stream * s);
+
+/***************************************************************************************
+ *
+ * DMA channel requests
+ *
+ **************************************************************************************/
+static void omap_sound_dma_link_lch(void *data)
+{
+
+ struct audio_stream *s = (struct audio_stream *) data;
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (s->linked) {
+ FN_OUT(1);
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ int nex_chan =
+ ((nr_linked_channels - 1 ==
+ i) ? chan[0] : chan[i + 1]);
+ omap_dma_link_lch(cur_chan, nex_chan);
+ }
+ s->linked = 1;
+ FN_OUT(0);
+}
+
+int omap_request_sound_dma(int device_id, const char *device_name,
+ void *data, int **channels)
+{
+ int i, err = 0;
+ int *chan = NULL;
+ FN_IN;
+ if (unlikely((NULL == channels) || (NULL == device_name))) {
+ BUG();
+ return -EPERM;
+ }
+ /* Try allocate memory for the num channels */
+ *channels =
+ (int *) kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
+ chan = *channels;
+ if (NULL == chan) {
+ ERR("No Memory for channel allocs!\n");
+ FN_OUT(-ENOMEM);
+ return -ENOMEM;
+ }
+ spin_lock(&dma_list_lock);
+ for (i = 0; i < nr_linked_channels; i++) {
+ err =
+ omap_request_dma(device_id, device_name,
+ sound_dma_irq_handler, data,
+ &chan[i]);
+
+ /* Handle Failure condition here */
+ if (err < 0) {
+ int j;
+ for (j = 0; j < i; j++) {
+ omap_free_dma(chan[j]);
+ }
+ spin_unlock(&dma_list_lock);
+ kfree(chan);
+ *channels = NULL;
+ ERR("Error in requesting channel %d=0x%x\n", i,
+ err);
+ FN_OUT(err);
+ return err;
+ }
+ }
+
+ /* Chain the channels together */
+ if (!cpu_is_omap1510())
+ omap_sound_dma_link_lch(data);
+
+ spin_unlock(&dma_list_lock);
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests Freeing
+ *
+ **************************************************************************************/
+static void omap_sound_dma_unlink_lch(void *data)
+{
+ struct audio_stream *s = (struct audio_stream *) data;
+ int *chan = s->lch;
+ int i;
+
+ FN_IN;
+ if (!s->linked) {
+ FN_OUT(1);
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ int nex_chan =
+ ((nr_linked_channels - 1 ==
+ i) ? chan[0] : chan[i + 1]);
+ omap_dma_unlink_lch(cur_chan, nex_chan);
+ }
+ s->linked = 0;
+ FN_OUT(0);
+}
+
+int omap_free_sound_dma(void *data, int **channels)
+{
+
+ int i;
+ int *chan = NULL;
+ FN_IN;
+ if (unlikely(NULL == channels)) {
+ BUG();
+ return -EPERM;
+ }
+ if (unlikely(NULL == *channels)) {
+ BUG();
+ return -EPERM;
+ }
+ chan = (*channels);
+
+ if (!cpu_is_omap1510())
+ omap_sound_dma_unlink_lch(data);
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ omap_stop_dma(cur_chan);
+ omap_free_dma(cur_chan);
+ }
+ kfree(*channels);
+ *channels = NULL;
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************************************************************************
+ *
+ * Stop all the DMA channels of the stream
+ *
+ **************************************************************************************/
+void omap_audio_stop_dma(struct audio_stream *s)
+{
+ int *chan = s->lch;
+ int i;
+ FN_IN;
+ if (unlikely(NULL == chan)) {
+ BUG();
+ return;
+ }
+ for (i = 0; i < nr_linked_channels; i++) {
+ int cur_chan = chan[i];
+ omap_stop_dma(cur_chan);
+ }
+ s->started = 0;
+ FN_OUT(0);
+ return;
+}
+/***************************************************************************************
+ *
+ * Clear any pending transfers
+ *
+ **************************************************************************************/
+void omap_clear_sound_dma(struct audio_stream * s)
+{
+ FN_IN;
+ omap_clear_dma(s->lch[s->dma_q_head]);
+ FN_OUT(0);
+ return;
+}
+
+/*********************************** MODULE FUNCTIONS DEFINTIONS ***********************/
+
+#ifdef OMAP1610_MCBSP1_BASE
+#undef OMAP1610_MCBSP1_BASE
+#endif
+#define OMAP1610_MCBSP1_BASE 0xE1011000
+
+/***************************************************************************************
+ *
+ * DMA related functions
+ *
+ **************************************************************************************/
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int dt = 0x1; /* data type 16 */
+ int cen = 32; /* Stereo */
+ int cfn = dma_size / (2 * cen);
+ FN_IN;
+ omap_set_dma_dest_params(channel, 0x05, 0x00,
+ (OMAP1610_MCBSP1_BASE + 0x806),
+ 0, 0);
+ omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
+ 0, 0);
+ omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+ FN_OUT(0);
+ return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int dt = 0x1; /* data type 16 */
+ int cen = 32; /* stereo */
+
+ int cfn = dma_size / (2 * cen);
+ FN_IN;
+ omap_set_dma_src_params(channel, 0x05, 0x00,
+ (OMAP1610_MCBSP1_BASE + 0x802),
+ 0, 0);
+ omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
+ omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+ FN_OUT(0);
+ return 0;
+}
+
+static int audio_start_dma_chain(struct audio_stream *s)
+{
+ int channel = s->lch[s->dma_q_head];
+ FN_IN;
+ if (!s->started) {
+ s->hw_stop(); /* stops McBSP Interface */
+ omap_start_dma(channel);
+ s->started = 1;
+ s->hw_start(); /* start McBSP interface */
+ }
+ /* else the dma itself will progress forward with out our help */
+ FN_OUT(0);
+ return 0;
+}
+
+/* Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+int omap_start_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int ret = -EPERM;
+
+ FN_IN;
+
+ if (unlikely(dma_size > MAX_DMA_SIZE)) {
+ ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+ MAX_DMA_SIZE);
+ return -EOVERFLOW;
+ }
+ //if (AUDIO_QUEUE_FULL(s)) {
+ // ret = -2;
+ // goto sound_out;
+ //}
+
+ if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*playback */
+ ret =
+ audio_set_dma_params_play(s->lch[s->dma_q_tail],
+ dma_ptr, dma_size);
+ } else {
+ ret =
+ audio_set_dma_params_capture(s->lch[s->dma_q_tail],
+ dma_ptr, dma_size);
+ }
+ if (ret != 0) {
+ ret = -3; /* indicate queue full */
+ goto sound_out;
+ }
+ AUDIO_INCREMENT_TAIL(s);
+ ret = audio_start_dma_chain(s);
+ if (ret) {
+ ERR("dma start failed");
+ }
+ sound_out:
+ FN_OUT(ret);
+ return ret;
+
+}
+
+/*
+ * ISRs have to be short and smart..
+ * Here we call alsa handling, after some error checking
+ */
+static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status,
+ void *data)
+{
+ int dma_status = ch_status;
+ struct audio_stream *s = (struct audio_stream *) data;
+ FN_IN;
+
+ /*
+ * some register checkings
+ */
+ DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
+ sound_curr_lch, ch_status, dma_status, data);
+
+ if (dma_status & (DCSR_ERROR)) {
+ OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
+ ERR("DCSR_ERROR!\n");
+ FN_OUT(-1);
+ return;
+ }
+
+ if (ch_status & DCSR_END_BLOCK)
+ audio_dma_callback(s);
+ FN_OUT(0);
+ return;
+}
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+ ("Common DMA handling for Audio driver on OMAP processors");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(omap_start_sound_dma);
+EXPORT_SYMBOL(omap_clear_sound_dma);
+EXPORT_SYMBOL(omap_request_sound_dma);
+EXPORT_SYMBOL(omap_free_sound_dma);
+EXPORT_SYMBOL(omap_audio_stop_dma);
Index: linux-omap-2.6.git-q/sound/arm/omap-alsa-dma.c
===================================================================
--- linux-omap-2.6.git-q.orig/sound/arm/omap-alsa-dma.c 2006-02-16 08:38:29.000000000 -0400
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,456 +0,0 @@
-/*
- * sound/arm/omap-alsa-dma.c
- *
- * Common audio DMA handling for the OMAP processors
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History:
- *
- * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c. This file
- * will contain only the DMA interface and buffer handling of OMAP
- * audio driver.
- *
- * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking of DMA logical channel.
- *
- * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
- *
- * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support multi channel chaining.
- *
- * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
- *
- * 2005-07-19 INdT Kernel Team - Alsa port. Creation of new file omap-alsa-dma.c based in
- * omap-audio-dma-intfc.c oss file. Support for aic23 codec.
- * Removal of buffer handling (Alsa does that), modifications
- * in dma handling and port to alsa structures.
- *
- * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/pm.h>
-#include <linux/errno.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/sysrq.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/semaphore.h>
-
-#include <asm/arch/dma.h>
-#include "omap-alsa-dma.h"
-
-#include <asm/arch/mcbsp.h>
-
-#include <asm/arch/omap-alsa.h>
-
-#undef DEBUG
-//#define DEBUG
-//#ifdef DEBUG
-//#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
-//#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
-//#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
-//#else
-
-//#define DPRINTK( x... )
-//#define FN_IN
-//#define FN_OUT(x)
-//#endif
-
-#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
-
-/* Channel Queue Handling macros
- * tail always points to the current free entry
- * Head always points to the current entry being used
- * end is either head or tail
- */
-
-#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
-#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
-#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
-#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
-#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
-#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
-#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
-
-/* DMA buffer fragmentation sizes */
-#define MAX_DMA_SIZE 0x1000000 /* todo: sync with alsa */
-//#define CUT_DMA_SIZE 0x1000
-/* TODO: To be moved to more appropriate location */
-#define DCSR_ERROR 0x3
-#define DCSR_END_BLOCK (1 << 5)
-#define DCSR_SYNC_SET (1 << 6)
-
-#define DCCR_FS (1 << 5)
-#define DCCR_PRIO (1 << 6)
-#define DCCR_EN (1 << 7)
-#define DCCR_AI (1 << 8)
-#define DCCR_REPEAT (1 << 9)
-/* if 0 the channel works in 3.1 compatible mode*/
-#define DCCR_N31COMP (1 << 10)
-#define DCCR_EP (1 << 11)
-#define DCCR_SRC_AMODE_BIT 12
-#define DCCR_SRC_AMODE_MASK (0x3<<12)
-#define DCCR_DST_AMODE_BIT 14
-#define DCCR_DST_AMODE_MASK (0x3<<14)
-#define AMODE_CONST 0x0
-#define AMODE_POST_INC 0x1
-#define AMODE_SINGLE_INDEX 0x2
-#define AMODE_DOUBLE_INDEX 0x3
-
-/**************************** DATA STRUCTURES *****************************************/
-
-static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
-
-static char nr_linked_channels = 1;
-
-/*********************************** MODULE SPECIFIC FUNCTIONS ***********************/
-
-static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
-static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
- u_int dma_size);
-static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
- u_int dma_size);
-static int audio_start_dma_chain(struct audio_stream * s);
-
-/***************************************************************************************
- *
- * DMA channel requests
- *
- **************************************************************************************/
-static void omap_sound_dma_link_lch(void *data)
-{
-
- struct audio_stream *s = (struct audio_stream *) data;
- int *chan = s->lch;
- int i;
-
- FN_IN;
- if (s->linked) {
- FN_OUT(1);
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- int nex_chan =
- ((nr_linked_channels - 1 ==
- i) ? chan[0] : chan[i + 1]);
- omap_dma_link_lch(cur_chan, nex_chan);
- }
- s->linked = 1;
- FN_OUT(0);
-}
-
-int omap_request_sound_dma(int device_id, const char *device_name,
- void *data, int **channels)
-{
- int i, err = 0;
- int *chan = NULL;
- FN_IN;
- if (unlikely((NULL == channels) || (NULL == device_name))) {
- BUG();
- return -EPERM;
- }
- /* Try allocate memory for the num channels */
- *channels =
- (int *) kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
- chan = *channels;
- if (NULL == chan) {
- ERR("No Memory for channel allocs!\n");
- FN_OUT(-ENOMEM);
- return -ENOMEM;
- }
- spin_lock(&dma_list_lock);
- for (i = 0; i < nr_linked_channels; i++) {
- err =
- omap_request_dma(device_id, device_name,
- sound_dma_irq_handler, data,
- &chan[i]);
-
- /* Handle Failure condition here */
- if (err < 0) {
- int j;
- for (j = 0; j < i; j++) {
- omap_free_dma(chan[j]);
- }
- spin_unlock(&dma_list_lock);
- kfree(chan);
- *channels = NULL;
- ERR("Error in requesting channel %d=0x%x\n", i,
- err);
- FN_OUT(err);
- return err;
- }
- }
-
- /* Chain the channels together */
- if (!cpu_is_omap1510())
- omap_sound_dma_link_lch(data);
-
- spin_unlock(&dma_list_lock);
- FN_OUT(0);
- return 0;
-}
-
-/***************************************************************************************
- *
- * DMA channel requests Freeing
- *
- **************************************************************************************/
-static void omap_sound_dma_unlink_lch(void *data)
-{
- struct audio_stream *s = (struct audio_stream *) data;
- int *chan = s->lch;
- int i;
-
- FN_IN;
- if (!s->linked) {
- FN_OUT(1);
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- int nex_chan =
- ((nr_linked_channels - 1 ==
- i) ? chan[0] : chan[i + 1]);
- omap_dma_unlink_lch(cur_chan, nex_chan);
- }
- s->linked = 0;
- FN_OUT(0);
-}
-
-int omap_free_sound_dma(void *data, int **channels)
-{
-
- int i;
- int *chan = NULL;
- FN_IN;
- if (unlikely(NULL == channels)) {
- BUG();
- return -EPERM;
- }
- if (unlikely(NULL == *channels)) {
- BUG();
- return -EPERM;
- }
- chan = (*channels);
-
- if (!cpu_is_omap1510())
- omap_sound_dma_unlink_lch(data);
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- omap_stop_dma(cur_chan);
- omap_free_dma(cur_chan);
- }
- kfree(*channels);
- *channels = NULL;
- FN_OUT(0);
- return 0;
-}
-
-/***************************************************************************************
- *
- * Stop all the DMA channels of the stream
- *
- **************************************************************************************/
-void omap_audio_stop_dma(struct audio_stream *s)
-{
- int *chan = s->lch;
- int i;
- FN_IN;
- if (unlikely(NULL == chan)) {
- BUG();
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- omap_stop_dma(cur_chan);
- }
- s->started = 0;
- FN_OUT(0);
- return;
-}
-/***************************************************************************************
- *
- * Clear any pending transfers
- *
- **************************************************************************************/
-void omap_clear_sound_dma(struct audio_stream * s)
-{
- FN_IN;
- omap_clear_dma(s->lch[s->dma_q_head]);
- FN_OUT(0);
- return;
-}
-
-/*********************************** MODULE FUNCTIONS DEFINTIONS ***********************/
-
-#ifdef OMAP1610_MCBSP1_BASE
-#undef OMAP1610_MCBSP1_BASE
-#endif
-#define OMAP1610_MCBSP1_BASE 0xE1011000
-
-/***************************************************************************************
- *
- * DMA related functions
- *
- **************************************************************************************/
-static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int dt = 0x1; /* data type 16 */
- int cen = 32; /* Stereo */
- int cfn = dma_size / (2 * cen);
- FN_IN;
- omap_set_dma_dest_params(channel, 0x05, 0x00,
- (OMAP1610_MCBSP1_BASE + 0x806),
- 0, 0);
- omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
- 0, 0);
- omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
- FN_OUT(0);
- return 0;
-}
-
-static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int dt = 0x1; /* data type 16 */
- int cen = 32; /* stereo */
-
- int cfn = dma_size / (2 * cen);
- FN_IN;
- omap_set_dma_src_params(channel, 0x05, 0x00,
- (OMAP1610_MCBSP1_BASE + 0x802),
- 0, 0);
- omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
- omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
- FN_OUT(0);
- return 0;
-}
-
-static int audio_start_dma_chain(struct audio_stream *s)
-{
- int channel = s->lch[s->dma_q_head];
- FN_IN;
- if (!s->started) {
- s->hw_stop(); /* stops McBSP Interface */
- omap_start_dma(channel);
- s->started = 1;
- s->hw_start(); /* start McBSP interface */
- }
- /* else the dma itself will progress forward with out our help */
- FN_OUT(0);
- return 0;
-}
-
-/* Start DMA -
- * Do the initial set of work to initialize all the channels as required.
- * We shall then initate a transfer
- */
-int omap_start_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int ret = -EPERM;
-
- FN_IN;
-
- if (unlikely(dma_size > MAX_DMA_SIZE)) {
- ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
- MAX_DMA_SIZE);
- return -EOVERFLOW;
- }
- //if (AUDIO_QUEUE_FULL(s)) {
- // ret = -2;
- // goto sound_out;
- //}
-
- if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
- /*playback */
- ret =
- audio_set_dma_params_play(s->lch[s->dma_q_tail],
- dma_ptr, dma_size);
- } else {
- ret =
- audio_set_dma_params_capture(s->lch[s->dma_q_tail],
- dma_ptr, dma_size);
- }
- if (ret != 0) {
- ret = -3; /* indicate queue full */
- goto sound_out;
- }
- AUDIO_INCREMENT_TAIL(s);
- ret = audio_start_dma_chain(s);
- if (ret) {
- ERR("dma start failed");
- }
- sound_out:
- FN_OUT(ret);
- return ret;
-
-}
-
-/*
- * ISRs have to be short and smart..
- * Here we call alsa handling, after some error checking
- */
-static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status,
- void *data)
-{
- int dma_status = ch_status;
- struct audio_stream *s = (struct audio_stream *) data;
- FN_IN;
-
- /*
- * some register checkings
- */
- DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
- sound_curr_lch, ch_status, dma_status, data);
-
- if (dma_status & (DCSR_ERROR)) {
- OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
- ERR("DCSR_ERROR!\n");
- FN_OUT(-1);
- return;
- }
-
- if (ch_status & DCSR_END_BLOCK)
- audio_dma_callback(s);
- FN_OUT(0);
- return;
-}
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION
- ("Common DMA handling for Audio driver on OMAP processors");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(omap_start_sound_dma);
-EXPORT_SYMBOL(omap_clear_sound_dma);
-EXPORT_SYMBOL(omap_request_sound_dma);
-EXPORT_SYMBOL(omap_free_sound_dma);
-EXPORT_SYMBOL(omap_audio_stop_dma);
Index: linux-omap-2.6.git-q/sound/arm/omap/omap-alsa-dma.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-omap-2.6.git-q/sound/arm/omap/omap-alsa-dma.h 2006-02-16 08:40:57.000000000 -0400
@@ -0,0 +1,59 @@
+/*
+ * linux/sound/arm/omap/omap-alsa-dma.h
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ *
+ * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2005/07/25 INdT Kernel Team - Renamed to omap-alsa-dma.h. Ported to Alsa.
+ */
+
+#ifndef __OMAP_AUDIO_ALSA_DMA_H
+#define __OMAP_AUDIO_ALSA_DMA_H
+
+/************************** INCLUDES *************************************/
+
+#include <asm/arch/omap-alsa.h>
+
+/************************** GLOBAL MACROS *************************************/
+
+/* Provide the Macro interfaces common across platforms */
+#define DMA_REQUEST(e,s, cb) {e=omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);}
+#define DMA_FREE(s) omap_free_sound_dma(s, &s->lch)
+#define DMA_CLEAR(s) omap_clear_sound_dma(s)
+
+/************************** GLOBAL DATA STRUCTURES *********************************/
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/**************** ARCH SPECIFIC FUNCIONS *******************************************/
+
+void omap_clear_sound_dma(struct audio_stream * s);
+
+int omap_request_sound_dma(int device_id, const char *device_name,
+ void *data, int **channels);
+int omap_free_sound_dma(void *data, int **channels);
+
+int omap_start_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
+ u_int dma_size);
+
+void omap_audio_stop_dma(struct audio_stream *s);
+
+#endif
Index: linux-omap-2.6.git-q/sound/arm/omap-alsa-dma.h
===================================================================
--- linux-omap-2.6.git-q.orig/sound/arm/omap-alsa-dma.h 2006-02-16 08:38:29.000000000 -0400
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,59 +0,0 @@
-/*
- * linux/sound/arm/omap-alsa-dma.h
- *
- * Common audio DMA handling for the OMAP processors
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History:
- *
- *
- * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
- *
- * 2005/07/25 INdT Kernel Team - Renamed to omap-alsa-dma.h. Ported to Alsa.
- */
-
-#ifndef __OMAP_AUDIO_ALSA_DMA_H
-#define __OMAP_AUDIO_ALSA_DMA_H
-
-/************************** INCLUDES *************************************/
-
-#include <asm/arch/omap-alsa.h>
-
-/************************** GLOBAL MACROS *************************************/
-
-/* Provide the Macro interfaces common across platforms */
-#define DMA_REQUEST(e,s, cb) {e=omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);}
-#define DMA_FREE(s) omap_free_sound_dma(s, &s->lch)
-#define DMA_CLEAR(s) omap_clear_sound_dma(s)
-
-/************************** GLOBAL DATA STRUCTURES *********************************/
-
-typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
-
-/**************** ARCH SPECIFIC FUNCIONS *******************************************/
-
-void omap_clear_sound_dma(struct audio_stream * s);
-
-int omap_request_sound_dma(int device_id, const char *device_name,
- void *data, int **channels);
-int omap_free_sound_dma(void *data, int **channels);
-
-int omap_start_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
- u_int dma_size);
-
-void omap_audio_stop_dma(struct audio_stream *s);
-
-#endif
Index: linux-omap-2.6.git-q/sound/arm/Makefile
===================================================================
--- linux-omap-2.6.git-q.orig/sound/arm/Makefile 2006-02-16 08:34:58.000000000 -0400
+++ linux-omap-2.6.git-q/sound/arm/Makefile 2006-02-16 08:40:57.000000000 -0400
@@ -14,9 +14,4 @@ snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
-obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-alsa-aic23.o
-snd-omap-alsa-aic23-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-mixer.o
-
-obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-alsa-tsc2101.o
-snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2101-mixer.o
-
+obj-$(CONFIG_SND) += omap/
Index: linux-omap-2.6.git-q/sound/arm/omap/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-omap-2.6.git-q/sound/arm/omap/Makefile 2006-02-16 08:40:57.000000000 -0400
@@ -0,0 +1,10 @@
+#
+## Makefile for ALSA OMAP
+#
+#
+obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-alsa-aic23.o
+snd-omap-alsa-aic23-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-alsa-tsc2101.o
+snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2101-mixer.o
+
Index: linux-omap-2.6.git-q/sound/arm/omap-alsa-mixer.c
===================================================================
--- linux-omap-2.6.git-q.orig/sound/arm/omap-alsa-mixer.c 2006-02-16 08:38:29.000000000 -0400
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,485 +0,0 @@
-/*
- * sound/arm/omap/omap-alsa-mixer.c
- *
- * Alsa Driver Mixer for generic codecs for omap boards
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Written by David Cohen, Daniel Petrini
- * {david.cohen, daniel.petrini}@indt.org.br
- *
- * Based on es1688_lib.c,
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History:
- *
- * 2005-08-02 INdT Kernel Team - Alsa mixer driver for omap osk. Creation of new
- * file omap-alsa-mixer.c. Initial version
- * with aic23 codec for osk5912
- */
-
-#include <linux/config.h>
-#include <sound/driver.h>
-#include <asm/arch/aic23.h>
-
-#include <asm/arch/omap-alsa.h>
-#include <../arch/arm/mach-omap1/omap-alsa-aic23.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-
-MODULE_AUTHOR("David Cohen, Daniel Petrini - INdT");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
-
-/*
- * Codec dependent region
- */
-
-/* Codec AIC23 */
-#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
-
-extern __inline__ void audio_aic23_write(u8, u16);
-
-#define MIXER_NAME "Mixer AIC23"
-#define SND_OMAP_WRITE(reg, val) audio_aic23_write(reg, val)
-
-#endif
-
-/* Callback Functions */
-#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .info = snd_omap_info_bool, \
- .get = snd_omap_get_bool, \
- .put = snd_omap_put_bool, \
- .private_value = reg | (reg_index << 8) | (invert << 10) | (mask << 12) \
-}
-
-#define OMAP_MUX(xname, reg, reg_index, mask) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .info = snd_omap_info_mux, \
- .get = snd_omap_get_mux, \
- .put = snd_omap_put_mux, \
- .private_value = reg | (reg_index << 8) | (mask << 10) \
-}
-
-#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
-{\
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .info = snd_omap_info_single, \
- .get = snd_omap_get_single, \
- .put = snd_omap_put_single, \
- .private_value = reg | (reg_val << 8) | (reg_index << 16) | (mask << 18) \
-}
-
-#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
-{\
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .info = snd_omap_info_double, \
- .get = snd_omap_get_double, \
- .put = snd_omap_put_double, \
- .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | (mask << 18) \
-}
-
-/* Local Registers */
-enum snd_device_index {
- PCM_INDEX = 0,
- LINE_INDEX,
- AAC_INDEX, /* Analog Audio Control: reg = l_reg */
-};
-
-struct {
- u16 l_reg;
- u16 r_reg;
- u8 sw;
-} omap_regs[3];
-
-#ifdef CONFIG_PM
-struct {
- u16 l_reg;
- u16 r_reg;
- u8 sw;
-} omap_pm_regs[3];
-#endif
-
-u16 snd_sidetone[6] = {
- SIDETONE_18,
- SIDETONE_12,
- SIDETONE_9,
- SIDETONE_6,
- SIDETONE_0,
- 0
-};
-
-/* Begin Bool Functions */
-
-static int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
-
- return 0;
-}
-
-static int snd_omap_get_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- int mic_index = (kcontrol->private_value >> 8) & 0x03;
- u16 mask = (kcontrol->private_value >> 12) & 0xff;
- int invert = (kcontrol->private_value >> 10) & 0x03;
-
- if (invert)
- ucontrol->value.integer.value[0] = (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
- else
- ucontrol->value.integer.value[0] = (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
-
- return 0;
-}
-
-static int snd_omap_put_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- int mic_index = (kcontrol->private_value >> 8) & 0x03;
- u16 mask = (kcontrol->private_value >> 12) & 0xff;
- u16 reg = kcontrol->private_value & 0xff;
- int invert = (kcontrol->private_value >> 10) & 0x03;
-
- int changed = 1;
-
- if (ucontrol->value.integer.value[0]) /* XOR */
- if (invert)
- omap_regs[mic_index].l_reg &= ~mask;
- else
- omap_regs[mic_index].l_reg |= mask;
- else
- if (invert)
- omap_regs[mic_index].l_reg |= mask;
- else
- omap_regs[mic_index].l_reg &= ~mask;
-
- SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
-
- return changed;
-}
-
-/* End Bool Functions */
-
-/* Begin Mux Functions */
-
-static int snd_omap_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
- /* Mic = 0
- * Line = 1 */
- static char *texts[2] = { "Mic", "Line" };
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
-
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
-
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-
- return 0;
-}
-
-static int snd_omap_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- u16 mask = (kcontrol->private_value >> 10) & 0xff;
- int mux_index = (kcontrol->private_value >> 8) & 0x03;
-
- ucontrol->value.enumerated.item[0] = (omap_regs[mux_index].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
-
- return 0;
-}
-
-static int snd_omap_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- u16 reg = kcontrol->private_value & 0xff;
- u16 mask = (kcontrol->private_value >> 10) & 0xff;
- int mux_index = (kcontrol->private_value >> 8) & 0x03;
-
- int changed = 1;
-
- if (!ucontrol->value.integer.value[0])
- omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
- else
- omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
-
- SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
-
- return changed;
-}
-
-/* End Mux Functions */
-
-/* Begin Single Functions */
-
-static int snd_omap_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
- int mask = (kcontrol->private_value >> 18) & 0xff;
- int reg_val = (kcontrol->private_value >> 8) & 0xff;
-
- uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER : SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = reg_val-1;
-
- return 0;
-}
-
-static int snd_omap_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
-
- ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
-
- return 0;
-}
-
-static int snd_omap_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
- u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
- u16 reg = kcontrol->private_value & 0xff;
- u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
-
- int changed = 0;
-
- /* Volume */
- if ((omap_regs[reg_index].l_reg != (ucontrol->value.integer.value[0] & mask)))
- {
- changed = 1;
-
- omap_regs[reg_index].l_reg &= ~mask;
- omap_regs[reg_index].l_reg |= snd_sidetone[ucontrol->value.integer.value[0]];
-
- snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
- SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
- }
- else
- changed = 0;
-
- return changed;
-}
-
-/* End Single Functions */
-
-/* Begin Double Functions */
-
-static int snd_omap_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
- /* mask == 0 : Switch
- * mask != 0 : Volume */
- int mask = (kcontrol->private_value >> 18) & 0xff;
-
- uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER : SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = mask ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask ? mask : 1;
-
- return 0;
-}
-
-static int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- /* mask == 0 : Switch
- * mask != 0 : Volume */
- int mask = (kcontrol->private_value >> 18) & 0xff;
- int vol_index = (kcontrol->private_value >> 16) & 0x03;
-
- if (!mask)
- /* Switch */
- ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
- else
- {
- /* Volume */
- ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
- ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
- }
-
- return 0;
-}
-
-static int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- /* mask == 0 : Switch
- * mask != 0 : Volume */
- int vol_index = (kcontrol->private_value >> 16) & 0x03;
- int mask = (kcontrol->private_value >> 18) & 0xff;
- int left_reg = kcontrol->private_value & 0xff;
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
-
- int changed = 0;
-
- if (!mask)
- {
- /* Switch */
- if (!ucontrol->value.integer.value[0])
- {
- SND_OMAP_WRITE(left_reg, 0x00);
- SND_OMAP_WRITE(right_reg, 0x00);
- }
- else
- {
- SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
- SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
- }
- changed = 1;
- omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
- }
- else
- {
- /* Volume */
- if ((omap_regs[vol_index].l_reg != (ucontrol->value.integer.value[0] & mask)) ||
- (omap_regs[vol_index].r_reg != (ucontrol->value.integer.value[1] & mask)))
- {
- changed = 1;
-
- omap_regs[vol_index].l_reg &= ~mask;
- omap_regs[vol_index].r_reg &= ~mask;
- omap_regs[vol_index].l_reg |= (ucontrol->value.integer.value[0] & mask);
- omap_regs[vol_index].r_reg |= (ucontrol->value.integer.value[1] & mask);
- if (omap_regs[vol_index].sw)
- {
- /* write to registers only if sw is actived */
- SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
- SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
- }
- }
- else
- changed = 0;
- }
-
- return changed;
-}
-
-/* End Double Functions */
-
-static snd_kcontrol_new_t snd_omap_controls[] = {
- OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
- PCM_INDEX, 0x00),
- OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
- PCM_INDEX, OUTPUT_VOLUME_MASK),
- OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, BYPASS_ON, 0),
- OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
- LINE_INDEX, 0x00),
- OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
- LINE_INDEX, INPUT_VOLUME_MASK),
- OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, STE_ENABLED, 0),
- OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, 5, SIDETONE_MASK),
- OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICM_MUTED, 1),
- OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
- OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
-};
-
-#ifdef CONFIG_PM
-
-void snd_omap_suspend_mixer(void)
-{
- /* Saves current values to wake-up correctly */
- omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
- omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
- omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
-
- omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
-
- omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
- omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
- omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
-}
-
-void snd_omap_resume_mixer(void)
-{
- /* Line's saved values */
- omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
- omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
- omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
- SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
- SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
-
- /* Analog Audio Control's saved values */
- omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
- SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
-
- /* Headphone's saved values */
- omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
- omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
- omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
- SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].l_reg);
- SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].r_reg);
-}
-#endif
-
-void snd_omap_init_mixer(void)
-{
- u16 vol_reg;
-
- /* Line's default values */
- omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
- omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
- omap_regs[LINE_INDEX].sw = 0;
- SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
- SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
-
- /* Analog Audio Control's default values */
- omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
-
- /* Headphone's default values */
- vol_reg = LZC_ON;
- vol_reg &= ~OUTPUT_VOLUME_MASK;
- vol_reg |= DEFAULT_OUTPUT_VOLUME;
- omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
- omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
- omap_regs[PCM_INDEX].sw = 1;
- SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
- SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
-}
-
-int snd_omap_mixer(struct snd_card_omap_codec *chip)
-{
- snd_card_t *card;
- unsigned int idx;
- int err;
-
- snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
-
- card = chip->card;
-
- strcpy(card->mixername, MIXER_NAME);
-
- /* Registering alsa mixer controls */
- for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++)
- if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_omap_controls[idx], chip))) < 0)
- return err;
-
- return 0;
-}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2006-02-20 18:27 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-02-20 18:27 [PATCH] Alsa modularisations and support for tsc2101 5/7 lamikr
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox