[PATCH] Alsa modularisations and support for tsc2101 1/7

Daniel Petrini
2006-02-20T17:44:14Z

[-- Attachment #1: Type: text/plain, Size: 1285 bytes --]

ALSA Omap Modularisation

This series of patches adds modularisation in alsa files for omap so that
makes possible to use the same alsa omap core files for different boards.
Regarding the original omap alsa support, the codec specific functions
were removed from file omap-aic23.c (which now is called omap-alsa.c)
and inserted in a specific file for this codec. Similar action was made
for tsc2101 codec, based in oss former drivers.
With this series of patches omap now have support for osk and H2 boards.
Besides codec files, the mixer file has its support added for H2.

Summary:

-New architecture: extraction of codec dependent code from main alsa file
-Support for board H2
-Creation of codec alsa file for codec aic23 (from existing alsa work)
-Creation of codec alsa file for codec tsc2101 from oss
-Migration of specific codec configuration to platform_data
-Improvement of function probe in omap-alsa driver
-Creation of the mixer for tsc2101

This first patch creates the new files omap-alsa.[c,h] based in the
former omap-aic23.[c,h] and put the .h file in include/asm/arch/.

signed-off by Daniel Petrini <d.pensator@gmail.com>
signed-off by Mika Laitio <lamikr@cc.jyu.fi>

------------------------
Daniel Petrini
--
INdT - Manaus - Brazil

[-- Attachment #2: alsa1-20060214.patch --]
[-- Type: text/x-patch, Size: 56503 bytes --]

ALSA Omap Modularisation

This series of patches adds modularisation in alsa files for omap so that
makes possible to use the same alsa omap core files for different boards.
Regarding the original omap alsa support, the codec specific functions
were removed from file omap-aic23.c (which now is called omap-alsa.c)
and inserted in a specific file for this codec. Similar action was made
for tsc2101 codec, based in oss former drivers.
With this series of patches omap now have support for osk and H2 boards.
Besides codec files, the mixer file has its support added for H2.

Summary:

-New architecture: extraction of codec dependent code from main alsa file
-Support for board H2
-Creation of codec alsa file for codec aic23 (from existing alsa work)
-Creation of codec alsa file for codec tsc2101 from oss
-Migration of specific codec configuration to platform_data
-Improvement of function probe in omap-alsa driver
-Creation of the mixer for tsc2101

This first patch creates the new files omap-alsa.[c,h] based in the
former omap-aic23.[c,h] and put the .h file in include/asm/arch/.

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/Makefile
===================================================================
--- linux-omap-2.6.git-q.orig/sound/arm/Makefile 2006-02-14 08:25:48.000000000 -0400
+++ linux-omap-2.6.git-q/sound/arm/Makefile 2006-02-14 09:35:12.000000000 -0400
@@ -14,5 +14,9 @@ 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-aic23.o
-snd-omap-aic23-objs := omap-aic23.o omap-alsa-dma.o omap-alsa-mixer.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
+
Index: linux-omap-2.6.git-q/sound/arm/omap-alsa.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-omap-2.6.git-q/sound/arm/omap-alsa.c 2006-02-14 09:49:14.000000000 -0400
@@ -0,0 +1,714 @@
+/*
+ * 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/include/asm-arm/arch-omap/omap-alsa.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-omap-2.6.git-q/include/asm-arm/arch-omap/omap-alsa.h 2006-02-14 09:48:25.000000000 -0400
@@ -0,0 +1,150 @@
+/*
+ * linux/include/asm-arm/arch-omap/omap-alsa.h
+ *
+ * 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
+ *
+ * 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/25 INdT-10LE Kernel Team - Alsa driver for omap osk,
+ * original version based in sa1100 driver
+ * and omap oss driver.
+ *
+ * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ * 2006-02-10 Mika Laitio - Moved from sound/arm to linux/include/asm-arm/arch-omap.
+ * Added omap alsa codec config datatype to handle aic23 and tsc2101
+ * codecs from the same omap-alsa.c base driver.
+ */
+
+#ifndef __OMAP_ALSA_H
+#define __OMAP_ALSA_H
+
+#include <sound/driver.h>
+#include <asm/arch/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <asm/arch/mcbsp.h>
+
+/*
+ * Debug functions
+ */
+#undef DEBUG
+//#define DEBUG
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
+#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(ARGS...) /* nop */
+#define ADEBUG() /* nop */
+#define FN_IN /* nop */
+#define FN_OUT(n) /* nop */
+#endif
+
+/*
+ * Buffer management for alsa and dma
+ */
+struct audio_stream {
+ char *id; /* identification string */
+ int stream_id; /* numeric identification */
+ int dma_dev; /* dma number of that device */
+ int *lch; /* Chain of channels this stream is linked to */
+ char started; /* to store if the chain was started or not */
+ int dma_q_head; /* DMA Channel Q Head */
+ int dma_q_tail; /* DMA Channel Q Tail */
+ char dma_q_count; /* DMA Channel Q Count */
+ int active:1; /* we are using this stream for transfer now */
+ int period; /* current transfer period */
+ int periods; /* current count of periods registerd in the DMA engine */
+ spinlock_t dma_lock; /* for locking in DMA operations */
+ snd_pcm_substream_t *stream; /* the pcm stream */
+ unsigned linked:1; /* dma channels linked */
+ int offset; /* store start position of the last period in the alsa buffer */
+ int (*hw_start)(void); /* interface to start HW interface, e.g. McBSP */
+ int (*hw_stop)(void); /* interface to stop HW interface, e.g. McBSP */
+};
+
+/*
+ * Alsa card structure for aic23
+ */
+struct snd_card_omap_codec {
+ snd_card_t *card;
+ snd_pcm_t *pcm;
+ long samplerate;
+ struct audio_stream s[2]; /* playback & capture */
+};
+
+/* Codec specific information and function pointers.
+ * Codec (omap-alsa-aic23.c and omap-alsa-tsc2101.c)
+ * are responsible for defining the function pointers.
+ */
+struct omap_alsa_codec_config {
+ char *name;
+ struct omap_mcbsp_reg_cfg * mcbsp_regs_alsa;
+ void (*codec_configure_dev)(void);
+ void (*codec_set_samplerate)(long);
+ void (*codec_clock_setup)(void);
+ int (*codec_clock_on)(void);
+ int (*codec_clock_off)(void);
+ int (*get_default_samplerate)(void);
+};
+
+/*********** Mixer function prototypes *************************/
+int snd_omap_mixer(struct snd_card_omap_codec *);
+void snd_omap_init_mixer(void);
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void);
+void snd_omap_resume_mixer(void);
+#endif
+
+/*
+ * Defines codec specific functions pointers that can be used from the
+ * common omap-alse base driver for all omap codecs. (tsc2101 and aic23)
+ */
+void define_codec_functions(struct omap_alsa_codec_config *codec_config);
+inline void aic23_configure(void);
+void aic23_set_samplerate(long rate);
+void aic23_clock_setup(void);
+int aic23_clock_on(void);
+int aic23_clock_off(void);
+int aic23_get_default_samplerate(void);
+
+inline void tsc2101_configure(void);
+void tsc2101_set_samplerate(long rate);
+void tsc2101_clock_setup(void);
+int tsc2101_clock_on(void);
+int tsc2101_clock_off(void);
+int tsc2101_get_default_samplerate(void);
+
+/*********** function prototype to function called from the dma interrupt handler ******/
+void audio_dma_callback(void *);
+
+#endif
Index: linux-omap-2.6.git-q/sound/arm/omap-aic23.h
===================================================================
--- linux-omap-2.6.git-q.orig/sound/arm/omap-aic23.h 2006-02-14 08:25:48.000000000 -0400
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,130 +0,0 @@
-/*
- * sound/arm/omap-aic23.h
- *
- * 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
- *
- * 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/25 INdT-10LE Kernel Team - Alsa driver for omap osk,
- * original version based in sa1100 driver
- * and omap oss driver.
- *
- * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
- */
-
-#ifndef __OMAP_AIC23_H
-#define __OMAP_AIC23_H
-
-#include <sound/driver.h>
-#include <asm/arch/dma.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-
-#define DEFAULT_OUTPUT_VOLUME 0x60
-#define DEFAULT_INPUT_VOLUME 0x00 /* 0 ==> mute line in */
-
-#define OUTPUT_VOLUME_MIN LHV_MIN
-#define OUTPUT_VOLUME_MAX LHV_MAX
-#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
-#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MAX
-
-#define INPUT_VOLUME_MIN LIV_MIN
-#define INPUT_VOLUME_MAX LIV_MAX
-#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
-#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
-
-#define SIDETONE_MASK 0x1c0
-#define SIDETONE_0 0x100
-#define SIDETONE_6 0x000
-#define SIDETONE_9 0x040
-#define SIDETONE_12 0x080
-#define SIDETONE_18 0x0c0
-
-#define DEFAULT_ANALOG_AUDIO_CONTROL DAC_SELECTED | STE_ENABLED | BYPASS_ON | INSEL_MIC | MICB_20DB
-
-/*
- * Buffer management for alsa and dma
- */
-struct audio_stream {
- char *id; /* identification string */
- int stream_id; /* numeric identification */
- int dma_dev; /* dma number of that device */
- int *lch; /* Chain of channels this stream is linked to */
- char started; /* to store if the chain was started or not */
- int dma_q_head; /* DMA Channel Q Head */
- int dma_q_tail; /* DMA Channel Q Tail */
- char dma_q_count; /* DMA Channel Q Count */
- int active:1; /* we are using this stream for transfer now */
- int period; /* current transfer period */
- int periods; /* current count of periods registerd in the DMA engine */
- spinlock_t dma_lock; /* for locking in DMA operations */
- snd_pcm_substream_t *stream; /* the pcm stream */
- unsigned linked:1; /* dma channels linked */
- int offset; /* store start position of the last period in the alsa buffer */
- int (*hw_start)(void); /* interface to start HW interface, e.g. McBSP */
- int (*hw_stop)(void); /* interface to stop HW interface, e.g. McBSP */
-};
-
-/*
- * Alsa card structure for aic23
- */
-struct snd_card_omap_aic23 {
- snd_card_t *card;
- snd_pcm_t *pcm;
- long samplerate;
- struct audio_stream s[2]; /* playback & capture */
-};
-
-/*********** Function Prototypes *************************/
-
-void audio_dma_callback(void *);
-int snd_omap_mixer(struct snd_card_omap_aic23 *);
-void snd_omap_init_mixer(void);
-/* Clock functions */
-int omap_aic23_clock_on(void);
-int omap_aic23_clock_off(void);
-
-#ifdef CONFIG_PM
-void snd_omap_suspend_mixer(void);
-void snd_omap_resume_mixer(void);
-#endif
-
-/* Codec AIC23 */
-#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
-
-extern int tlv320aic23_write_value(u8 reg, u16 value);
-
-/* TLV320AIC23 is a write only device */
-static __inline__ void audio_aic23_write(u8 address, u16 data)
-{
- tlv320aic23_write_value(address, data);
-}
-
-#endif /* CONFIG_SENSORS_TLV320AIC23 */
-
-#endif
Index: linux-omap-2.6.git-q/sound/arm/omap-aic23.c
===================================================================
--- linux-omap-2.6.git-q.orig/sound/arm/omap-aic23.c 2006-02-14 08:25:48.000000000 -0400
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,929 +0,0 @@
-/*
- * sound/arm/omap-aic23.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
- */
-
-#include <linux/config.h>
-#include <sound/driver.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-
-#ifdef CONFIG_PM
-#include <linux/pm.h>
-#endif
-
-#include <asm/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/aic23.h>
-#include <asm/arch/mcbsp.h>
-#include <asm/arch/clock.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-#include <sound/memalloc.h>
-
-#include "omap-alsa-dma.h"
-#include "omap-aic23.h"
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
-#else
-#define ADEBUG() /* nop */
-#endif
-
-/* Define to set the AIC23 as the master w.r.t McBSP */
-#define AIC23_MASTER
-
-/*
- * AUDIO related MACROS
- */
-#define DEFAULT_BITPERSAMPLE 16
-#define AUDIO_RATE_DEFAULT 44100
-#define AUDIO_MCBSP OMAP_MCBSP1
-#define NUMBER_SAMPLE_RATES_SUPPORTED 10
-
-
-MODULE_AUTHOR("Daniel Petrini, David Cohen, Anderson Briglia - INdT");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("OMAP AIC23 driver for ALSA");
-MODULE_SUPPORTED_DEVICE("{{AIC23,OMAP AIC23}}");
-MODULE_ALIAS("omap_mcbsp.1");
-
-static char *id = NULL;
-MODULE_PARM_DESC(id, "OMAP OSK ALSA Driver for AIC23 chip.");
-
-static struct snd_card_omap_aic23 *omap_aic23 = NULL;
-
-static struct clk *aic23_mclk = 0;
-
-struct sample_rate_rate_reg_info {
- u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
- u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
-};
-
-/*
- * 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 const struct sample_rate_rate_reg_info
- rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
- {0x06, 1}, /* 4000 */
- {0x06, 0}, /* 8000 */
- {0x0C, 1}, /* 16000 */
- {0x11, 1}, /* 22050 */
- {0x00, 1}, /* 24000 */
- {0x0C, 0}, /* 32000 */
- {0x11, 0}, /* 44100 */
- {0x00, 0}, /* 48000 */
- {0x1F, 0}, /* 88200 */
- {0x0E, 0}, /* 96000 */
-};
-
-/*
- * mcbsp configuration structure
- */
-static struct omap_mcbsp_reg_cfg initial_config_mcbsp = {
- .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
- .spcr1 = RINTM(3) | RRST,
- .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
- RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0),
- .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
- .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
- XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG,
- .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
- .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
- .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
-#ifndef AIC23_MASTER
- /* configure McBSP to be the I2S master */
- .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
-#else
- /* configure McBSP to be the I2S slave */
- .pcr0 = CLKXP | CLKRP,
-#endif /* AIC23_MASTER */
-};
-
-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;
-}
-
-/*
- * Codec/mcbsp init and configuration section
- * codec dependent code.
- */
-
-/*
- * Sample rate changing
- */
-static void omap_aic23_set_samplerate(struct snd_card_omap_aic23
- *omap_aic23, long rate)
-{
- u8 count = 0;
- u16 data = 0;
-
- /* Fix the rate if it has a wrong value */
- if (rate >= 96000)
- rate = 96000;
- else if (rate >= 88200)
- rate = 88200;
- else if (rate >= 48000)
- rate = 48000;
- else if (rate >= 44100)
- rate = 44100;
- else if (rate >= 32000)
- rate = 32000;
- else if (rate >= 24000)
- rate = 24000;
- else if (rate >= 22050)
- rate = 22050;
- else if (rate >= 16000)
- rate = 16000;
- else if (rate >= 8000)
- rate = 8000;
- else
- rate = 4000;
-
- /* Search for the right sample rate */
- /* Verify what happens if the rate is not supported
- * now it goes to 96Khz */
- while ((rates[count] != rate) &&
- (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
- count++;
- }
-
- data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
- (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
-
- audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
-
- omap_aic23->samplerate = rate;
-}
-
-static inline void aic23_configure(void)
-{
- /* Reset codec */
- audio_aic23_write(RESET_CONTROL_ADDR, 0);
-
- /* Initialize the AIC23 internal state */
-
- /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
- audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DEFAULT_ANALOG_AUDIO_CONTROL);
-
- /* Digital audio path control, de-emphasis control 44.1kHz */
- audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
-
- /* Digital audio interface, master/slave mode, I2S, 16 bit */
-#ifdef AIC23_MASTER
- audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
- MS_MASTER | IWL_16 | FOR_DSP);
-#else
- audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
-#endif
-
- /* Enable digital interface */
- audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
-
-}
-
-static void omap_aic23_audio_init(struct snd_card_omap_aic23 *omap_aic23)
-{
- /* Setup DMA stuff */
- omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa AIC23 out";
- omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
- SNDRV_PCM_STREAM_PLAYBACK;
- omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
- OMAP_DMA_MCBSP1_TX;
- omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
- audio_ifc_start;
- omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
- audio_ifc_stop;
-
- omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa AIC23 in";
- omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
- SNDRV_PCM_STREAM_CAPTURE;
- omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
- OMAP_DMA_MCBSP1_RX;
- omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
- audio_ifc_start;
- omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
- audio_ifc_stop;
-
- /* configuring the McBSP */
- omap_mcbsp_request(AUDIO_MCBSP);
-
- /* if configured, then stop mcbsp */
- omap_mcbsp_stop(AUDIO_MCBSP);
-
- omap_mcbsp_config(AUDIO_MCBSP, &initial_config_mcbsp);
- omap_mcbsp_start(AUDIO_MCBSP);
- aic23_configure();
-}
-
-/*
- * DMA functions
- * Depends on omap-aic23-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;
-
- 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;
-
- 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;
-
- 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,);
- 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;
-
- /*
- * 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_aic23_trigger(snd_pcm_substream_t * substream, int cmd)
-{
- struct snd_card_omap_aic23 *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_aic23_prepare(snd_pcm_substream_t * substream)
-{
- struct snd_card_omap_aic23 *chip =
- snd_pcm_substream_chip(substream);
- snd_pcm_runtime_t *runtime = substream->runtime;
- struct audio_stream *s = &chip->s[substream->pstr->stream];
-
- /* set requested samplerate */
- omap_aic23_set_samplerate(chip, runtime->rate);
-
- s->period = 0;
- s->periods = 0;
-
- return 0;
-}
-
-static snd_pcm_uframes_t snd_omap_aic23_pointer(snd_pcm_substream_t *
- substream)
-{
- struct snd_card_omap_aic23 *chip =
- snd_pcm_substream_chip(substream);
-
- return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
-}
-
-/* Hardware capabilities */
-
-static snd_pcm_hardware_t snd_omap_aic23_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_aic23_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_aic23_open(snd_pcm_substream_t * substream)
-{
- struct snd_card_omap_aic23 *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;
-
- omap_aic23_clock_on();
-
- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
- runtime->hw = snd_omap_aic23_playback;
- else
- runtime->hw = snd_omap_aic23_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_aic23_close(snd_pcm_substream_t * substream)
-{
- struct snd_card_omap_aic23 *chip =
- snd_pcm_substream_chip(substream);
- ADEBUG();
-
- omap_aic23_clock_off();
- chip->s[substream->pstr->stream].stream = NULL;
-
- return 0;
-}
-
-/* HW params & free */
-
-static int snd_omap_aic23_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_aic23_hw_free(snd_pcm_substream_t * substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
-/* pcm operations */
-
-static snd_pcm_ops_t snd_card_omap_aic23_playback_ops = {
- .open = snd_card_omap_aic23_open,
- .close = snd_card_omap_aic23_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_omap_aic23_hw_params,
- .hw_free = snd_omap_aic23_hw_free,
- .prepare = snd_omap_aic23_prepare,
- .trigger = snd_omap_aic23_trigger,
- .pointer = snd_omap_aic23_pointer,
-};
-
-static snd_pcm_ops_t snd_card_omap_aic23_capture_ops = {
- .open = snd_card_omap_aic23_open,
- .close = snd_card_omap_aic23_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_omap_aic23_hw_params,
- .hw_free = snd_omap_aic23_hw_free,
- .prepare = snd_omap_aic23_prepare,
- .trigger = snd_omap_aic23_trigger,
- .pointer = snd_omap_aic23_pointer,
-};
-
-/*
- * Alsa init and exit section
- *
- * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
- */
-static int __init snd_card_omap_aic23_pcm(struct snd_card_omap_aic23
- *omap_aic23, int device)
-{
- snd_pcm_t *pcm;
- int err;
- ADEBUG();
-
- if ((err =
- snd_pcm_new(omap_aic23->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_aic23_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
- &snd_card_omap_aic23_capture_ops);
- pcm->private_data = omap_aic23;
- pcm->info_flags = 0;
- strcpy(pcm->name, "omap aic23 pcm");
-
- omap_aic23_audio_init(omap_aic23);
-
- /* setup DMA controller */
- audio_dma_request(&omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK],
- audio_dma_callback);
- audio_dma_request(&omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE],
- audio_dma_callback);
-
- omap_aic23->pcm = pcm;
-
- return 0;
-}
-
-
-#ifdef CONFIG_PM
-
-static int snd_omap_aic23_suspend(snd_card_t * card, pm_message_t state)
-{
- struct snd_card_omap_aic23 *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 */
- omap_aic23_clock_off();
- snd_omap_suspend_mixer();
- }
-
- return 0;
-}
-
-/*
- * Prepare hardware for resume
- */
-static int snd_omap_aic23_resume(snd_card_t * card)
-{
- struct snd_card_omap_aic23 *chip = card->private_data;
- ADEBUG();
-
- if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
- snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
- omap_aic23_clock_on();
- snd_omap_resume_mixer();
- }
-
- return 0;
-}
-
-/*
- * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
- */
-static int omap_aic23_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_aic23_suspend(card, PMSG_SUSPEND);
- }
- return 0;
-}
-
-static int omap_aic23_resume(struct platform_device *pdev)
-{
- snd_card_t *card = platform_get_drvdata(pdev);
-
- if (card->power_state != SNDRV_CTL_POWER_D0) {
- snd_omap_aic23_resume(card);
- }
- return 0;
-}
-
-#else
-#define snd_omap_aic23_suspend NULL
-#define snd_omap_aic23_resume NULL
-#define omap_aic23_suspend NULL
-#define omap_aic23_resume NULL
-
-#endif /* CONFIG_PM */
-
-/*
- */
-void snd_omap_aic23_free(snd_card_t * card)
-{
- struct snd_card_omap_aic23 *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_aic23_write(RESET_CONTROL_ADDR, 0);
- audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0xff);
-
- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
-}
-
-/*
- * Omap MCBSP clock configuration
- *
- * Here we have some functions that allows clock to be enabled and
- * disabled only when needed. Besides doing clock configuration
- * it allows turn on/turn off audio when necessary.
- */
-#define CODEC_CLOCK 12000000
-#define AUDIO_RATE_DEFAULT 44100
-
-/*
- * Do clock framework mclk search
- */
-static __init void omap_aic23_clock_setup(void)
-{
- aic23_mclk = clk_get(0, "mclk");
-}
-
-/*
- * Do some sanity check, set clock rate, starts it and
- * turn codec audio on
- */
-int omap_aic23_clock_on(void)
-{
- if (clk_get_usecount(aic23_mclk) > 0) {
- /* MCLK is already in use */
- printk(KERN_WARNING
- "MCLK in use at %d Hz. We change it to %d Hz\n",
- (uint) clk_get_rate(aic23_mclk),
- CODEC_CLOCK);
- }
-
- if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
- printk(KERN_ERR
- "Cannot set MCLK for AIC23 CODEC\n");
- return -ECANCELED;
- }
-
- clk_enable(aic23_mclk);
-
- printk(KERN_DEBUG
- "MCLK = %d [%d], usecount = %d\n",
- (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
- clk_get_usecount(aic23_mclk));
-
- /* Now turn the audio on */
- audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
- ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
- ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);
-
- return 0;
-}
-/*
- * Do some sanity check, turn clock off and then turn
- * codec audio off
- */
-int omap_aic23_clock_off(void)
-{
- if (clk_get_usecount(aic23_mclk) > 0) {
- if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
- printk(KERN_WARNING
- "MCLK for audio should be %d Hz. But is %d Hz\n",
- (uint) clk_get_rate(aic23_mclk),
- CODEC_CLOCK);
- }
-
- clk_disable(aic23_mclk);
- }
-
- audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
- DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
- ADC_OFF | MIC_OFF | LINE_OFF);
- return 0;
-}
-
-/* module init & exit */
-
-/*
- * Inits alsa soudcard structure
- */
-static int __init snd_omap_aic23_probe(struct platform_device *pdev)
-{
- int err = 0;
- snd_card_t *card;
- ADEBUG();
-
- /* gets clock from clock framework */
- omap_aic23_clock_setup();
-
- /* register the soundcard */
- card = snd_card_new(-1, id, THIS_MODULE, sizeof(omap_aic23));
- if (card == NULL)
- return -ENOMEM;
-
- omap_aic23 = kcalloc(1, sizeof(*omap_aic23), GFP_KERNEL);
- if (omap_aic23 == NULL)
- return -ENOMEM;
-
- card->private_data = (void *) omap_aic23;
- card->private_free = snd_omap_aic23_free;
-
- omap_aic23->card = card;
- omap_aic23->samplerate = AUDIO_RATE_DEFAULT;
-
- spin_lock_init(&omap_aic23->s[0].dma_lock);
- spin_lock_init(&omap_aic23->s[1].dma_lock);
-
- /* mixer */
- if ((err = snd_omap_mixer(omap_aic23)) < 0)
- goto nodev;
-
- /* PCM */
- if ((err = snd_card_omap_aic23_pcm(omap_aic23, 0)) < 0)
- goto nodev;
-
- strcpy(card->driver, "AIC23");
- strcpy(card->shortname, "OSK AIC23");
- sprintf(card->longname, "OMAP OSK with AIC23");
-
- snd_omap_init_mixer();
-
- snd_card_set_dev(card, &pdev->dev);
-
- if ((err = snd_card_register(card)) == 0) {
- printk(KERN_INFO "OSK audio support initialized\n");
- platform_set_drvdata(pdev, card);
- return 0;
- }
-
-nodev:
- snd_omap_aic23_free(card);
-
- return err;
-}
-
-static int snd_omap_aic23_remove(struct platform_device *pdev)
-{
- snd_card_t *card = platform_get_drvdata(pdev);
- struct snd_card_omap_aic23 *chip = card->private_data;
-
- snd_card_free(card);
-
- omap_aic23 = NULL;
- card->private_data = NULL;
- kfree(chip);
-
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-
-}
-
-static struct platform_driver omap_alsa_driver = {
- .probe = snd_omap_aic23_probe,
- .remove = snd_omap_aic23_remove,
- .suspend = omap_aic23_suspend,
- .resume = omap_aic23_resume,
- .driver = {
- .name = "omap_mcbsp",
- },
-};
-
-static int __init omap_aic23_init(void)
-{
- int err;
- ADEBUG();
-
- err = platform_driver_register(&omap_alsa_driver);
-
- return err;
-}
-
-static void __exit omap_aic23_exit(void)
-{
- ADEBUG();
-
- platform_driver_unregister(&omap_alsa_driver);
-}
-
-module_init(omap_aic23_init);
-module_exit(omap_aic23_exit);

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]