<div>Dear sirs,</div>
<div> </div>
<div>Submit wrong patch file, drop it.</div>
<div>I will resubmit it.<br><br></div>
<div class="gmail_quote">2010/5/18 Wan ZongShun <span dir="ltr"><<a href="http://mcuos.com">mcuos.com</a>@<a href="http://gmail.com">gmail.com</a>></span><br>
<blockquote style="BORDER-LEFT: #ccc 1px solid; MARGIN: 0px 0px 0px 0.8ex; PADDING-LEFT: 1ex" class="gmail_quote">Dear Mark,<br><br>I have modified some codes according to your comments,<br>now I submit the patch as v2 again.<br>
<br>Thanks a lot for your help.<br><br>From 35d6ecb61972919a8c7fd418766bd303dde687b3 Mon Sep 17 00:00:00 2001<br>From: zswan <zswan@zswan-marvell.(none)><br>Date: Tue, 18 May 2010 10:51:12 +0800<br>Subject: [PATCH 3/3] add-nuc900-audio-driver-support-v5.patch<br>
<br>---<br> sound/soc/Kconfig | 1 +<br> sound/soc/Makefile | 1 +<br> sound/soc/nuc900/Kconfig | 27 +++<br> sound/soc/nuc900/Makefile | 11 +<br> sound/soc/nuc900/nuc900-ac97.c | 443 +++++++++++++++++++++++++++++++++++++++<br>
sound/soc/nuc900/nuc900-audio.c | 81 +++++++<br> sound/soc/nuc900/nuc900-auido.h | 121 +++++++++++<br> sound/soc/nuc900/nuc900-pcm.c | 352 +++++++++++++++++++++++++++++++<br> 8 files changed, 1037 insertions(+), 0 deletions(-)<br>
create mode 100644 sound/soc/nuc900/Kconfig<br> create mode 100644 sound/soc/nuc900/Makefile<br> create mode 100644 sound/soc/nuc900/nuc900-ac97.c<br> create mode 100644 sound/soc/nuc900/nuc900-audio.c<br> create mode 100644 sound/soc/nuc900/nuc900-auido.h<br>
create mode 100644 sound/soc/nuc900/nuc900-pcm.c<br><br>diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig<br>index b1749bc..6e04fc2 100644<br>--- a/sound/soc/Kconfig<br>+++ b/sound/soc/Kconfig<br>@@ -30,6 +30,7 @@ source "sound/soc/blackfin/Kconfig"<br>
source "sound/soc/davinci/Kconfig"<br> source "sound/soc/fsl/Kconfig"<br> source "sound/soc/imx/Kconfig"<br>+source "sound/soc/nuc900/Kconfig"<br> source "sound/soc/omap/Kconfig"<br>
source "sound/soc/pxa/Kconfig"<br> source "sound/soc/s3c24xx/Kconfig"<br>diff --git a/sound/soc/Makefile b/sound/soc/Makefile<br>index 1470141..ccec241 100644<br>--- a/sound/soc/Makefile<br>+++ b/sound/soc/Makefile<br>
@@ -8,6 +8,7 @@ obj-$(CONFIG_SND_SOC) += blackfin/<br> obj-$(CONFIG_SND_SOC) += davinci/<br> obj-$(CONFIG_SND_SOC) += fsl/<br> obj-$(CONFIG_SND_SOC) += imx/<br>+obj-$(CONFIG_SND_SOC) += nuc900/<br> obj-$(CONFIG_SND_SOC) += omap/<br>
obj-$(CONFIG_SND_SOC) += pxa/<br> obj-$(CONFIG_SND_SOC) += s3c24xx/<br>diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig<br>new file mode 100644<br>index 0000000..a0ed1c6<br>--- /dev/null<br>+++ b/sound/soc/nuc900/KconfigFrom 35d6ecb61972919a8c7fd418766bd303dde687b3 Mon Sep 17 00:00:00 2001<br>
From: zswan <zswan@zswan-marvell.(none)><br>Date: Tue, 18 May 2010 10:51:12 +0800<br>Subject: [PATCH 3/3] add-nuc900-audio-driver-support-v5.patch<br><br>---<br> sound/soc/Kconfig | 1 +<br> sound/soc/Makefile | 1 +<br>
sound/soc/nuc900/Kconfig | 27 +++<br> sound/soc/nuc900/Makefile | 11 +<br> sound/soc/nuc900/nuc900-ac97.c | 443 +++++++++++++++++++++++++++++++++++++++<br> sound/soc/nuc900/nuc900-audio.c | 81 +++++++<br>
sound/soc/nuc900/nuc900-auido.h | 121 +++++++++++<br> sound/soc/nuc900/nuc900-pcm.c | 352 +++++++++++++++++++++++++++++++<br> 8 files changed, 1037 insertions(+), 0 deletions(-)<br> create mode 100644 sound/soc/nuc900/Kconfig<br>
create mode 100644 sound/soc/nuc900/Makefile<br> create mode 100644 sound/soc/nuc900/nuc900-ac97.c<br> create mode 100644 sound/soc/nuc900/nuc900-audio.c<br> create mode 100644 sound/soc/nuc900/nuc900-auido.h<br> create mode 100644 sound/soc/nuc900/nuc900-pcm.c<br>
<br>diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig<br>index b1749bc..6e04fc2 100644<br>--- a/sound/soc/Kconfig<br>+++ b/sound/soc/Kconfig<br>@@ -30,6 +30,7 @@ source "sound/soc/blackfin/Kconfig"<br> source "sound/soc/davinci/Kconfig"<br>
source "sound/soc/fsl/Kconfig"<br> source "sound/soc/imx/Kconfig"<br>+source "sound/soc/nuc900/Kconfig"<br> source "sound/soc/omap/Kconfig"<br> source "sound/soc/pxa/Kconfig"<br>
source "sound/soc/s3c24xx/Kconfig"<br>diff --git a/sound/soc/Makefile b/sound/soc/Makefile<br>index 1470141..ccec241 100644<br>--- a/sound/soc/Makefile<br>+++ b/sound/soc/Makefile<br>@@ -8,6 +8,7 @@ obj-$(CONFIG_SND_SOC) += blackfin/<br>
obj-$(CONFIG_SND_SOC) += davinci/<br> obj-$(CONFIG_SND_SOC) += fsl/<br> obj-$(CONFIG_SND_SOC) += imx/<br>+obj-$(CONFIG_SND_SOC) += nuc900/<br> obj-$(CONFIG_SND_SOC) += omap/<br> obj-$(CONFIG_SND_SOC) += pxa/<br> obj-$(CONFIG_SND_SOC) += s3c24xx/<br>
diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig<br>new file mode 100644<br>index 0000000..a0ed1c6<br>--- /dev/null<br>+++ b/sound/soc/nuc900/Kconfig<br>@@ -0,0 +1,27 @@<br>+##<br>+## NUC900 series AC97 API<br>
+##<br>+config SND_SOC_NUC900<br>+ tristate "SoC Audio for NUC900 series"<br>+ depends on ARCH_W90X900<br>+ help<br>+ This option enables support for AC97 mode on the NUC900 SoC.<br>+<br>
+config SND_SOC_NUC900_AC97<br>+ tristate<br>+ select AC97_BUS<br>+ select SND_AC97_CODEC<br>+ select SND_SOC_AC97_BUS<br>+<br>+<br>+##<br>+## Boards<br>+##<br>+config SND_SOC_NUC900EVB<br>+ tristate "NUC900 AC97 support for demo board"<br>
+ depends on SND_SOC_NUC900<br>+ select SND_SOC_NUC900_AC97<br>+ select SND_SOC_AC97_CODEC<br>+ help<br>+ Select this option to enable audio (AC97) on the<br>+ NUC900 demoboard.<br>
diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile<br>new file mode 100644<br>index 0000000..7e46c71<br>--- /dev/null<br>+++ b/sound/soc/nuc900/Makefile<br>@@ -0,0 +1,11 @@<br>+# NUC900 series audio<br>+snd-soc-nuc900-pcm-objs := nuc900-pcm.o<br>
+snd-soc-nuc900-ac97-objs := nuc900-ac97.o<br>+<br>+obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o<br>+obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o<br>+<br>+# Boards<br>+snd-soc-nuc900-audio-objs := nuc900-audio.o<br>
+<br>+obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o<br>diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c<br>new file mode 100644<br>index 0000000..2c345e2<br>--- /dev/null<br>+++ b/sound/soc/nuc900/nuc900-ac97.c<br>
@@ -0,0 +1,443 @@<br>+/*<br>+ * Copyright (c) 2009-2010 Nuvoton technology corporation.<br>+ *<br>+ * Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>><br>
+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation;version 2 of the License.<br>
+ *<br>+ */<br>+<br>+#include <linux/init.h><br>+#include <linux/module.h><br>+#include <linux/slab.h><br>+#include <linux/device.h><br>+#include <linux/delay.h><br>+#include <linux/mutex.h><br>
+#include <linux/suspend.h><br>+#include <sound/core.h><br>+#include <sound/pcm.h><br>+#include <sound/initval.h><br>+#include <sound/soc.h><br>+#include <linux/device.h><br>+#include <linux/clk.h><br>
+<br>+#include <mach/mfp.h><br>+<br>+#include "nuc900-auido.h"<br>+<br>+static DEFINE_MUTEX(ac97_mutex);<br>+struct nuc900_audio *nuc900_ac97_data;<br>+<br>+static int nuc900_checkready(void)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>
+<br>+ if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY))<br>+ return -EPERM;<br>+<br>+ return 0;<br>+}<br>+<br>+/* AC97 controller reads codec register */<br>+static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97,<br>
+ unsigned short reg)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ unsigned long timeout = 0x10000, val;<br>+<br>+ mutex_lock(&ac97_mutex);<br>
+<br>+ val = nuc900_checkready();<br>+ if (!!val) {<br>+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");<br>+ goto out;<br>+ }<br>+<br>+ /* set the R_WB bit and write register index */<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg);<br>+<br>+ /* set the valid frame bit and valid slots */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>+ val |= (VALID_FRAME | SLOT1_VALID);<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);<br>+<br>+ udelay(100);<br>+<br>+ /* polling the AC_R_FINISH */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>+ val &= AC_R_FINISH;<br>
+ while (!val && timeout--)<br>+ mdelay(1);<br>+<br>+ if (!timeout) {<br>+ dev_err(nuc900_audio->dev, "AC97 read register time out !\n");<br>+ val = -EPERM;<br>
+ goto out;<br>+ }<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ;<br>+ val &= ~SLOT1_VALID;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);<br>+<br>+ if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) {<br>
+ dev_err(nuc900_audio->dev,<br>+ "R_INDEX of REG_ACTL_ACIS1 not match!\n");<br>+ }<br>+<br>+ udelay(100);<br>+ val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF);<br>
+<br>+out:<br>+ mutex_unlock(&ac97_mutex);<br>+ return val;<br>+}<br>+<br>+/* AC97 controller writes to codec register */<br>+static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg,<br>+ unsigned short val)<br>
+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ unsigned long tmp, timeout = 0x10000;<br>+<br>+ mutex_lock(&ac97_mutex);<br>+<br>+ tmp = nuc900_checkready();<br>+ if (!!tmp)<br>
+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");<br>+<br>+ /* clear the R_WB bit and write register index */<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg);<br>+<br>
+ /* write register value */<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val);<br>+<br>+ /* set the valid frame bit and valid slots */<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>
+ tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);<br>+<br>+ udelay(100);<br>+<br>+ /* polling the AC_W_FINISH */<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>
+ tmp &= AC_W_FINISH;<br>+ while (tmp && timeout--)<br>+ mdelay(1);<br>+<br>+ if (!timeout)<br>+ dev_err(nuc900_audio->dev, "AC97 write register time out !\n");<br>
+<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>+ tmp &= ~(SLOT1_VALID | SLOT2_VALID);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);<br>+<br>+ mutex_unlock(&ac97_mutex);<br>
+<br>+}<br>+<br>+static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ unsigned long val;<br>+<br>+ mutex_lock(&ac97_mutex);<br>
+<br>+ /* warm reset AC 97 */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>+ val |= AC_W_RES;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);<br>+<br>+ udelay(1000);<br>
+<br>+ val = nuc900_checkready();<br>+ if (!!val)<br>+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");<br>+<br>+ mutex_unlock(&ac97_mutex);<br>+}<br>+<br>+static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97)<br>
+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ unsigned long val;<br>+<br>+ mutex_lock(&ac97_mutex);<br>+<br>+ /* reset Audio Controller */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>
+ val |= ACTL_RESET_BIT;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+<br>+ udelay(1000);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ val &= (~ACTL_RESET_BIT);<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+<br>+ udelay(1000);<br>+<br>+ /* reset AC-link interface */<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ val |= AC_RESET;<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+<br>+ udelay(1000);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ val &= ~AC_RESET;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>
+<br>+ udelay(1000);<br>+<br>+ /* cold reset AC 97 */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>+ val |= AC_C_RES;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);<br>
+<br>+ udelay(1000);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>+ val &= (~AC_C_RES);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);<br>+<br>+ udelay(1000);<br>
+<br>+ mutex_unlock(&ac97_mutex);<br>+<br>+}<br>+<br>+/* AC97 controller operations */<br>+struct snd_ac97_bus_ops soc_ac97_ops = {<br>+ .read = nuc900_ac97_read,<br>+ .write = nuc900_ac97_write,<br>
+ .reset = nuc900_ac97_cold_reset,<br>+ .warm_reset = nuc900_ac97_warm_reset,<br>+}<br>+EXPORT_SYMBOL_GPL(soc_ac97_ops);<br>+<br>+static int nuc900_ac97_trigger(struct snd_pcm_substream *substream,<br>
+ int cmd, struct snd_soc_dai *dai)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ int ret, stype = SUBSTREAM_TYPE(substream);<br>+ unsigned long val, tmp;<br>
+<br>+ ret = 0;<br>+<br>+ switch (cmd) {<br>+ case SNDRV_PCM_TRIGGER_START:<br>+ case SNDRV_PCM_TRIGGER_RESUME:<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ if (PCM_TX == stype) {<br>
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>+ tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);<br>
+<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);<br>+ tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp);<br>
+ val |= AC_PLAY;<br>+ } else {<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);<br>+ tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ);<br>+<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp);<br>+ val |= AC_RECORD;<br>+ }<br>+<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>
+<br>+ break;<br>+ case SNDRV_PCM_TRIGGER_STOP:<br>+ case SNDRV_PCM_TRIGGER_SUSPEND:<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ if (PCM_TX == stype) {<br>
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>+ tmp &= ~(SLOT3_VALID | SLOT4_VALID);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);<br>
+<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR);<br>+ val &= ~AC_PLAY;<br>+ } else {<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR);<br>
+ val &= ~AC_RECORD;<br>+ }<br>+<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+<br>+ break;<br>+ default:<br>+ ret = -EINVAL;<br>
+ }<br>+<br>+ return ret;<br>+}<br>+<br>+static int nuc900_ac97_probe(struct platform_device *pdev,<br>+ struct snd_soc_dai *dai)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>
+ unsigned long val;<br>+<br>+ mutex_lock(&ac97_mutex);<br>+<br>+ /* enable unit clock */<br>+ clk_enable(nuc900_audio->clk);<br>+<br>+ /* enable audio controller and AC-link interface */<br>
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);<br>+ val |= (IIS_AC_PIN_SEL | ACLINK_EN);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);<br>+<br>+ mutex_unlock(&ac97_mutex);<br>
+<br>+ return 0;<br>+}<br>+<br>+static void nuc900_ac97_remove(struct platform_device *pdev,<br>+ struct snd_soc_dai *dai)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>
+<br>+ clk_disable(nuc900_audio->clk);<br>+}<br>+<br>+static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {<br>+ .trigger = nuc900_ac97_trigger,<br>+};<br>+<br>+struct snd_soc_dai nuc900_ac97_dai = {<br>
+ .name = "nuc900-ac97",<br>+ .probe = nuc900_ac97_probe,<br>+ .remove = nuc900_ac97_remove,<br>+ .ac97_control = 1,<br>+ .playback = {<br>
+ .rates = SNDRV_PCM_RATE_8000_48000,<br>+ .formats = SNDRV_PCM_FMTBIT_S16_LE,<br>+ .channels_min = 1,<br>+ .channels_max = 2,<br>+ },<br>+ .capture = {<br>
+ .rates = SNDRV_PCM_RATE_8000_48000,<br>+ .formats = SNDRV_PCM_FMTBIT_S16_LE,<br>+ .channels_min = 1,<br>+ .channels_max = 2,<br>+ },<br>+ .ops = &nuc900_ac97_dai_ops,<br>
+}<br>+EXPORT_SYMBOL_GPL(nuc900_ac97_dai);<br>+<br>+static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)<br>+{<br>+ struct nuc900_audio *nuc900_audio;<br>+ int ret;<br>+<br>+ if (nuc900_ac97_data)<br>
+ return -EBUSY;<br>+<br>+ nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL);<br>+ if (!nuc900_audio)<br>+ return -ENOMEM;<br>+<br>+ spin_lock_init(&nuc900_audio->lock);<br>
+<br>+ nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);<br>+ if (!nuc900_audio->res) {<br>+ ret = -ENODEV;<br>+ goto out0;<br>+ }<br>+<br>+ if (!request_mem_region(nuc900_audio->res->start,<br>
+ resource_size(nuc900_audio->res), pdev->name)) {<br>+ ret = -EBUSY;<br>+ goto out0;<br>+ }<br>+<br>+ nuc900_audio->mmio = ioremap(nuc900_audio->res->start,<br>
+ resource_size(nuc900_audio->res));<br>+ if (!nuc900_audio->mmio) {<br>+ ret = -ENOMEM;<br>+ goto out1;<br>+ }<br>+<br>+ nuc900_audio->clk = clk_get(&pdev->dev, NULL);<br>
+ if (IS_ERR(nuc900_audio->clk)) {<br>+ ret = PTR_ERR(nuc900_audio->clk);<br>+ goto out2;<br>+ }<br>+<br>+ nuc900_audio->irq_num = platform_get_irq(pdev, 0);<br>+ if (!nuc900_audio->irq_num) {<br>
+ ret = -EBUSY;<br>+ goto out2;<br>+ }<br>+<br>+ nuc900_ac97_data = nuc900_audio;<br>+<br>+ nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev;<br>+<br>+ ret = snd_soc_register_dai(&nuc900_ac97_dai);<br>
+ if (ret)<br>+ goto out3;<br>+<br>+ mfp_set_groupg(nuc900_audio->dev); /* enbale ac97 multifunction pin*/<br>+<br>+ return 0;<br>+<br>+out3:<br>+ clk_put(nuc900_audio->clk);<br>
+out2:<br>+ iounmap(nuc900_audio->mmio);<br>+out1:<br>+ release_mem_region(nuc900_audio->res->start,<br>+ resource_size(nuc900_audio->res));<br>+out0:<br>+ kfree(nuc900_audio);<br>
+ return ret;<br>+}<br>+<br>+static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)<br>+{<br>+<br>+ snd_soc_unregister_dai(&nuc900_ac97_dai);<br>+<br>+ clk_put(nuc900_ac97_data->clk);<br>
+ iounmap(nuc900_ac97_data->mmio);<br>+ release_mem_region(nuc900_ac97_data->res->start,<br>+ resource_size(nuc900_ac97_data->res));<br>+<br>+ nuc900_ac97_data = NULL;<br>
+<br>+ return 0;<br>+}<br>+<br>+static struct platform_driver nuc900_ac97_driver = {<br>+ .driver = {<br>+ .name = "nuc900-audio",<br>+ .owner = THIS_MODULE,<br>+ },<br>
+ .probe = nuc900_ac97_drvprobe,<br>+ .remove = __devexit_p(nuc900_ac97_drvremove),<br>+};<br>+<br>+static int __init nuc900_ac97_init(void)<br>+{<br>+ return platform_driver_register(&nuc900_ac97_driver);<br>
+}<br>+<br>+static void __exit nuc900_ac97_exit(void)<br>+{<br>+ platform_driver_unregister(&nuc900_ac97_driver);<br>+}<br>+<br>+module_init(nuc900_ac97_init);<br>+module_exit(nuc900_ac97_exit);<br>+<br>+MODULE_AUTHOR("Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>>");<br>
+MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");<br>+MODULE_LICENSE("GPL");<br>+MODULE_ALIAS("platform:nuc900-ac97");<br>+<br>diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c<br>
new file mode 100644<br>index 0000000..b33d5b8<br>--- /dev/null<br>+++ b/sound/soc/nuc900/nuc900-audio.c<br>@@ -0,0 +1,81 @@<br>+/*<br>+ * Copyright (c) 2010 Nuvoton technology corporation.<br>+ *<br>+ * Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>><br>
+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation;version 2 of the License.<br>
+ *<br>+ */<br>+<br>+#include <linux/module.h><br>+#include <linux/moduleparam.h><br>+#include <linux/timer.h><br>+#include <linux/interrupt.h><br>+#include <linux/platform_device.h><br>+<br>
+#include <sound/core.h><br>+#include <sound/pcm.h><br>+#include <sound/soc.h><br>+#include <sound/soc-dapm.h><br>+<br>+#include "../codecs/ac97.h"<br>+#include "nuc900-auido.h"<br>
+<br>+static struct snd_soc_dai_link nuc900evb_ac97_dai = {<br>+ .name = "AC97",<br>+ .stream_name = "AC97 HiFi",<br>+ .cpu_dai = &nuc900_ac97_dai,<br>+ .codec_dai = &ac97_dai,<br>
+};<br>+<br>+static struct snd_soc_card nuc900evb_audio_machine = {<br>+ .name = "NUC900EVB_AC97",<br>+ .dai_link = &nuc900evb_ac97_dai,<br>+ .num_links = 1,<br>+ .platform = &nuc900_soc_platform,<br>
+};<br>+<br>+static struct snd_soc_device nuc900evb_ac97_devdata = {<br>+ .card = &nuc900evb_audio_machine,<br>+ .codec_dev = &soc_codec_dev_ac97,<br>+};<br>+<br>+static struct platform_device *nuc900evb_asoc_dev;<br>
+<br>+static int __init nuc900evb_audio_init(void)<br>+{<br>+ int ret;<br>+<br>+ ret = -ENOMEM;<br>+ nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1);<br>+ if (!nuc900evb_asoc_dev)<br>
+ goto out;<br>+<br>+ /* nuc900 board audio device */<br>+ platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);<br>+<br>+ nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;<br>
+ ret = platform_device_add(nuc900evb_asoc_dev);<br>+<br>+ if (ret) {<br>+ platform_device_put(nuc900evb_asoc_dev);<br>+ nuc900evb_asoc_dev = NULL;<br>+ }<br>+<br>+out:<br>+ return ret;<br>
+}<br>+<br>+static void __exit nuc900evb_audio_exit(void)<br>+{<br>+ platform_device_unregister(nuc900evb_asoc_dev);<br>+}<br>+<br>+module_init(nuc900evb_audio_init);<br>+module_exit(nuc900evb_audio_exit);<br>+<br>+MODULE_LICENSE("GPL");<br>
+MODULE_DESCRIPTION("NUC900 Series ASoC audio support");<br>+MODULE_AUTHOR("Wan ZongShun");<br>diff --git a/sound/soc/nuc900/nuc900-auido.h b/sound/soc/nuc900/nuc900-auido.h<br>new file mode 100644<br>
index 0000000..95ac4ef<br>--- /dev/null<br>+++ b/sound/soc/nuc900/nuc900-auido.h<br>@@ -0,0 +1,121 @@<br>+/*<br>+ * Copyright (c) 2010 Nuvoton technology corporation.<br>+ *<br>+ * Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>><br>
+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation;version 2 of the License.<br>
+ *<br>+ */<br>+<br>+#ifndef _NUC900_AUDIO_H<br>+#define _NUC900_AUDIO_H<br>+<br>+#include <linux/io.h><br>+<br>+/* Audio Control Registers */<br>+#define ACTL_CON 0x00<br>+#define ACTL_RESET 0x04<br>
+#define ACTL_RDSTB 0x08<br>+#define ACTL_RDST_LENGTH 0x0C<br>+#define ACTL_RDSTC 0x10<br>+#define ACTL_RSR 0x14<br>+#define ACTL_PDSTB 0x18<br>+#define ACTL_PDST_LENGTH 0x1C<br>
+#define ACTL_PDSTC 0x20<br>+#define ACTL_PSR 0x24<br>+#define ACTL_IISCON 0x28<br>+#define ACTL_ACCON 0x2C<br>+#define ACTL_ACOS0 0x30<br>+#define ACTL_ACOS1 0x34<br>
+#define ACTL_ACOS2 0x38<br>+#define ACTL_ACIS0 0x3C<br>+#define ACTL_ACIS1 0x40<br>+#define ACTL_ACIS2 0x44<br>+#define ACTL_COUNTER 0x48<br>+<br>+/* bit definition of REG_ACTL_CON register */<br>
+#define R_DMA_IRQ 0x1000<br>+#define T_DMA_IRQ 0x0800<br>+#define IIS_AC_PIN_SEL 0x0100<br>+#define FIFO_TH 0x0080<br>+#define ADC_EN 0x0010<br>+#define M80_EN 0x0008<br>
+#define ACLINK_EN 0x0004<br>+#define IIS_EN 0x0002<br>+<br>+/* bit definition of REG_ACTL_RESET register */<br>+#define W5691_PLAY 0x20000<br>+#define ACTL_RESET_BIT 0x10000<br>
+#define RECORD_RIGHT_CHNNEL 0x08000<br>+#define RECORD_LEFT_CHNNEL 0x04000<br>+#define PLAY_RIGHT_CHNNEL 0x02000<br>+#define PLAY_LEFT_CHNNEL 0x01000<br>+#define DAC_PLAY 0x00800<br>+#define ADC_RECORD 0x00400<br>
+#define M80_PLAY 0x00200<br>+#define AC_RECORD 0x00100<br>+#define AC_PLAY 0x00080<br>+#define IIS_RECORD 0x00040<br>+#define IIS_PLAY 0x00020<br>
+#define DAC_RESET 0x00010<br>+#define ADC_RESET 0x00008<br>+#define M80_RESET 0x00004<br>+#define AC_RESET 0x00002<br>+#define IIS_RESET 0x00001<br>+<br>+/* bit definition of REG_ACTL_ACCON register */<br>
+#define AC_BCLK_PU_EN 0x20<br>+#define AC_R_FINISH 0x10<br>+#define AC_W_FINISH 0x08<br>+#define AC_W_RES 0x04<br>+#define AC_C_RES 0x02<br>+<br>+/* bit definition of ACTL_RSR register */<br>
+#define R_FIFO_EMPTY 0x04<br>+#define R_DMA_END_IRQ 0x02<br>+#define R_DMA_MIDDLE_IRQ 0x01<br>+<br>+/* bit definition of ACTL_PSR register */<br>+#define P_FIFO_EMPTY 0x04<br>+#define P_DMA_END_IRQ 0x02<br>
+#define P_DMA_MIDDLE_IRQ 0x01<br>+<br>+/* bit definition of ACTL_ACOS0 register */<br>+#define SLOT1_VALID 0x01<br>+#define SLOT2_VALID 0x02<br>+#define SLOT3_VALID 0x04<br>+#define SLOT4_VALID 0x08<br>
+#define VALID_FRAME 0x10<br>+<br>+/* bit definition of ACTL_ACOS1 register */<br>+#define R_WB 0x80<br>+<br>+#define CODEC_READY 0x10<br>+#define RESET_PRSR 0x00<br>+#define AUDIO_WRITE(addr, val) __raw_writel(val, addr)<br>
+#define AUDIO_READ(addr) __raw_readl(addr)<br>+#define PCM_TX 0<br>+#define PCM_RX 1<br>+#define SUBSTREAM_TYPE(substream) \<br>+ ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)<br>
+<br>+struct nuc900_audio {<br>+ void __iomem *mmio;<br>+ spinlock_t lock;<br>+ dma_addr_t dma_addr[2];<br>+ unsigned long buffersize[2];<br>+ unsigned long irq_num;<br>+ struct snd_pcm_substream *substream;<br>
+ struct resource *res;<br>+ struct clk *clk;<br>+ struct device *dev;<br>+<br>+};<br>+<br>+extern struct nuc900_audio *nuc900_ac97_data;<br>+extern struct snd_soc_dai nuc900_ac97_dai;<br>+extern struct snd_soc_platform nuc900_soc_platform;<br>
+<br>+#endif /*end _NUC900_AUDIO_H */<br>diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c<br>new file mode 100644<br>index 0000000..32a503c<br>--- /dev/null<br>+++ b/sound/soc/nuc900/nuc900-pcm.c<br>
@@ -0,0 +1,352 @@<br>+/*<br>+ * Copyright (c) 2010 Nuvoton technology corporation.<br>+ *<br>+ * Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>><br>
+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation;version 2 of the License.<br>
+ *<br>+ */<br>+<br>+#include <linux/module.h><br>+#include <linux/init.h><br>+#include <linux/io.h><br>+#include <linux/platform_device.h><br>+#include <linux/slab.h><br>+#include <linux/dma-mapping.h><br>
+<br>+#include <sound/core.h><br>+#include <sound/pcm.h><br>+#include <sound/pcm_params.h><br>+#include <sound/soc.h><br>+<br>+#include <mach/hardware.h><br>+<br>+#include "nuc900-auido.h"<br>
+<br>+static const struct snd_pcm_hardware nuc900_pcm_hardware = {<br>+ .info = SNDRV_PCM_INFO_INTERLEAVED |<br>+ SNDRV_PCM_INFO_BLOCK_TRANSFER |<br>+ SNDRV_PCM_INFO_MMAP |<br>
+ SNDRV_PCM_INFO_MMAP_VALID |<br>+ SNDRV_PCM_INFO_PAUSE |<br>+ SNDRV_PCM_INFO_RESUME,<br>+ .formats = SNDRV_PCM_FMTBIT_S16_LE,<br>
+ .channels_min = 1,<br>+ .channels_max = 2,<br>+ .buffer_bytes_max = 4*1024,<br>+ .period_bytes_min = 1*1024,<br>+ .period_bytes_max = 4*1024,<br>+ .periods_min = 1,<br>
+ .periods_max = 1024,<br>+};<br>+<br>+static int nuc900_dma_hw_params(struct snd_pcm_substream *substream,<br>+ struct snd_pcm_hw_params *params)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>
+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ unsigned long flags, stype = SUBSTREAM_TYPE(substream);<br>+ int ret = 0;<br>+<br>+ spin_lock_irqsave(&nuc900_audio->lock, flags);<br>
+<br>+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));<br>+ if (ret < 0)<br>+ return ret;<br>+<br>+ nuc900_audio->substream = substream;<br>+ nuc900_audio->dma_addr[stype] = runtime->dma_addr;<br>
+ nuc900_audio->buffersize[stype] = params_buffer_bytes(params);<br>+<br>+ spin_unlock_irqrestore(&nuc900_audio->lock, flags);<br>+<br>+ return ret;<br>+}<br>+<br>+static void nuc900_update_dma_register(struct snd_pcm_substream *substream,<br>
+ dma_addr_t dma_addr, size_t count)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ void __iomem *mmio_addr, *mmio_len;<br>
+<br>+ if (SUBSTREAM_TYPE(substream) == PCM_TX) {<br>+ mmio_addr = nuc900_audio->mmio + ACTL_PDSTB;<br>+ mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH;<br>+ } else {<br>+ mmio_addr = nuc900_audio->mmio + ACTL_RDSTB;<br>
+ mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH;<br>+ }<br>+<br>+ AUDIO_WRITE(mmio_addr, dma_addr);<br>+ AUDIO_WRITE(mmio_len, count);<br>+}<br>+<br>+static void nuc900_dma_start(struct snd_pcm_substream *substream)<br>
+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ unsigned long val;<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);<br>
+ val |= (T_DMA_IRQ | R_DMA_IRQ);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);<br>+}<br>+<br>+static void nuc900_dma_stop(struct snd_pcm_substream *substream)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>
+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ unsigned long val;<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);<br>+ val &= ~(T_DMA_IRQ | R_DMA_IRQ);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);<br>
+}<br>+<br>+static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id)<br>+{<br>+ struct snd_pcm_substream *substream = dev_id;<br>+ struct nuc900_audio *nuc900_audio = substream->runtime->private_data;<br>
+ unsigned long val;<br>+<br>+ spin_lock(&nuc900_audio->lock);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);<br>+<br>+ if (val & R_DMA_IRQ) {<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ);<br>
+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);<br>+<br>+ if (val & R_DMA_MIDDLE_IRQ) {<br>+ val |= R_DMA_MIDDLE_IRQ;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);<br>
+ }<br>+<br>+ if (val & R_DMA_END_IRQ) {<br>+ val |= R_DMA_END_IRQ;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);<br>+ }<br>
+ } else if (val & T_DMA_IRQ) {<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);<br>+<br>+ if (val & P_DMA_MIDDLE_IRQ) {<br>
+ val |= P_DMA_MIDDLE_IRQ;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);<br>+ }<br>+<br>+ if (val & P_DMA_END_IRQ) {<br>+ val |= P_DMA_END_IRQ;<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);<br>+ }<br>+ } else {<br>+ dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n");<br>+ spin_unlock(&nuc900_audio->lock);<br>
+ return IRQ_HANDLED;<br>+ }<br>+<br>+ spin_unlock(&nuc900_audio->lock);<br>+<br>+ snd_pcm_period_elapsed(substream);<br>+<br>+ return IRQ_HANDLED;<br>+}<br>+<br>+static int nuc900_dma_hw_free(struct snd_pcm_substream *substream)<br>
+{<br>+ snd_pcm_lib_free_pages(substream);<br>+ return 0;<br>+}<br>+<br>+static int nuc900_dma_prepare(struct snd_pcm_substream *substream)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>
+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ unsigned long flags, val, stype = SUBSTREAM_TYPE(substream);;<br>+<br>+ spin_lock_irqsave(&nuc900_audio->lock, flags);<br>+<br>
+ nuc900_update_dma_register(substream,<br>+ nuc900_audio->dma_addr[stype], nuc900_audio->buffersize[stype]);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+<br>+ switch (runtime->channels) {<br>
+ case 1:<br>+ if (PCM_TX == stype) {<br>+ val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);<br>+ val |= PLAY_RIGHT_CHNNEL;<br>+ } else {<br>
+ val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);<br>+ val |= RECORD_RIGHT_CHNNEL;<br>+ }<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>
+ break;<br>+ case 2:<br>+ if (PCM_TX == stype)<br>+ val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);<br>+ else<br>+ val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+ break;<br>+ default:<br>+ return -EINVAL;<br>+ }<br>+ spin_unlock_irqrestore(&nuc900_audio->lock, flags);<br>
+ return 0;<br>+}<br>+<br>+static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd)<br>+{<br>+ int ret = 0;<br>+<br>+ switch (cmd) {<br>+ case SNDRV_PCM_TRIGGER_START:<br>+ case SNDRV_PCM_TRIGGER_RESUME:<br>
+ nuc900_dma_start(substream);<br>+ break;<br>+<br>+ case SNDRV_PCM_TRIGGER_STOP:<br>+ case SNDRV_PCM_TRIGGER_SUSPEND:<br>+ nuc900_dma_stop(substream);<br>+ break;<br>
+<br>+ default:<br>+ ret = -EINVAL;<br>+ break;<br>+ }<br>+<br>+ return ret;<br>+}<br>+<br>+int nuc900_dma_getposition(struct snd_pcm_substream *substream,<br>+ dma_addr_t *src, dma_addr_t *dst)<br>
+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+<br>+ if (src != NULL)<br>+ *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC);<br>
+<br>+ if (dst != NULL)<br>+ *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC);<br>+<br>+ return 0;<br>+}<br>+<br>+static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream)<br>
+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ dma_addr_t src, dst;<br>+ unsigned long res;<br>+<br>+ nuc900_dma_getposition(substream, &src, &dst);<br>+<br>+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)<br>
+ res = dst - runtime->dma_addr;<br>+ else<br>+ res = src - runtime->dma_addr;<br>+<br>+ return bytes_to_frames(substream->runtime, res);<br>+}<br>+<br>+static int nuc900_dma_open(struct snd_pcm_substream *substream)<br>
+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio;<br>+<br>+ snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware);<br>+<br>+ nuc900_audio = nuc900_ac97_data;<br>
+<br>+ if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt,<br>+ IRQF_DISABLED, "nuc900-dma", substream))<br>+ return -EBUSY;<br>+<br>+ runtime->private_data = nuc900_audio;<br>
+<br>+ return 0;<br>+}<br>+<br>+static int nuc900_dma_close(struct snd_pcm_substream *substream)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>
+<br>+ free_irq(nuc900_audio->irq_num, substream);<br>+<br>+ return 0;<br>+}<br>+<br>+static int nuc900_dma_mmap(struct snd_pcm_substream *substream,<br>+ struct vm_area_struct *vma)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>
+<br>+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,<br>+ runtime->dma_area,<br>+ runtime->dma_addr,<br>+ runtime->dma_bytes);<br>
+}<br>+<br>+static struct snd_pcm_ops nuc900_dma_ops = {<br>+ .open = nuc900_dma_open,<br>+ .close = nuc900_dma_close,<br>+ .ioctl = snd_pcm_lib_ioctl,<br>+ .hw_params = nuc900_dma_hw_params,<br>
+ .hw_free = nuc900_dma_hw_free,<br>+ .prepare = nuc900_dma_prepare,<br>+ .trigger = nuc900_dma_trigger,<br>+ .pointer = nuc900_dma_pointer,<br>+ .mmap = nuc900_dma_mmap,<br>
+};<br>+<br>+static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)<br>+{<br>+ snd_pcm_lib_preallocate_free_for_all(pcm);<br>+}<br>+<br>+static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);<br>+static int nuc900_dma_new(struct snd_card *card,<br>
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)<br>+{<br>+ if (!card->dev->dma_mask)<br>+ card->dev->dma_mask = &nuc900_pcm_dmamask;<br>+ if (!card->dev->coherent_dma_mask)<br>
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);<br>+<br>+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,<br>+ card->dev, 4 * 1024, (4 * 1024) - 1);<br>+<br>+ return 0;<br>
+}<br>+<br>+struct snd_soc_platform nuc900_soc_platform = {<br>+ .name = "nuc900-dma",<br>+ .pcm_ops = &nuc900_dma_ops,<br>+ .pcm_new = nuc900_dma_new,<br>+ .pcm_free = nuc900_dma_free_dma_buffers,<br>
+}<br>+EXPORT_SYMBOL_GPL(nuc900_soc_platform);<br>+<br>+static int __init nuc900_soc_platform_init(void)<br>+{<br>+ return snd_soc_register_platform(&nuc900_soc_platform);<br>+}<br>+<br>+static void __exit nuc900_soc_platform_exit(void)<br>
+{<br>+ snd_soc_unregister_platform(&nuc900_soc_platform);<br>+}<br>+<br>+module_init(nuc900_soc_platform_init);<br>+module_exit(nuc900_soc_platform_exit);<br>+<br>+MODULE_AUTHOR("Wan ZongShun, <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>>");<br>
+MODULE_DESCRIPTION("nuc900 Audio DMA module");<br>+MODULE_LICENSE("GPL");<br>-- <br>1.6.3.3<br><br>@@ -0,0 +1,27 @@<br>+##<br>+## NUC900 series AC97 API<br>+##<br>+config SND_SOC_NUC900<br>+ tristate "SoC Audio for NUC900 series"<br>
+ depends on ARCH_W90X900<br>+ help<br>+ This option enables support for AC97 mode on the NUC900 SoC.<br>+<br>+config SND_SOC_NUC900_AC97<br>+ tristate<br>+ select AC97_BUS<br>+ select SND_AC97_CODEC<br>
+ select SND_SOC_AC97_BUS<br>+<br>+<br>+##<br>+## Boards<br>+##<br>+config SND_SOC_NUC900EVB<br>+ tristate "NUC900 AC97 support for demo board"<br>+ depends on SND_SOC_NUC900<br>+ select SND_SOC_NUC900_AC97<br>
+ select SND_SOC_AC97_CODEC<br>+ help<br>+ Select this option to enable audio (AC97) on the<br>+ NUC900 demoboard.<br>diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile<br>new file mode 100644<br>
index 0000000..7e46c71<br>--- /dev/null<br>+++ b/sound/soc/nuc900/Makefile<br>@@ -0,0 +1,11 @@<br>+# NUC900 series audio<br>+snd-soc-nuc900-pcm-objs := nuc900-pcm.o<br>+snd-soc-nuc900-ac97-objs := nuc900-ac97.o<br>+<br>+obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o<br>
+obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o<br>+<br>+# Boards<br>+snd-soc-nuc900-audio-objs := nuc900-audio.o<br>+<br>+obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o<br>diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c<br>
new file mode 100644<br>index 0000000..2c345e2<br>--- /dev/null<br>+++ b/sound/soc/nuc900/nuc900-ac97.c<br>@@ -0,0 +1,443 @@<br>+/*<br>+ * Copyright (c) 2009-2010 Nuvoton technology corporation.<br>+ *<br>+ * Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>><br>
+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation;version 2 of the License.<br>
+ *<br>+ */<br>+<br>+#include <linux/init.h><br>+#include <linux/module.h><br>+#include <linux/slab.h><br>+#include <linux/device.h><br>+#include <linux/delay.h><br>+#include <linux/mutex.h><br>
+#include <linux/suspend.h><br>+#include <sound/core.h><br>+#include <sound/pcm.h><br>+#include <sound/initval.h><br>+#include <sound/soc.h><br>+#include <linux/device.h><br>+#include <linux/clk.h><br>
+<br>+#include <mach/mfp.h><br>+<br>+#include "nuc900-auido.h"<br>+<br>+static DEFINE_MUTEX(ac97_mutex);<br>+struct nuc900_audio *nuc900_ac97_data;<br>+<br>+static int nuc900_checkready(void)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>
+<br>+ if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY))<br>+ return -EPERM;<br>+<br>+ return 0;<br>+}<br>+<br>+/* AC97 controller reads codec register */<br>+static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97,<br>
+ unsigned short reg)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ unsigned long timeout = 0x10000, val;<br>+<br>+ mutex_lock(&ac97_mutex);<br>
+<br>+ val = nuc900_checkready();<br>+ if (!!val) {<br>+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");<br>+ goto out;<br>+ }<br>+<br>+ /* set the R_WB bit and write register index */<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg);<br>+<br>+ /* set the valid frame bit and valid slots */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>+ val |= (VALID_FRAME | SLOT1_VALID);<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);<br>+<br>+ udelay(100);<br>+<br>+ /* polling the AC_R_FINISH */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>+ val &= AC_R_FINISH;<br>
+ while (!val && timeout--)<br>+ mdelay(1);<br>+<br>+ if (!timeout) {<br>+ dev_err(nuc900_audio->dev, "AC97 read register time out !\n");<br>+ val = -EPERM;<br>
+ goto out;<br>+ }<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ;<br>+ val &= ~SLOT1_VALID;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);<br>+<br>+ if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) {<br>
+ dev_err(nuc900_audio->dev,<br>+ "R_INDEX of REG_ACTL_ACIS1 not match!\n");<br>+ }<br>+<br>+ udelay(100);<br>+ val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF);<br>
+<br>+out:<br>+ mutex_unlock(&ac97_mutex);<br>+ return val;<br>+}<br>+<br>+/* AC97 controller writes to codec register */<br>+static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg,<br>+ unsigned short val)<br>
+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ unsigned long tmp, timeout = 0x10000;<br>+<br>+ mutex_lock(&ac97_mutex);<br>+<br>+ tmp = nuc900_checkready();<br>+ if (!!tmp)<br>
+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");<br>+<br>+ /* clear the R_WB bit and write register index */<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg);<br>+<br>
+ /* write register value */<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val);<br>+<br>+ /* set the valid frame bit and valid slots */<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>
+ tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);<br>+<br>+ udelay(100);<br>+<br>+ /* polling the AC_W_FINISH */<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>
+ tmp &= AC_W_FINISH;<br>+ while (tmp && timeout--)<br>+ mdelay(1);<br>+<br>+ if (!timeout)<br>+ dev_err(nuc900_audio->dev, "AC97 write register time out !\n");<br>
+<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>+ tmp &= ~(SLOT1_VALID | SLOT2_VALID);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);<br>+<br>+ mutex_unlock(&ac97_mutex);<br>
+<br>+}<br>+<br>+static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ unsigned long val;<br>+<br>+ mutex_lock(&ac97_mutex);<br>
+<br>+ /* warm reset AC 97 */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>+ val |= AC_W_RES;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);<br>+<br>+ udelay(1000);<br>
+<br>+ val = nuc900_checkready();<br>+ if (!!val)<br>+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");<br>+<br>+ mutex_unlock(&ac97_mutex);<br>+}<br>+<br>+static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97)<br>
+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ unsigned long val;<br>+<br>+ mutex_lock(&ac97_mutex);<br>+<br>+ /* reset Audio Controller */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>
+ val |= ACTL_RESET_BIT;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+<br>+ udelay(1000);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ val &= (~ACTL_RESET_BIT);<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+<br>+ udelay(1000);<br>+<br>+ /* reset AC-link interface */<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ val |= AC_RESET;<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+<br>+ udelay(1000);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ val &= ~AC_RESET;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>
+<br>+ udelay(1000);<br>+<br>+ /* cold reset AC 97 */<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>+ val |= AC_C_RES;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);<br>
+<br>+ udelay(1000);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);<br>+ val &= (~AC_C_RES);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);<br>+<br>+ udelay(1000);<br>
+<br>+ mutex_unlock(&ac97_mutex);<br>+<br>+}<br>+<br>+/* AC97 controller operations */<br>+struct snd_ac97_bus_ops soc_ac97_ops = {<br>+ .read = nuc900_ac97_read,<br>+ .write = nuc900_ac97_write,<br>
+ .reset = nuc900_ac97_cold_reset,<br>+ .warm_reset = nuc900_ac97_warm_reset,<br>+}<br>+EXPORT_SYMBOL_GPL(soc_ac97_ops);<br>+<br>+static int nuc900_ac97_trigger(struct snd_pcm_substream *substream,<br>
+ int cmd, struct snd_soc_dai *dai)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>+ int ret, stype = SUBSTREAM_TYPE(substream);<br>+ unsigned long val, tmp;<br>
+<br>+ ret = 0;<br>+<br>+ switch (cmd) {<br>+ case SNDRV_PCM_TRIGGER_START:<br>+ case SNDRV_PCM_TRIGGER_RESUME:<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ if (PCM_TX == stype) {<br>
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>+ tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);<br>
+<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);<br>+ tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp);<br>
+ val |= AC_PLAY;<br>+ } else {<br>+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);<br>+ tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ);<br>+<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp);<br>+ val |= AC_RECORD;<br>+ }<br>+<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>
+<br>+ break;<br>+ case SNDRV_PCM_TRIGGER_STOP:<br>+ case SNDRV_PCM_TRIGGER_SUSPEND:<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+ if (PCM_TX == stype) {<br>
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);<br>+ tmp &= ~(SLOT3_VALID | SLOT4_VALID);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);<br>
+<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR);<br>+ val &= ~AC_PLAY;<br>+ } else {<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR);<br>
+ val &= ~AC_RECORD;<br>+ }<br>+<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+<br>+ break;<br>+ default:<br>+ ret = -EINVAL;<br>
+ }<br>+<br>+ return ret;<br>+}<br>+<br>+static int nuc900_ac97_probe(struct platform_device *pdev,<br>+ struct snd_soc_dai *dai)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>
+ unsigned long val;<br>+<br>+ mutex_lock(&ac97_mutex);<br>+<br>+ /* enable unit clock */<br>+ clk_enable(nuc900_audio->clk);<br>+<br>+ /* enable audio controller and AC-link interface */<br>
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);<br>+ val |= (IIS_AC_PIN_SEL | ACLINK_EN);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);<br>+<br>+ mutex_unlock(&ac97_mutex);<br>
+<br>+ return 0;<br>+}<br>+<br>+static void nuc900_ac97_remove(struct platform_device *pdev,<br>+ struct snd_soc_dai *dai)<br>+{<br>+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;<br>
+<br>+ clk_disable(nuc900_audio->clk);<br>+}<br>+<br>+static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {<br>+ .trigger = nuc900_ac97_trigger,<br>+};<br>+<br>+struct snd_soc_dai nuc900_ac97_dai = {<br>
+ .name = "nuc900-ac97",<br>+ .probe = nuc900_ac97_probe,<br>+ .remove = nuc900_ac97_remove,<br>+ .ac97_control = 1,<br>+ .playback = {<br>
+ .rates = SNDRV_PCM_RATE_8000_48000,<br>+ .formats = SNDRV_PCM_FMTBIT_S16_LE,<br>+ .channels_min = 1,<br>+ .channels_max = 2,<br>+ },<br>+ .capture = {<br>
+ .rates = SNDRV_PCM_RATE_8000_48000,<br>+ .formats = SNDRV_PCM_FMTBIT_S16_LE,<br>+ .channels_min = 1,<br>+ .channels_max = 2,<br>+ },<br>+ .ops = &nuc900_ac97_dai_ops,<br>
+}<br>+EXPORT_SYMBOL_GPL(nuc900_ac97_dai);<br>+<br>+static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)<br>+{<br>+ struct nuc900_audio *nuc900_audio;<br>+ int ret;<br>+<br>+ if (nuc900_ac97_data)<br>
+ return -EBUSY;<br>+<br>+ nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL);<br>+ if (!nuc900_audio)<br>+ return -ENOMEM;<br>+<br>+ spin_lock_init(&nuc900_audio->lock);<br>
+<br>+ nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);<br>+ if (!nuc900_audio->res) {<br>+ ret = -ENODEV;<br>+ goto out0;<br>+ }<br>+<br>+ if (!request_mem_region(nuc900_audio->res->start,<br>
+ resource_size(nuc900_audio->res), pdev->name)) {<br>+ ret = -EBUSY;<br>+ goto out0;<br>+ }<br>+<br>+ nuc900_audio->mmio = ioremap(nuc900_audio->res->start,<br>
+ resource_size(nuc900_audio->res));<br>+ if (!nuc900_audio->mmio) {<br>+ ret = -ENOMEM;<br>+ goto out1;<br>+ }<br>+<br>+ nuc900_audio->clk = clk_get(&pdev->dev, NULL);<br>
+ if (IS_ERR(nuc900_audio->clk)) {<br>+ ret = PTR_ERR(nuc900_audio->clk);<br>+ goto out2;<br>+ }<br>+<br>+ nuc900_audio->irq_num = platform_get_irq(pdev, 0);<br>+ if (!nuc900_audio->irq_num) {<br>
+ ret = -EBUSY;<br>+ goto out2;<br>+ }<br>+<br>+ nuc900_ac97_data = nuc900_audio;<br>+<br>+ nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev;<br>+<br>+ ret = snd_soc_register_dai(&nuc900_ac97_dai);<br>
+ if (ret)<br>+ goto out3;<br>+<br>+ mfp_set_groupg(nuc900_audio->dev); /* enbale ac97 multifunction pin*/<br>+<br>+ return 0;<br>+<br>+out3:<br>+ clk_put(nuc900_audio->clk);<br>
+out2:<br>+ iounmap(nuc900_audio->mmio);<br>+out1:<br>+ release_mem_region(nuc900_audio->res->start,<br>+ resource_size(nuc900_audio->res));<br>+out0:<br>+ kfree(nuc900_audio);<br>
+ return ret;<br>+}<br>+<br>+static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)<br>+{<br>+<br>+ snd_soc_unregister_dai(&nuc900_ac97_dai);<br>+<br>+ clk_put(nuc900_ac97_data->clk);<br>
+ iounmap(nuc900_ac97_data->mmio);<br>+ release_mem_region(nuc900_ac97_data->res->start,<br>+ resource_size(nuc900_ac97_data->res));<br>+<br>+ nuc900_ac97_data = NULL;<br>
+<br>+ return 0;<br>+}<br>+<br>+static struct platform_driver nuc900_ac97_driver = {<br>+ .driver = {<br>+ .name = "nuc900-audio",<br>+ .owner = THIS_MODULE,<br>+ },<br>
+ .probe = nuc900_ac97_drvprobe,<br>+ .remove = __devexit_p(nuc900_ac97_drvremove),<br>+};<br>+<br>+static int __init nuc900_ac97_init(void)<br>+{<br>+ return platform_driver_register(&nuc900_ac97_driver);<br>
+}<br>+<br>+static void __exit nuc900_ac97_exit(void)<br>+{<br>+ platform_driver_unregister(&nuc900_ac97_driver);<br>+}<br>+<br>+module_init(nuc900_ac97_init);<br>+module_exit(nuc900_ac97_exit);<br>+<br>+MODULE_AUTHOR("Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>>");<br>
+MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");<br>+MODULE_LICENSE("GPL");<br>+MODULE_ALIAS("platform:nuc900-ac97");<br>+<br>diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c<br>
new file mode 100644<br>index 0000000..b33d5b8<br>--- /dev/null<br>+++ b/sound/soc/nuc900/nuc900-audio.c<br>@@ -0,0 +1,81 @@<br>+/*<br>+ * Copyright (c) 2010 Nuvoton technology corporation.<br>+ *<br>+ * Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>><br>
+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation;version 2 of the License.<br>
+ *<br>+ */<br>+<br>+#include <linux/module.h><br>+#include <linux/moduleparam.h><br>+#include <linux/timer.h><br>+#include <linux/interrupt.h><br>+#include <linux/platform_device.h><br>+<br>
+#include <sound/core.h><br>+#include <sound/pcm.h><br>+#include <sound/soc.h><br>+#include <sound/soc-dapm.h><br>+<br>+#include "../codecs/ac97.h"<br>+#include "nuc900-auido.h"<br>
+<br>+static struct snd_soc_dai_link nuc900evb_ac97_dai = {<br>+ .name = "AC97",<br>+ .stream_name = "AC97 HiFi",<br>+ .cpu_dai = &nuc900_ac97_dai,<br>+ .codec_dai = &ac97_dai,<br>
+};<br>+<br>+static struct snd_soc_card nuc900evb_audio_machine = {<br>+ .name = "NUC900EVB_AC97",<br>+ .dai_link = &nuc900evb_ac97_dai,<br>+ .num_links = 1,<br>+ .platform = &nuc900_soc_platform,<br>
+};<br>+<br>+static struct snd_soc_device nuc900evb_ac97_devdata = {<br>+ .card = &nuc900evb_audio_machine,<br>+ .codec_dev = &soc_codec_dev_ac97,<br>+};<br>+<br>+static struct platform_device *nuc900evb_asoc_dev;<br>
+<br>+static int __init nuc900evb_audio_init(void)<br>+{<br>+ int ret;<br>+<br>+ ret = -ENOMEM;<br>+ nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1);<br>+ if (!nuc900evb_asoc_dev)<br>
+ goto out;<br>+<br>+ /* nuc900 board audio device */<br>+ platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);<br>+<br>+ nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;<br>
+ ret = platform_device_add(nuc900evb_asoc_dev);<br>+<br>+ if (ret) {<br>+ platform_device_put(nuc900evb_asoc_dev);<br>+ nuc900evb_asoc_dev = NULL;<br>+ }<br>+<br>+out:<br>+ return ret;<br>
+}<br>+<br>+static void __exit nuc900evb_audio_exit(void)<br>+{<br>+ platform_device_unregister(nuc900evb_asoc_dev);<br>+}<br>+<br>+module_init(nuc900evb_audio_init);<br>+module_exit(nuc900evb_audio_exit);<br>+<br>+MODULE_LICENSE("GPL");<br>
+MODULE_DESCRIPTION("NUC900 Series ASoC audio support");<br>+MODULE_AUTHOR("Wan ZongShun");<br>diff --git a/sound/soc/nuc900/nuc900-auido.h b/sound/soc/nuc900/nuc900-auido.h<br>new file mode 100644<br>
index 0000000..95ac4ef<br>--- /dev/null<br>+++ b/sound/soc/nuc900/nuc900-auido.h<br>@@ -0,0 +1,121 @@<br>+/*<br>+ * Copyright (c) 2010 Nuvoton technology corporation.<br>+ *<br>+ * Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>><br>
+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation;version 2 of the License.<br>
+ *<br>+ */<br>+<br>+#ifndef _NUC900_AUDIO_H<br>+#define _NUC900_AUDIO_H<br>+<br>+#include <linux/io.h><br>+<br>+/* Audio Control Registers */<br>+#define ACTL_CON 0x00<br>+#define ACTL_RESET 0x04<br>
+#define ACTL_RDSTB 0x08<br>+#define ACTL_RDST_LENGTH 0x0C<br>+#define ACTL_RDSTC 0x10<br>+#define ACTL_RSR 0x14<br>+#define ACTL_PDSTB 0x18<br>+#define ACTL_PDST_LENGTH 0x1C<br>
+#define ACTL_PDSTC 0x20<br>+#define ACTL_PSR 0x24<br>+#define ACTL_IISCON 0x28<br>+#define ACTL_ACCON 0x2C<br>+#define ACTL_ACOS0 0x30<br>+#define ACTL_ACOS1 0x34<br>
+#define ACTL_ACOS2 0x38<br>+#define ACTL_ACIS0 0x3C<br>+#define ACTL_ACIS1 0x40<br>+#define ACTL_ACIS2 0x44<br>+#define ACTL_COUNTER 0x48<br>+<br>+/* bit definition of REG_ACTL_CON register */<br>
+#define R_DMA_IRQ 0x1000<br>+#define T_DMA_IRQ 0x0800<br>+#define IIS_AC_PIN_SEL 0x0100<br>+#define FIFO_TH 0x0080<br>+#define ADC_EN 0x0010<br>+#define M80_EN 0x0008<br>
+#define ACLINK_EN 0x0004<br>+#define IIS_EN 0x0002<br>+<br>+/* bit definition of REG_ACTL_RESET register */<br>+#define W5691_PLAY 0x20000<br>+#define ACTL_RESET_BIT 0x10000<br>
+#define RECORD_RIGHT_CHNNEL 0x08000<br>+#define RECORD_LEFT_CHNNEL 0x04000<br>+#define PLAY_RIGHT_CHNNEL 0x02000<br>+#define PLAY_LEFT_CHNNEL 0x01000<br>+#define DAC_PLAY 0x00800<br>+#define ADC_RECORD 0x00400<br>
+#define M80_PLAY 0x00200<br>+#define AC_RECORD 0x00100<br>+#define AC_PLAY 0x00080<br>+#define IIS_RECORD 0x00040<br>+#define IIS_PLAY 0x00020<br>
+#define DAC_RESET 0x00010<br>+#define ADC_RESET 0x00008<br>+#define M80_RESET 0x00004<br>+#define AC_RESET 0x00002<br>+#define IIS_RESET 0x00001<br>+<br>+/* bit definition of REG_ACTL_ACCON register */<br>
+#define AC_BCLK_PU_EN 0x20<br>+#define AC_R_FINISH 0x10<br>+#define AC_W_FINISH 0x08<br>+#define AC_W_RES 0x04<br>+#define AC_C_RES 0x02<br>+<br>+/* bit definition of ACTL_RSR register */<br>
+#define R_FIFO_EMPTY 0x04<br>+#define R_DMA_END_IRQ 0x02<br>+#define R_DMA_MIDDLE_IRQ 0x01<br>+<br>+/* bit definition of ACTL_PSR register */<br>+#define P_FIFO_EMPTY 0x04<br>+#define P_DMA_END_IRQ 0x02<br>
+#define P_DMA_MIDDLE_IRQ 0x01<br>+<br>+/* bit definition of ACTL_ACOS0 register */<br>+#define SLOT1_VALID 0x01<br>+#define SLOT2_VALID 0x02<br>+#define SLOT3_VALID 0x04<br>+#define SLOT4_VALID 0x08<br>
+#define VALID_FRAME 0x10<br>+<br>+/* bit definition of ACTL_ACOS1 register */<br>+#define R_WB 0x80<br>+<br>+#define CODEC_READY 0x10<br>+#define RESET_PRSR 0x00<br>+#define AUDIO_WRITE(addr, val) __raw_writel(val, addr)<br>
+#define AUDIO_READ(addr) __raw_readl(addr)<br>+#define PCM_TX 0<br>+#define PCM_RX 1<br>+#define SUBSTREAM_TYPE(substream) \<br>+ ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)<br>
+<br>+struct nuc900_audio {<br>+ void __iomem *mmio;<br>+ spinlock_t lock;<br>+ dma_addr_t dma_addr[2];<br>+ unsigned long buffersize[2];<br>+ unsigned long irq_num;<br>+ struct snd_pcm_substream *substream;<br>
+ struct resource *res;<br>+ struct clk *clk;<br>+ struct device *dev;<br>+<br>+};<br>+<br>+extern struct nuc900_audio *nuc900_ac97_data;<br>+extern struct snd_soc_dai nuc900_ac97_dai;<br>+extern struct snd_soc_platform nuc900_soc_platform;<br>
+<br>+#endif /*end _NUC900_AUDIO_H */<br>diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c<br>new file mode 100644<br>index 0000000..32a503c<br>--- /dev/null<br>+++ b/sound/soc/nuc900/nuc900-pcm.c<br>
@@ -0,0 +1,352 @@<br>+/*<br>+ * Copyright (c) 2010 Nuvoton technology corporation.<br>+ *<br>+ * Wan ZongShun <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>><br>
+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation;version 2 of the License.<br>
+ *<br>+ */<br>+<br>+#include <linux/module.h><br>+#include <linux/init.h><br>+#include <linux/io.h><br>+#include <linux/platform_device.h><br>+#include <linux/slab.h><br>+#include <linux/dma-mapping.h><br>
+<br>+#include <sound/core.h><br>+#include <sound/pcm.h><br>+#include <sound/pcm_params.h><br>+#include <sound/soc.h><br>+<br>+#include <mach/hardware.h><br>+<br>+#include "nuc900-auido.h"<br>
+<br>+static const struct snd_pcm_hardware nuc900_pcm_hardware = {<br>+ .info = SNDRV_PCM_INFO_INTERLEAVED |<br>+ SNDRV_PCM_INFO_BLOCK_TRANSFER |<br>+ SNDRV_PCM_INFO_MMAP |<br>
+ SNDRV_PCM_INFO_MMAP_VALID |<br>+ SNDRV_PCM_INFO_PAUSE |<br>+ SNDRV_PCM_INFO_RESUME,<br>+ .formats = SNDRV_PCM_FMTBIT_S16_LE,<br>
+ .channels_min = 1,<br>+ .channels_max = 2,<br>+ .buffer_bytes_max = 4*1024,<br>+ .period_bytes_min = 1*1024,<br>+ .period_bytes_max = 4*1024,<br>+ .periods_min = 1,<br>
+ .periods_max = 1024,<br>+};<br>+<br>+static int nuc900_dma_hw_params(struct snd_pcm_substream *substream,<br>+ struct snd_pcm_hw_params *params)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>
+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ unsigned long flags, stype = SUBSTREAM_TYPE(substream);<br>+ int ret = 0;<br>+<br>+ spin_lock_irqsave(&nuc900_audio->lock, flags);<br>
+<br>+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));<br>+ if (ret < 0)<br>+ return ret;<br>+<br>+ nuc900_audio->substream = substream;<br>+ nuc900_audio->dma_addr[stype] = runtime->dma_addr;<br>
+ nuc900_audio->buffersize[stype] = params_buffer_bytes(params);<br>+<br>+ spin_unlock_irqrestore(&nuc900_audio->lock, flags);<br>+<br>+ return ret;<br>+}<br>+<br>+static void nuc900_update_dma_register(struct snd_pcm_substream *substream,<br>
+ dma_addr_t dma_addr, size_t count)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ void __iomem *mmio_addr, *mmio_len;<br>
+<br>+ if (SUBSTREAM_TYPE(substream) == PCM_TX) {<br>+ mmio_addr = nuc900_audio->mmio + ACTL_PDSTB;<br>+ mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH;<br>+ } else {<br>+ mmio_addr = nuc900_audio->mmio + ACTL_RDSTB;<br>
+ mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH;<br>+ }<br>+<br>+ AUDIO_WRITE(mmio_addr, dma_addr);<br>+ AUDIO_WRITE(mmio_len, count);<br>+}<br>+<br>+static void nuc900_dma_start(struct snd_pcm_substream *substream)<br>
+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ unsigned long val;<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);<br>
+ val |= (T_DMA_IRQ | R_DMA_IRQ);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);<br>+}<br>+<br>+static void nuc900_dma_stop(struct snd_pcm_substream *substream)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>
+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ unsigned long val;<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);<br>+ val &= ~(T_DMA_IRQ | R_DMA_IRQ);<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);<br>
+}<br>+<br>+static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id)<br>+{<br>+ struct snd_pcm_substream *substream = dev_id;<br>+ struct nuc900_audio *nuc900_audio = substream->runtime->private_data;<br>
+ unsigned long val;<br>+<br>+ spin_lock(&nuc900_audio->lock);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);<br>+<br>+ if (val & R_DMA_IRQ) {<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ);<br>
+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);<br>+<br>+ if (val & R_DMA_MIDDLE_IRQ) {<br>+ val |= R_DMA_MIDDLE_IRQ;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);<br>
+ }<br>+<br>+ if (val & R_DMA_END_IRQ) {<br>+ val |= R_DMA_END_IRQ;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);<br>+ }<br>
+ } else if (val & T_DMA_IRQ) {<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);<br>+<br>+ if (val & P_DMA_MIDDLE_IRQ) {<br>
+ val |= P_DMA_MIDDLE_IRQ;<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);<br>+ }<br>+<br>+ if (val & P_DMA_END_IRQ) {<br>+ val |= P_DMA_END_IRQ;<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);<br>+ }<br>+ } else {<br>+ dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n");<br>+ spin_unlock(&nuc900_audio->lock);<br>
+ return IRQ_HANDLED;<br>+ }<br>+<br>+ spin_unlock(&nuc900_audio->lock);<br>+<br>+ snd_pcm_period_elapsed(substream);<br>+<br>+ return IRQ_HANDLED;<br>+}<br>+<br>+static int nuc900_dma_hw_free(struct snd_pcm_substream *substream)<br>
+{<br>+ snd_pcm_lib_free_pages(substream);<br>+ return 0;<br>+}<br>+<br>+static int nuc900_dma_prepare(struct snd_pcm_substream *substream)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>
+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+ unsigned long flags, val, stype = SUBSTREAM_TYPE(substream);;<br>+<br>+ spin_lock_irqsave(&nuc900_audio->lock, flags);<br>+<br>
+ nuc900_update_dma_register(substream,<br>+ nuc900_audio->dma_addr[stype], nuc900_audio->buffersize[stype]);<br>+<br>+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);<br>+<br>+ switch (runtime->channels) {<br>
+ case 1:<br>+ if (PCM_TX == stype) {<br>+ val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);<br>+ val |= PLAY_RIGHT_CHNNEL;<br>+ } else {<br>
+ val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);<br>+ val |= RECORD_RIGHT_CHNNEL;<br>+ }<br>+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>
+ break;<br>+ case 2:<br>+ if (PCM_TX == stype)<br>+ val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);<br>+ else<br>+ val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);<br>
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);<br>+ break;<br>+ default:<br>+ return -EINVAL;<br>+ }<br>+ spin_unlock_irqrestore(&nuc900_audio->lock, flags);<br>
+ return 0;<br>+}<br>+<br>+static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd)<br>+{<br>+ int ret = 0;<br>+<br>+ switch (cmd) {<br>+ case SNDRV_PCM_TRIGGER_START:<br>+ case SNDRV_PCM_TRIGGER_RESUME:<br>
+ nuc900_dma_start(substream);<br>+ break;<br>+<br>+ case SNDRV_PCM_TRIGGER_STOP:<br>+ case SNDRV_PCM_TRIGGER_SUSPEND:<br>+ nuc900_dma_stop(substream);<br>+ break;<br>
+<br>+ default:<br>+ ret = -EINVAL;<br>+ break;<br>+ }<br>+<br>+ return ret;<br>+}<br>+<br>+int nuc900_dma_getposition(struct snd_pcm_substream *substream,<br>+ dma_addr_t *src, dma_addr_t *dst)<br>
+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>+<br>+ if (src != NULL)<br>+ *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC);<br>
+<br>+ if (dst != NULL)<br>+ *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC);<br>+<br>+ return 0;<br>+}<br>+<br>+static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream)<br>
+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ dma_addr_t src, dst;<br>+ unsigned long res;<br>+<br>+ nuc900_dma_getposition(substream, &src, &dst);<br>+<br>+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)<br>
+ res = dst - runtime->dma_addr;<br>+ else<br>+ res = src - runtime->dma_addr;<br>+<br>+ return bytes_to_frames(substream->runtime, res);<br>+}<br>+<br>+static int nuc900_dma_open(struct snd_pcm_substream *substream)<br>
+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio;<br>+<br>+ snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware);<br>+<br>+ nuc900_audio = nuc900_ac97_data;<br>
+<br>+ if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt,<br>+ IRQF_DISABLED, "nuc900-dma", substream))<br>+ return -EBUSY;<br>+<br>+ runtime->private_data = nuc900_audio;<br>
+<br>+ return 0;<br>+}<br>+<br>+static int nuc900_dma_close(struct snd_pcm_substream *substream)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>+ struct nuc900_audio *nuc900_audio = runtime->private_data;<br>
+<br>+ free_irq(nuc900_audio->irq_num, substream);<br>+<br>+ return 0;<br>+}<br>+<br>+static int nuc900_dma_mmap(struct snd_pcm_substream *substream,<br>+ struct vm_area_struct *vma)<br>+{<br>+ struct snd_pcm_runtime *runtime = substream->runtime;<br>
+<br>+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,<br>+ runtime->dma_area,<br>+ runtime->dma_addr,<br>+ runtime->dma_bytes);<br>
+}<br>+<br>+static struct snd_pcm_ops nuc900_dma_ops = {<br>+ .open = nuc900_dma_open,<br>+ .close = nuc900_dma_close,<br>+ .ioctl = snd_pcm_lib_ioctl,<br>+ .hw_params = nuc900_dma_hw_params,<br>
+ .hw_free = nuc900_dma_hw_free,<br>+ .prepare = nuc900_dma_prepare,<br>+ .trigger = nuc900_dma_trigger,<br>+ .pointer = nuc900_dma_pointer,<br>+ .mmap = nuc900_dma_mmap,<br>
+};<br>+<br>+static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)<br>+{<br>+ snd_pcm_lib_preallocate_free_for_all(pcm);<br>+}<br>+<br>+static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);<br>+static int nuc900_dma_new(struct snd_card *card,<br>
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)<br>+{<br>+ if (!card->dev->dma_mask)<br>+ card->dev->dma_mask = &nuc900_pcm_dmamask;<br>+ if (!card->dev->coherent_dma_mask)<br>
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);<br>+<br>+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,<br>+ card->dev, 4 * 1024, (4 * 1024) - 1);<br>+<br>+ return 0;<br>
+}<br>+<br>+struct snd_soc_platform nuc900_soc_platform = {<br>+ .name = "nuc900-dma",<br>+ .pcm_ops = &nuc900_dma_ops,<br>+ .pcm_new = nuc900_dma_new,<br>+ .pcm_free = nuc900_dma_free_dma_buffers,<br>
+}<br>+EXPORT_SYMBOL_GPL(nuc900_soc_platform);<br>+<br>+static int __init nuc900_soc_platform_init(void)<br>+{<br>+ return snd_soc_register_platform(&nuc900_soc_platform);<br>+}<br>+<br>+static void __exit nuc900_soc_platform_exit(void)<br>
+{<br>+ snd_soc_unregister_platform(&nuc900_soc_platform);<br>+}<br>+<br>+module_init(nuc900_soc_platform_init);<br>+module_exit(nuc900_soc_platform_exit);<br>+<br>+MODULE_AUTHOR("Wan ZongShun, <<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>>");<br>
+MODULE_DESCRIPTION("nuc900 Audio DMA module");<br>+MODULE_LICENSE("GPL");<br><font color="#888888">-- <br>1.6.3.3<br><br></font></blockquote></div><br><br clear="all"><br>-- <br>*linux-arm-kernel mailing list<br>
mail <a href="mailto:addr%3Alinux-arm-kernel@lists.infradead.org">addr:linux-arm-kernel@lists.infradead.org</a><br>you can subscribe by:<br><a href="http://lists.infradead.org/mailman/listinfo/linux-arm-kernel">http://lists.infradead.org/mailman/listinfo/linux-arm-kernel</a><br>
<br>* linux-arm-NUC900 mailing list<br>mail <a href="mailto:addr%3ANUC900@googlegroups.com">addr:NUC900@googlegroups.com</a><br>main web: <a href="https://groups.google.com/group/NUC900">https://groups.google.com/group/NUC900</a><br>
you can subscribe it by sending me mail:<br><a href="http://mcuos.com">mcuos.com</a>@<a href="http://gmail.com">gmail.com</a><br><br><br>