[alsa-devel] [PATCH] Add AC'97 driver for AT91SAM9263ek atmel board.

Sedji Gaouaou sedji.gaouaou at atmel.com
Wed Oct 1 18:24:12 CEST 2008


Add AC'97 driver for AT91SAM9263ek atmel board.
The driver includes the playback and the capture.

Signed-off-by: Sedji Gaouaou <sedji.gaouaou at atmel.com>
---
 sound/arm/Kconfig     |    9 +
 sound/arm/Makefile    |    4 +
 sound/arm/at91-ac97.c |  912 +++++++++++++++++++++++++++++++++++++++++++++++++
 sound/arm/at91-ac97.h |  295 ++++++++++++++++
 4 files changed, 1220 insertions(+), 0 deletions(-)
 create mode 100644 sound/arm/at91-ac97.c
 create mode 100644 sound/arm/at91-ac97.h

diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index f8e6de4..bfe12f7 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -50,5 +50,14 @@ config SND_PXA2XX_AC97
 	  Say Y or M if you want to support any AC97 codec attached to
 	  the PXA2xx AC97 interface.
 
+config SND_AT91_AC97
+	tristate "AC97 Controller driver for SAM926X familly from ATMEL"
+	depends on SND && ARCH_AT91
+	select SND_PCM
+	select SND_AC97_CODEC
+	help
+	  Say Y or M if you want to support any AC97 codec attached to
+	  the SAM926X AC97 Controller.
+
 endif	# SND_ARM
 
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index 2054de1..73fc74b 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -17,3 +17,7 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97)	+= pxa2xx-ac97-lib.o
 
 obj-$(CONFIG_SND_PXA2XX_AC97)	+= snd-pxa2xx-ac97.o
 snd-pxa2xx-ac97-objs		:= pxa2xx-ac97.o
+
+obj-$(CONFIG_SND_AT91_AC97)	+= snd-at91-ac97.o
+snd-at91-ac97-objs		:= at91-ac97.o
+
diff --git a/sound/arm/at91-ac97.c b/sound/arm/at91-ac97.c
new file mode 100644
index 0000000..3dcf742
--- /dev/null
+++ b/sound/arm/at91-ac97.c
@@ -0,0 +1,912 @@
+/*
+ * at91-ac97.c  --  AC'97 driver for atmel boards.
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2006 Atmel
+ *
+ * Author:	Patrice Vilchez <patrice.vilchez at atmel.com>
+ *		Sedji Gaouaou <sedji.gaouaou at atmel.com>
+ *		ATMEL CORP.
+ *
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/atmel_pdc.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/ac97_codec.h>
+#include <sound/soc.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+
+#include "at91-ac97.h"
+
+
+/*
+ * module parameters
+ */
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for AC97 controller");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for AC97 controller");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable AC97 controller");
+
+typedef struct at91_ac97 {
+	spinlock_t lock;
+	void *regs;
+	int period;
+	struct clk *ac97_clk;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	struct snd_ac97 *ac97;
+	struct snd_ac97_bus *ac97_bus;
+	int irq;
+	struct platform_device *pdev;
+	u8 reset_pin;
+} at91_ac97_t;
+
+
+/*
+ * PIO management functions
+ */
+void at91_ac97c_drive_reset(at91_ac97_t *chip, unsigned int value)
+{
+	at91_set_gpio_value(chip->reset_pin, value);
+}
+
+static const char driver_name[] = "at91-ac97";
+
+
+/*
+ * PCM part
+ */
+static struct snd_pcm_hardware snd_at91_ac97_playback_hw = {
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED
+				   | SNDRV_PCM_INFO_MMAP
+				   | SNDRV_PCM_INFO_MMAP_VALID
+				   | SNDRV_PCM_INFO_BLOCK_TRANSFER),
+	.formats		= (SNDRV_PCM_FMTBIT_S16_LE
+				   | SNDRV_PCM_FMTBIT_S16_BE),
+	.rates			= SNDRV_PCM_RATE_CONTINUOUS,
+	.rate_min		= 8000,
+	.rate_max		= 48000,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.buffer_bytes_max	= 256*1024,
+	.period_bytes_min	= 1024,
+	.period_bytes_max	= 4*1024,
+	.periods_min		= 1,
+	.periods_max		= 64,
+};
+
+static struct snd_pcm_hardware snd_at91_ac97_capture_hw = {
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED
+				   | SNDRV_PCM_INFO_MMAP
+				   | SNDRV_PCM_INFO_MMAP_VALID
+				   | SNDRV_PCM_INFO_BLOCK_TRANSFER),
+	.formats		= (SNDRV_PCM_FMTBIT_S16_LE
+				   | SNDRV_PCM_FMTBIT_S16_BE),
+	.rates			= SNDRV_PCM_RATE_CONTINUOUS,
+	.rate_min		= 8000,
+	.rate_max		= 48000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= 256*1024,
+	.period_bytes_min	= 1024,
+	.period_bytes_max	= 4*1024,
+	.periods_min		= 1,
+	.periods_max		= 64,
+};
+
+static int snd_at91_ac97_playback_open(struct snd_pcm_substream *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw = snd_at91_ac97_playback_hw;
+	chip->playback_substream = substream;
+	chip->period = 0;
+
+	pr_debug("%s : snd_at91_ac97_playback_open\n\r", driver_name);
+
+	return 0;
+}
+
+static int snd_at91_ac97_capture_open(struct snd_pcm_substream *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw = snd_at91_ac97_capture_hw;
+	chip->capture_substream = substream;
+	chip->period = 0;
+
+	pr_debug("%s : snd_at91_ac97_capture_open\n\r", driver_name);
+
+	return 0;
+}
+
+static int snd_at91_ac97_playback_close(struct snd_pcm_substream *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+
+	chip->playback_substream = NULL;
+
+	return 0;
+}
+
+static int snd_at91_ac97_capture_close(struct snd_pcm_substream *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+
+	chip->capture_substream = NULL;
+
+	return 0;
+}
+
+static int snd_at91_ac97_playback_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *hw_params)
+{
+	int err;
+
+	err = snd_pcm_lib_malloc_pages(substream,
+				       params_buffer_bytes(hw_params));
+
+	return err;
+}
+
+static int snd_at91_ac97_capture_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *hw_params)
+{
+	int err;
+
+	err = snd_pcm_lib_malloc_pages(substream,
+				       params_buffer_bytes(hw_params));
+
+	return err;
+}
+
+static int snd_at91_ac97_playback_hw_free(struct snd_pcm_substream *substream)
+{
+
+	snd_pcm_lib_free_pages(substream);
+
+	return 0;
+}
+
+static int snd_at91_ac97_capture_hw_free(struct snd_pcm_substream *substream)
+{
+
+	snd_pcm_lib_free_pages(substream);
+
+	return 0;
+}
+
+static int snd_at91_ac97_playback_prepare(struct snd_pcm_substream *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int block_size = frames_to_bytes(runtime, runtime->period_size);
+	unsigned long word = 0;
+
+	pr_debug("%s : block_size = %d\n\r", driver_name, block_size);
+
+	/* Assign slots to channels */
+	switch (substream->runtime->channels) {
+	/* TODO: Support more than two channels */
+	case 1:
+		word |= AT91C_AC97C_CHID3_CA;
+		break;
+	case 2:
+	default:
+		/* Assign Left and Right slots (3,4) to Channel A */
+		word |= AT91C_AC97C_CHID3_CA | AT91C_AC97C_CHID4_CA;
+		break;
+	}
+
+	ac97c_writel(chip, OCA, word);
+
+	/*
+	 * Configure sample format and size..
+	 */
+	word = AT91C_AC97C_PDCEN | AT91C_AC97C_SIZE_16_BITS;
+
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_BE:
+		word |= AT91C_AC97C_CEM;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+	default:
+		break;
+	}
+
+	ac97c_writel(chip, CAMR, word);
+
+	/* Set variable rate if needed */
+	if (runtime->rate != 48000) {
+		word = ac97c_readl(chip, MR);
+		word |= AT91C_AC97C_VRA;
+		ac97c_writel(chip, MR, word);
+	} else {
+		/* Clear Variable Rate Bit */
+		word = ac97c_readl(chip, MR);
+		word &= ~AT91C_AC97C_VRA;
+		ac97c_writel(chip, MR, word);
+	}
+
+	/* Set rate */
+	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
+
+	pr_debug("%s : dma_addr = %x\n\r : dma_area = %x\n\r"
+			" : dma_bytes = %d\n\r",
+			driver_name, runtime->dma_addr,
+			runtime->dma_area, runtime->dma_bytes);
+
+	/* Initialize and start the PDC */
+	writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
+	writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_TNPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
+
+	/* Enable Channel A interrupts */
+	ac97c_writel(chip, IER, AT91C_AC97C_CAEVT);
+
+	pr_debug("%s : snd_at91_ac97_playback_prepare\n\r", driver_name);
+
+	return 0;
+}
+
+static int snd_at91_ac97_capture_prepare(struct snd_pcm_substream *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int block_size = frames_to_bytes(runtime, runtime->period_size);
+	unsigned long word = 0;
+
+	pr_debug("%s : block_size = %d\n\r", driver_name, block_size);
+
+
+	/* Assign slots to channels */
+	switch (substream->runtime->channels) {
+	/* TODO: Support more than two channels */
+	case 1:
+		word |= AT91C_AC97C_CHID3_CA;
+		break;
+	case 2:
+	default:
+		/* Assign Left and Right slots (3,4) to Channel A */
+		word |= AT91C_AC97C_CHID3_CA | AT91C_AC97C_CHID4_CA;
+		break;
+	}
+
+	ac97c_writel(chip, ICA, word);
+
+	/*
+	 * Configure sample format and size.
+	 */
+	word = AT91C_AC97C_PDCEN | AT91C_AC97C_SIZE_16_BITS;
+
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_BE:
+		word |= AT91C_AC97C_CEM;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	}
+
+	ac97c_writel(chip, CAMR, word);
+
+	/* Set variable rate if needed */
+	if (runtime->rate != 48000) {
+		word = ac97c_readl(chip, MR);
+		word |= AT91C_AC97C_VRA;
+		ac97c_writel(chip, MR, word);
+	} else {
+		/* Clear Variable Rate Bit */
+		word = ac97c_readl(chip, MR);
+		word &= ~AT91C_AC97C_VRA;
+		ac97c_writel(chip, MR, word);
+	}
+
+	/* Set rate */
+	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
+
+	pr_debug("%s : dma_addr = %x\n\r : dma_area = %x\n\r"
+			" : dma_bytes = %d\n\r",
+			driver_name, runtime->dma_addr,
+			runtime->dma_area, runtime->dma_bytes);
+
+	/* Initialize and start the PDC */
+	writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
+	writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_RNPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
+
+	/* Enable Channel A interrupts */
+	ac97c_writel(chip, IER, AT91C_AC97C_CAEVT);
+
+	pr_debug("%s : snd_at91_ac97_capture_prepare\n\r", driver_name);
+
+	return 0;
+}
+
+static int snd_at91_ac97_playback_trigger(struct snd_pcm_substream *substream,
+						int cmd)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long camr, ptcr = 0, flags;
+	int err = 0;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	camr = ac97c_readl(chip, CAMR);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		camr |= (AT91C_AC97C_CEN | AT91C_AC97C_ENDTX);
+		ptcr = ATMEL_PDC_TXTEN;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		camr &= ~(AT91C_AC97C_CEN | AT91C_AC97C_ENDTX);
+		ptcr = ATMEL_PDC_TXTDIS;
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	ac97c_writel(chip, CAMR, camr);
+
+	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	pr_debug("%s : snd_at91_ac97_playback_trigger\n\r", driver_name);
+
+	return err;
+}
+
+static int snd_at91_ac97_capture_trigger(struct snd_pcm_substream *substream,
+						int cmd)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long camr, ptcr = 0, flags;
+	int err = 0;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	camr = ac97c_readl(chip, CAMR);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		camr |= (AT91C_AC97C_CEN |
+				AT91C_AC97C_ENDRX |
+				AT91C_AC97C_OVRUN);
+		ptcr = ATMEL_PDC_RXTEN;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		camr &= ~(AT91C_AC97C_CEN |
+				AT91C_AC97C_ENDRX |
+				AT91C_AC97C_OVRUN);
+		ptcr = ATMEL_PDC_RXTDIS;
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	ac97c_writel(chip, CAMR, camr);
+
+	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	pr_debug("%s : snd_at91_ac97_capture_trigger\n\r", driver_name);
+
+	return err;
+}
+
+static snd_pcm_uframes_t
+snd_at91_ac97_playback_pointer(struct snd_pcm_substream *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_uframes_t pos;
+	unsigned long bytes;
+
+	bytes = readl(chip->regs + ATMEL_PDC_TPR) - runtime->dma_addr;
+
+	pos = bytes_to_frames(runtime, bytes);
+
+	if (pos >= runtime->buffer_size)
+		pos -= runtime->buffer_size;
+
+	pr_debug("%s : snd_at91_ac97_playback_pointer\n\r", driver_name);
+
+	return pos;
+}
+
+static  snd_pcm_uframes_t
+snd_at91_ac97_capture_pointer(struct snd_pcm_substream *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_uframes_t pos;
+	unsigned long bytes;
+
+	bytes = readl(chip->regs + ATMEL_PDC_RPR) - runtime->dma_addr;
+	pos = bytes_to_frames(runtime, bytes);
+	if (pos >= runtime->buffer_size)
+		pos -= runtime->buffer_size;
+
+	pr_debug("%s : snd_at91_ac97_capture_pointer\n\r", driver_name);
+
+	return pos;
+}
+
+static struct snd_pcm_ops at91_ac97_playback_ops = {
+	.open		= snd_at91_ac97_playback_open,
+	.close		= snd_at91_ac97_playback_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_at91_ac97_playback_hw_params,
+	.hw_free	= snd_at91_ac97_playback_hw_free,
+	.prepare	= snd_at91_ac97_playback_prepare,
+	.trigger	= snd_at91_ac97_playback_trigger,
+	.pointer	= snd_at91_ac97_playback_pointer,
+};
+
+static struct snd_pcm_ops at91_ac97_capture_ops = {
+	.open		= snd_at91_ac97_capture_open,
+	.close		= snd_at91_ac97_capture_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_at91_ac97_capture_hw_params,
+	.hw_free	= snd_at91_ac97_capture_hw_free,
+	.prepare	= snd_at91_ac97_capture_prepare,
+	.trigger	= snd_at91_ac97_capture_trigger,
+	.pointer	= snd_at91_ac97_capture_pointer,
+};
+
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = {
+	/* Playback */
+	{
+		.exclusive = 1,
+		.r = { {
+			.slots = ((1 << AC97_SLOT_PCM_LEFT)
+				  | (1 << AC97_SLOT_PCM_RIGHT)),
+		} },
+	},
+	/* PCM in */
+	{
+		.stream = 1,
+		.exclusive = 1,
+		.r = { {
+			.slots = ((1 << AC97_SLOT_PCM_LEFT)
+					| (1 << AC97_SLOT_PCM_RIGHT)),
+		} }
+	},
+	/* Mic in */
+	{
+		.stream = 1,
+		.exclusive = 1,
+		.r = { {
+			.slots = (1<<AC97_SLOT_MIC),
+		} }
+	},
+};
+
+static int __devinit snd_at91_ac97_pcm_new(at91_ac97_t *chip)
+{
+	struct snd_pcm *pcm;
+	int err;
+
+	err = snd_ac97_pcm_assign(chip->ac97_bus,
+					ARRAY_SIZE(at91_ac97_pcm_defs),
+					at91_ac97_pcm_defs);
+	if (err)
+		return err;
+
+	err = snd_pcm_new(chip->card, "Atmel AC97", 0, 1, 1, &pcm);
+	if (err)
+		return err;
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      &chip->pdev->dev,
+					      128 * 1024, 256 * 1024);
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+					&at91_ac97_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &at91_ac97_capture_ops);
+
+	pcm->private_data = chip;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "Atmel AC97");
+	chip->pcm = pcm;
+
+	return 0;
+}
+
+
+/*
+ * Mixer part
+ */
+static int snd_at91_ac97_mixer_new(at91_ac97_t *chip)
+{
+	int err;
+	struct snd_ac97_template template;
+
+	memset(&template, 0, sizeof(template));
+	template.private_data = chip;
+	template.num = 0;
+	template.addr = 0;
+	err = snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
+
+	return err;
+}
+
+static irqreturn_t snd_at91_ac97_interrupt(int irq, void *dev_id)
+{
+	at91_ac97_t *chip = dev_id;
+	unsigned long status;
+	unsigned long dummy;
+
+	status = ac97c_readl(chip, SR);
+
+	if (status & AT91C_AC97C_CAEVT) {
+		struct snd_pcm_runtime *runtime;
+		int offset, next_period, block_size;
+		unsigned long casr, camr, test;
+
+		casr = ac97c_readl(chip, CASR);
+		camr = ac97c_readl(chip, CAMR);
+		test = casr & camr;
+
+		if ((casr & camr) & AT91C_AC97C_ENDTX) {
+			runtime = chip->playback_substream->runtime;
+			block_size = frames_to_bytes(runtime,
+							runtime->period_size);
+			chip->period++;
+
+			if (chip->period == runtime->periods)
+				chip->period = 0;
+			next_period = chip->period + 1;
+			if (next_period == runtime->periods)
+				next_period = 0;
+
+			offset = block_size * next_period;
+
+			writel(runtime->dma_addr + offset,
+						chip->regs + ATMEL_PDC_TNPR);
+			writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
+
+			snd_pcm_period_elapsed(chip->playback_substream);
+		}
+		if ((casr & camr) & AT91C_AC97C_ENDRX) {
+			runtime = chip->capture_substream->runtime;
+			block_size = frames_to_bytes(runtime,
+							runtime->period_size);
+			chip->period++;
+
+			if (chip->period == runtime->periods)
+				chip->period = 0;
+			next_period = chip->period + 1;
+			if (next_period == runtime->periods)
+				next_period = 0;
+
+			offset = block_size * next_period;
+
+			writel(runtime->dma_addr + offset,
+						chip->regs + ATMEL_PDC_RNPR);
+			writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
+			snd_pcm_period_elapsed(chip->capture_substream);
+		}
+		if ((casr & camr) & AT91C_AC97C_OVRUN)
+			printk(KERN_INFO " AC97_irq - overrun!\n");
+	} else {
+		printk(KERN_WARNING
+		       "Spurious AC97 interrupt, status = 0x%08lx\n",
+		       status);
+	}
+
+	dummy = ac97c_readl(chip, SR);
+
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * CODEC part
+ */
+static void snd_at91_ac97_hard_reset(at91_ac97_t *chip)
+{
+       /* Enable AC97 Controller.*/
+       /* Perform a cold (hard) reset of the AC97 codec.*/
+       ac97c_writel(chip, MR, 0);
+       ac97c_writel(chip, MR, AT91C_AC97C_ENA);
+
+       at91_ac97c_drive_reset(chip, 0);
+       udelay(1);
+       at91_ac97c_drive_reset(chip, 1);
+       udelay(1);
+}
+
+static void snd_at91_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+				 unsigned short val)
+{
+	at91_ac97_t *chip = ac97->private_data;
+	unsigned long word;
+	int timeout = 0x100;
+
+	pr_debug("%s : Writing codec register 0x%x = 0x%x\n\r",
+						driver_name, reg, val);
+
+	word = (reg & 0x7f) << 16 | val;
+
+	do {
+		if (ac97c_readl(chip, COSR) & AT91C_AC97C_TXRDY) {
+			ac97c_writel(chip, COTHR, word);
+			return;
+		}
+		udelay(1);
+	} while (--timeout);
+
+	snd_printk(KERN_WARNING "at91-ac97: codec write timeout\n\r");
+}
+
+static unsigned short snd_at91_ac97_read(struct snd_ac97 *ac97,
+					  unsigned short reg)
+{
+	at91_ac97_t *chip = ac97->private_data;
+	unsigned long word;
+	int timeout = 40;
+
+	word = (0x80 | (reg & 0x7f)) << 16;
+
+	do {
+		if (ac97c_readl(chip, COSR) & AT91C_AC97C_TXRDY) {
+			ac97c_writel(chip, COTHR, word);
+			break;
+		}
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		goto timed_out;
+
+	timeout = 0x100;
+
+	do {
+		if (ac97c_readl(chip, COSR) & AT91C_AC97C_RXRDY) {
+			unsigned short val =
+				(unsigned short) ac97c_readl(chip, CORHR);
+			return val;
+		}
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		goto timed_out;
+
+timed_out:
+	snd_printk(KERN_WARNING "at91-ac97: codec write timeout\n\r");
+	return 0xffff;
+}
+
+static void snd_at91_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	at91_ac97_t *chip = ac97->private_data;
+	unsigned int mr = ac97c_readl(chip, MR);
+
+	mr |= AT91C_AC97C_WRST;
+
+	ac97c_writel(chip, MR, mr);
+	udelay(1);
+
+	mr &= ~AT91C_AC97C_WRST;
+	ac97c_writel(chip, MR, mr);
+}
+
+static void snd_at91_ac97_destroy(struct snd_card *card)
+{
+	at91_ac97_t *chip = get_chip(card);
+
+	if (chip->irq != -1)
+		free_irq(chip->irq, chip);
+
+	if (chip->regs)
+		iounmap(chip->regs);
+}
+
+static int __devinit snd_at91_ac97_create(struct snd_card *card,
+					   struct platform_device *pdev)
+{
+	static struct snd_ac97_bus_ops ops = {
+		.write	= snd_at91_ac97_write,
+		.read	= snd_at91_ac97_read,
+		.reset  = snd_at91_ac97_warm_reset,
+	};
+
+	at91_ac97_t *chip = get_chip(card);
+	int irq, err = 0;
+
+
+
+	card->private_free = snd_at91_ac97_destroy;
+
+	spin_lock_init(&chip->lock);
+	chip->card = card;
+	chip->pdev = pdev;
+	chip->irq = -1;
+
+	if (!(platform_resource_flags(pdev, 0) & IORESOURCE_MEM)
+	    || !(platform_resource_flags(pdev, 1) & IORESOURCE_IRQ))
+		return -ENODEV;
+
+	irq = platform_resource_start(pdev, 1);
+
+	err = request_irq(irq, snd_at91_ac97_interrupt, 0, "ac97", chip);
+	if (err) {
+		snd_printk(KERN_WARNING "unable to request IRQ%d\n", irq);
+		return err;
+	}
+
+	chip->irq = irq;
+	snd_printk(KERN_INFO "AC97C regs = %08X \n",
+					platform_resource_start(pdev, 0));
+	snd_printk(KERN_INFO "AC97C irq  = %d \n", irq);
+
+	chip->regs = ioremap(platform_resource_start(pdev, 0),
+			     platform_resource_len(pdev, 0));
+	if (!chip->regs) {
+		snd_printk(KERN_WARNING "unable to remap AC97C io memory\n");
+		return -ENOMEM;
+	}
+
+	snd_card_set_dev(card, &pdev->dev);
+
+	err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
+
+	return err;
+}
+
+static int __devinit snd_at91_ac97_probe(struct platform_device *pdev)
+{
+	static int dev;
+	struct atmel_ac97_data *pdata = pdev->dev.platform_data;
+	struct snd_card *card;
+	at91_ac97_t *chip;
+	int err;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE,
+			    sizeof(at91_ac97_t));
+	if (!card)
+		return -ENOMEM;
+	chip = get_chip(card);
+
+	err = snd_at91_ac97_create(card, pdev);
+	if (err)
+		goto out_free_card;
+
+	/* Enable AC97 Controller clock*/
+	chip->reset_pin = pdata->reset_pin;
+	chip->ac97_clk = clk_get(NULL, "ac97_clk");
+	if (!chip->ac97_clk)
+		goto out_free_card;
+
+	clk_enable(chip->ac97_clk);
+
+	/* Perform a codec hard reset.*/
+	/* This also enables the AC97 Controller.*/
+	snd_at91_ac97_hard_reset(chip);
+
+	err = snd_at91_ac97_mixer_new(chip);
+	if (err)
+		goto out_free_card;
+
+	err = snd_at91_ac97_pcm_new(chip);
+	if (err)
+		goto out_free_card;
+
+	strcpy(card->driver, "ac97c");
+	strcpy(card->shortname, "Atmel AC97");
+	sprintf(card->longname, "Atmel AC97 Controller at %#lx, irq %i",
+		(unsigned long) platform_resource_start(pdev, 0),
+		(int) chip->irq);
+
+	err = snd_card_register(card);
+	if (err)
+		goto out_free_card;
+
+	dev_set_drvdata(&pdev->dev, card);
+	dev++;
+	return 0;
+
+out_free_card:
+	snd_card_free(card);
+	return err;
+}
+
+static int __devexit snd_at91_ac97_remove(struct  platform_device *pdev)
+{
+	struct snd_card *card = dev_get_drvdata(&pdev->dev);
+	at91_ac97_t *chip = get_chip(card);
+
+
+	snd_card_free(card);
+
+	/* Disable AC97 Controller*/
+	ac97c_writel(chip, MR, 0);
+
+	/* Disable AC97 Controller clock*/
+	clk_disable(chip->ac97_clk);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver at91_ac97_driver = {
+	.probe      = snd_at91_ac97_probe,
+	.remove     = __devexit_p(snd_at91_ac97_remove),
+	.driver     =
+	{
+		.name       = "ac97c",
+	}
+	,
+};
+
+static int __init at91_ac97_init(void)
+{
+	return platform_driver_register(&at91_ac97_driver);
+}
+
+static void __exit at91_ac97_exit(void)
+{
+	platform_driver_unregister(&at91_ac97_driver);
+}
+
+module_init(at91_ac97_init);
+module_exit(at91_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for Atmel AC97 Controller");
+MODULE_AUTHOR("Atmel");
+
diff --git a/sound/arm/at91-ac97.h b/sound/arm/at91-ac97.h
new file mode 100644
index 0000000..e945f5d
--- /dev/null
+++ b/sound/arm/at91-ac97.h
@@ -0,0 +1,295 @@
+/*
+ * at91-ac97.h  --  Hardware definition for the ac97c peripheral
+ * 			in the ATMEL at91sam926x processor
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2006 Atmel
+ *
+ * Author:	Patrice Vilchez <patrice.vilchez at atmel.com>
+ *		ATMEL CORP.
+ *
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __AC97C_H
+#define __AC97C_H
+
+/* -------------------------------------------------------- */
+/* AC97C ID definitions for  AT91SAM926x           */
+/* -------------------------------------------------------- */
+#ifndef AT91C_ID_AC97C
+#define AT91C_ID_AC97C 	18 /**< AC97 Controller id */
+#endif /* AT91C_ID_AC97C */
+
+/* -------------------------------------------------------- */
+/* AC97C Base Address definitions for  AT91SAM926x   */
+/* -------------------------------------------------------- */
+#define AT91C_BASE_AC97C     	0xFFFA0000 /**< AC97C base address */
+
+/* -------------------------------------------------------- */
+/* PIO definition for AC97C hardware peripheral */
+/* -------------------------------------------------------- */
+#define AT91C_PB1_AC97CK   	(1 << 1) /**<  */
+#define AT91C_PB0_AC97FS   	(1 << 0) /**<  */
+#define AT91C_PB3_AC97RX   	(1 << 3) /**<  */
+#define AT91C_PB2_AC97TX   	(1 << 2) /**<  */
+
+/* -------------------------------------------------------- */
+/* Register offset definition for AC97C hardware peripheral */
+/* -------------------------------------------------------- */
+#define AC97C_MR 	(0x0008) 	/**< Mode Register */
+#define AC97C_ICA 	(0x0010) 	/**< Input Channel AssignementRegister */
+#define AC97C_OCA 	(0x0014) 	/**< Output Channel Assignement Register */
+#define AC97C_CARHR 	(0x0020) 	/**< Channel A Receive Holding Register */
+#define AC97C_CATHR 	(0x0024) 	/**< Channel A Transmit Holding Register */
+#define AC97C_CASR 	(0x0028) 	/**< Channel A Status Register */
+#define AC97C_CAMR 	(0x002C) 	/**< Channel A Mode Register */
+#define AC97C_CBRHR 	(0x0030) 	/**< Channel B Receive Holding Register (optional) */
+#define AC97C_CBTHR 	(0x0034) 	/**< Channel B Transmit Holding Register (optional) */
+#define AC97C_CBSR 	(0x0038) 	/**< Channel B Status Register */
+#define AC97C_CBMR 	(0x003C) 	/**< Channel B Mode Register */
+#define AC97C_CORHR 	(0x0040) 	/**< COdec Transmit Holding Register */
+#define AC97C_COTHR 	(0x0044) 	/**< COdec Transmit Holding Register */
+#define AC97C_COSR 	(0x0048) 	/**< CODEC Status Register */
+#define AC97C_COMR 	(0x004C) 	/**< CODEC Mask Status Register */
+#define AC97C_SR 	(0x0050) 	/**< Status Register */
+#define AC97C_IER 	(0x0054) 	/**< Interrupt Enable Register */
+#define AC97C_IDR 	(0x0058) 	/**< Interrupt Disable Register */
+#define AC97C_IMR 	(0x005C) 	/**< Interrupt Mask Register */
+#define AC97C_VERSION 	(0x00FC) 	/**< Version Register */
+
+/* -------------------------------------------------------- */
+/* Bitfields definition for AC97C hardware peripheral */
+/* -------------------------------------------------------- */
+/* --- Register AC97C_MR */
+#define AT91C_AC97C_ENA	(0x1 << 0) /**< (AC97C) AC97 Controller Global Enable */
+#define AT91C_AC97C_WRST	(0x1 << 1) /**< (AC97C) Warm Reset */
+#define AT91C_AC97C_VRA	(0x1 << 2) /**< (AC97C) Variable RAte (for Data Slots) */
+/* --- Register AC97C_ICA */
+#define AT91C_AC97C_CHID3	(0x7 << 0) /**< (AC97C) Channel Id for the input slot 3 */
+#define 	AT91C_AC97C_CHID3_NONE                 0x0 /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CA                   0x1 /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CB                   0x2 /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CC                   0x3 /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID4     (0x7 << 3) /**< (AC97C) Channel Id for the input slot 4 */
+#define 	AT91C_AC97C_CHID4_NONE                 (0x0 <<  3) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CA                   (0x1 <<  3) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CB                   (0x2 <<  3) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CC                   (0x3 <<  3) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID5     (0x7 << 6) /**< (AC97C) Channel Id for the input slot 5 */
+#define 	AT91C_AC97C_CHID5_NONE                 (0x0 <<  6) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CA                   (0x1 <<  6) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CB                   (0x2 <<  6) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CC                   (0x3 <<  6) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID6     (0x7 << 9) /**< (AC97C) Channel Id for the input slot 6 */
+#define 	AT91C_AC97C_CHID6_NONE                 (0x0 <<  9) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CA                   (0x1 <<  9) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CB                   (0x2 <<  9) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CC                   (0x3 <<  9) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID7     (0x7 << 12) /**< (AC97C) Channel Id for the input slot 7 */
+#define 	AT91C_AC97C_CHID7_NONE                 (0x0 << 12) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CA                   (0x1 << 12) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CB                   (0x2 << 12) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CC                   (0x3 << 12) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID8     (0x7 << 15) /**< (AC97C) Channel Id for the input slot 8 */
+#define 	AT91C_AC97C_CHID8_NONE                 (0x0 << 15) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CA                   (0x1 << 15) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CB                   (0x2 << 15) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CC                   (0x3 << 15) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID9     (0x7 << 18) /**< (AC97C) Channel Id for the input slot 9 */
+#define 	AT91C_AC97C_CHID9_NONE                 (0x0 << 18) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CA                   (0x1 << 18) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CB                   (0x2 << 18) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CC                   (0x3 << 18) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID10    (0x7 << 21) /**< (AC97C) Channel Id for the input slot 10 */
+#define 	AT91C_AC97C_CHID10_NONE                 (0x0 << 21) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CA                   (0x1 << 21) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CB                   (0x2 << 21) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CC                   (0x3 << 21) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID11    (0x7 << 24) /**< (AC97C) Channel Id for the input slot 11 */
+#define 	AT91C_AC97C_CHID11_NONE                 (0x0 << 24) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CA                   (0x1 << 24) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CB                   (0x2 << 24) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CC                   (0x3 << 24) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID12    (0x7 << 27) /**< (AC97C) Channel Id for the input slot 12 */
+#define 	AT91C_AC97C_CHID12_NONE                 (0x0 << 27) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CA                   (0x1 << 27) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CB                   (0x2 << 27) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CC                   (0x3 << 27) /**< (AC97C) Channel C data will be transmitted during this slot */
+/* --- Register AC97C_OCA */
+#define AT91C_AC97C_CHID3     (0x7 << 0) /**< (AC97C) Channel Id for the input slot 3 */
+#define 	AT91C_AC97C_CHID3_NONE                 0x0 /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CA                   0x1 /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CB                   0x2 /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CC                   0x3 /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID4     (0x7 << 3) /**< (AC97C) Channel Id for the input slot 4 */
+#define 	AT91C_AC97C_CHID4_NONE                 (0x0 <<  3) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CA                   (0x1 <<  3) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CB                   (0x2 <<  3) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CC                   (0x3 <<  3) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID5     (0x7 << 6) /**< (AC97C) Channel Id for the input slot 5 */
+#define 	AT91C_AC97C_CHID5_NONE                 (0x0 <<  6) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CA                   (0x1 <<  6) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CB                   (0x2 <<  6) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CC                   (0x3 <<  6) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID6     (0x7 << 9) /**< (AC97C) Channel Id for the input slot 6 */
+#define 	AT91C_AC97C_CHID6_NONE                 (0x0 <<  9) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CA                   (0x1 <<  9) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CB                   (0x2 <<  9) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CC                   (0x3 <<  9) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID7     (0x7 << 12) /**< (AC97C) Channel Id for the input slot 7 */
+#define 	AT91C_AC97C_CHID7_NONE                 (0x0 << 12) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CA                   (0x1 << 12) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CB                   (0x2 << 12) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CC                   (0x3 << 12) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID8     (0x7 << 15) /**< (AC97C) Channel Id for the input slot 8 */
+#define 	AT91C_AC97C_CHID8_NONE                 (0x0 << 15) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CA                   (0x1 << 15) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CB                   (0x2 << 15) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CC                   (0x3 << 15) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID9     (0x7 << 18) /**< (AC97C) Channel Id for the input slot 9 */
+#define 	AT91C_AC97C_CHID9_NONE                 (0x0 << 18) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CA                   (0x1 << 18) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CB                   (0x2 << 18) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CC                   (0x3 << 18) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID10    (0x7 << 21) /**< (AC97C) Channel Id for the input slot 10 */
+#define 	AT91C_AC97C_CHID10_NONE                 (0x0 << 21) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CA                   (0x1 << 21) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CB                   (0x2 << 21) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CC                   (0x3 << 21) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID11    (0x7 << 24) /**< (AC97C) Channel Id for the input slot 11 */
+#define 	AT91C_AC97C_CHID11_NONE                 (0x0 << 24) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CA                   (0x1 << 24) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CB                   (0x2 << 24) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CC                   (0x3 << 24) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID12    (0x7 << 27) /**< (AC97C) Channel Id for the input slot 12 */
+#define 	AT91C_AC97C_CHID12_NONE                 (0x0 << 27) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CA                   (0x1 << 27) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CB                   (0x2 << 27) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CC                   (0x3 << 27) /**< (AC97C) Channel C data will be transmitted during this slot */
+/* --- Register AC97C_CARHR */
+#define AT91C_AC97C_RDATA     (0xFFFFF << 0) /**< (AC97C) Receive data */
+/* --- Register AC97C_CATHR */
+#define AT91C_AC97C_TDATA     (0xFFFFF << 0) /**< (AC97C) Transmit data */
+/* --- Register AC97C_CASR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4) /**< (AC97C)  */
+#define AT91C_AC97C_OVRUN     (0x1 << 5) /**< (AC97C)  */
+#define AT91C_AC97C_ENDTX     (0x1 << 10) /**< (AC97C)  */
+#define AT91C_AC97C_TXBUFE    (0x1 << 11) /**< (AC97C)  */
+#define AT91C_AC97C_ENDRX     (0x1 << 14) /**< (AC97C)  */
+#define AT91C_AC97C_RXBUFF    (0x1 << 15) /**< (AC97C)  */
+/* --- Register AC97C_CAMR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4) /**< (AC97C)  */
+#define AT91C_AC97C_OVRUN     (0x1 << 5) /**< (AC97C)  */
+#define AT91C_AC97C_ENDTX     (0x1 << 10) /**< (AC97C)  */
+#define AT91C_AC97C_TXBUFE    (0x1 << 11) /**< (AC97C)  */
+#define AT91C_AC97C_ENDRX     (0x1 << 14) /**< (AC97C)  */
+#define AT91C_AC97C_RXBUFF    (0x1 << 15) /**< (AC97C)  */
+#define AT91C_AC97C_SIZE      (0x3 << 16) /**< (AC97C)  */
+#define 	AT91C_AC97C_SIZE_20_BITS              (0x0 << 16) /**< (AC97C) Data size is 20 bits */
+#define 	AT91C_AC97C_SIZE_18_BITS              (0x1 << 16) /**< (AC97C) Data size is 18 bits */
+#define 	AT91C_AC97C_SIZE_16_BITS              (0x2 << 16) /**< (AC97C) Data size is 16 bits */
+#define 	AT91C_AC97C_SIZE_10_BITS              (0x3 << 16) /**< (AC97C) Data size is 10 bits */
+#define AT91C_AC97C_CEM       (0x1 << 18) /**< (AC97C)  */
+#define AT91C_AC97C_CEN       (0x1 << 21) /**< (AC97C)  */
+#define AT91C_AC97C_PDCEN     (0x1 << 22) /**< (AC97C)  */
+/* --- Register AC97C_CBRHR */
+#define AT91C_AC97C_RDATA     (0xFFFFF << 0) /**< (AC97C) Receive data */
+/* --- Register AC97C_CBTHR */
+#define AT91C_AC97C_TDATA     (0xFFFFF << 0) /**< (AC97C) Transmit data */
+/* --- Register AC97C_CBSR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4) /**< (AC97C)  */
+#define AT91C_AC97C_OVRUN     (0x1 << 5) /**< (AC97C)  */
+/* --- Register AC97C_CBMR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4) /**< (AC97C)  */
+#define AT91C_AC97C_OVRUN     (0x1 << 5) /**< (AC97C)  */
+#define AT91C_AC97C_SIZE      (0x3 << 16) /**< (AC97C)  */
+#define 	AT91C_AC97C_SIZE_20_BITS              (0x0 << 16) /**< (AC97C) Data size is 20 bits */
+#define 	AT91C_AC97C_SIZE_18_BITS              (0x1 << 16) /**< (AC97C) Data size is 18 bits */
+#define 	AT91C_AC97C_SIZE_16_BITS              (0x2 << 16) /**< (AC97C) Data size is 16 bits */
+#define 	AT91C_AC97C_SIZE_10_BITS              (0x3 << 16) /**< (AC97C) Data size is 10 bits */
+#define AT91C_AC97C_CEM       (0x1 << 18) /**< (AC97C)  */
+#define AT91C_AC97C_CEN       (0x1 << 21) /**< (AC97C)  */
+/* --- Register AC97C_CORHR */
+#define AT91C_AC97C_SDATA     (0xFFFF << 0) /**< (AC97C) Status Data */
+/* --- Register AC97C_COTHR */
+#define AT91C_AC97C_CDATA     (0xFFFF << 0) /**< (AC97C) Command Data */
+#define AT91C_AC97C_CADDR     (0x7F << 16) /**< (AC97C) COdec control register index */
+#define AT91C_AC97C_READ      (0x1 << 23) /**< (AC97C) Read/Write command */
+/* --- Register AC97C_COSR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4) /**< (AC97C)  */
+/* --- Register AC97C_COMR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4) /**< (AC97C)  */
+/* --- Register AC97C_SR */
+#define AT91C_AC97C_SOF       (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_WKUP      (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_COEVT     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_CAEVT     (0x1 << 3) /**< (AC97C)  */
+#define AT91C_AC97C_CBEVT     (0x1 << 4) /**< (AC97C)  */
+/* --- Register AC97C_IER */
+#define AT91C_AC97C_SOF       (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_WKUP      (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_COEVT     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_CAEVT     (0x1 << 3) /**< (AC97C)  */
+#define AT91C_AC97C_CBEVT     (0x1 << 4) /**< (AC97C)  */
+/* --- Register AC97C_IDR */
+#define AT91C_AC97C_SOF       (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_WKUP      (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_COEVT     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_CAEVT     (0x1 << 3) /**< (AC97C)  */
+#define AT91C_AC97C_CBEVT     (0x1 << 4) /**< (AC97C)  */
+/* --- Register AC97C_IMR */
+#define AT91C_AC97C_SOF       (0x1 << 0) /**< (AC97C)  */
+#define AT91C_AC97C_WKUP      (0x1 << 1) /**< (AC97C)  */
+#define AT91C_AC97C_COEVT     (0x1 << 2) /**< (AC97C)  */
+#define AT91C_AC97C_CAEVT     (0x1 << 3) /**< (AC97C)  */
+#define AT91C_AC97C_CBEVT     (0x1 << 4) /**< (AC97C)  */
+
+#define platform_num_resources(dev)     ((dev)->num_resources)
+#define platform_resource_start(dev, i) ((dev)->resource[(i)].start)
+#define platform_resource_end(dev, i)   ((dev)->resource[(i)].end)
+#define platform_resource_flags(dev, i) ((dev)->resource[(i)].flags)
+#define platform_resource_len(dev, i)			\
+	(platform_resource_end((dev), (i)) -		\
+	platform_resource_start((dev), (i)) + 1)
+
+#define get_chip(card) ((at91_ac97_t *)(card)->private_data)
+
+#define ac97c_writel(chip, reg, val)			\
+	writel((val), (chip)->regs + AC97C_##reg)
+
+#define ac97c_readl(chip, reg)				\
+	readl((chip)->regs + AC97C_##reg)
+
+#endif /* __AC97C_H */
-- 
1.5.3.7






More information about the Alsa-devel mailing list