<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">&lt;<a href="http://mcuos.com">mcuos.com</a>@<a href="http://gmail.com">gmail.com</a>&gt;</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 &lt;zswan@zswan-marvell.(none)&gt;<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 &quot;sound/soc/blackfin/Kconfig&quot;<br>
 source &quot;sound/soc/davinci/Kconfig&quot;<br> source &quot;sound/soc/fsl/Kconfig&quot;<br> source &quot;sound/soc/imx/Kconfig&quot;<br>+source &quot;sound/soc/nuc900/Kconfig&quot;<br> source &quot;sound/soc/omap/Kconfig&quot;<br>
 source &quot;sound/soc/pxa/Kconfig&quot;<br> source &quot;sound/soc/s3c24xx/Kconfig&quot;<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 &lt;zswan@zswan-marvell.(none)&gt;<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 &quot;sound/soc/blackfin/Kconfig&quot;<br> source &quot;sound/soc/davinci/Kconfig&quot;<br>
 source &quot;sound/soc/fsl/Kconfig&quot;<br> source &quot;sound/soc/imx/Kconfig&quot;<br>+source &quot;sound/soc/nuc900/Kconfig&quot;<br> source &quot;sound/soc/omap/Kconfig&quot;<br> source &quot;sound/soc/pxa/Kconfig&quot;<br>
 source &quot;sound/soc/s3c24xx/Kconfig&quot;<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 &quot;SoC Audio for NUC900 series&quot;<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 &quot;NUC900 AC97 support for demo board&quot;<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 &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;<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 &lt;linux/init.h&gt;<br>+#include &lt;linux/module.h&gt;<br>+#include &lt;linux/slab.h&gt;<br>+#include &lt;linux/device.h&gt;<br>+#include &lt;linux/delay.h&gt;<br>+#include &lt;linux/mutex.h&gt;<br>
+#include &lt;linux/suspend.h&gt;<br>+#include &lt;sound/core.h&gt;<br>+#include &lt;sound/pcm.h&gt;<br>+#include &lt;sound/initval.h&gt;<br>+#include &lt;sound/soc.h&gt;<br>+#include &lt;linux/device.h&gt;<br>+#include &lt;linux/clk.h&gt;<br>
+<br>+#include &lt;mach/mfp.h&gt;<br>+<br>+#include &quot;nuc900-auido.h&quot;<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-&gt;mmio + ACTL_ACIS0) &amp; 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(&amp;ac97_mutex);<br>
+<br>+       val = nuc900_checkready();<br>+       if (!!val) {<br>+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 codec is not ready\n&quot;);<br>+               goto out;<br>+       }<br>+<br>+       /* set the R_WB bit and write register index */<br>
+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS1, R_WB | reg);<br>+<br>+       /* set the valid frame bit and valid slots */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>+       val |= (VALID_FRAME | SLOT1_VALID);<br>
+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, val);<br>+<br>+       udelay(100);<br>+<br>+       /* polling the AC_R_FINISH */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>+       val &amp;= AC_R_FINISH;<br>
+       while (!val &amp;&amp; timeout--)<br>+               mdelay(1);<br>+<br>+       if (!timeout) {<br>+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 read register time out !\n&quot;);<br>+               val = -EPERM;<br>
+               goto out;<br>+       }<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0) ;<br>+       val &amp;= ~SLOT1_VALID;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, val);<br>+<br>+       if (AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACIS1) &gt;&gt; 2 != reg) {<br>
+               dev_err(nuc900_audio-&gt;dev,<br>+                               &quot;R_INDEX of REG_ACTL_ACIS1 not match!\n&quot;);<br>+       }<br>+<br>+       udelay(100);<br>+       val = (AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACIS2) &amp; 0xFFFF);<br>
+<br>+out:<br>+       mutex_unlock(&amp;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(&amp;ac97_mutex);<br>+<br>+       tmp = nuc900_checkready();<br>+       if (!!tmp)<br>
+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 codec is not ready\n&quot;);<br>+<br>+       /* clear the R_WB bit and write register index */<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS1, reg);<br>+<br>
+       /* write register value */<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS2, val);<br>+<br>+       /* set the valid frame bit and valid slots */<br>+       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>
+       tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, tmp);<br>+<br>+       udelay(100);<br>+<br>+       /* polling the AC_W_FINISH */<br>+       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>
+       tmp &amp;= AC_W_FINISH;<br>+       while (tmp &amp;&amp; timeout--)<br>+               mdelay(1);<br>+<br>+       if (!timeout)<br>+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 write register time out !\n&quot;);<br>
+<br>+       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>+       tmp &amp;= ~(SLOT1_VALID | SLOT2_VALID);<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, tmp);<br>+<br>+       mutex_unlock(&amp;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(&amp;ac97_mutex);<br>
+<br>+       /* warm reset AC 97 */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>+       val |= AC_W_RES;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACCON, val);<br>+<br>+       udelay(1000);<br>
+<br>+       val = nuc900_checkready();<br>+       if (!!val)<br>+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 codec is not ready\n&quot;);<br>+<br>+       mutex_unlock(&amp;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(&amp;ac97_mutex);<br>+<br>+       /* reset Audio Controller */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>
+       val |= ACTL_RESET_BIT;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RESET, val);<br>+<br>+       udelay(1000);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>+       val &amp;= (~ACTL_RESET_BIT);<br>
+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RESET, val);<br>+<br>+       udelay(1000);<br>+<br>+       /* reset AC-link interface */<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>+       val |= AC_RESET;<br>
+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RESET, val);<br>+<br>+       udelay(1000);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>+       val &amp;= ~AC_RESET;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RESET, val);<br>
+<br>+       udelay(1000);<br>+<br>+       /* cold reset AC 97 */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>+       val |= AC_C_RES;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACCON, val);<br>
+<br>+       udelay(1000);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>+       val &amp;= (~AC_C_RES);<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACCON, val);<br>+<br>+       udelay(1000);<br>
+<br>+       mutex_unlock(&amp;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-&gt;mmio + ACTL_RESET);<br>+               if (PCM_TX == stype) {<br>
+                       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>+                       tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME);<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, tmp);<br>
+<br>+                       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_PSR);<br>+                       tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ);<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_PSR, tmp);<br>
+                       val |= AC_PLAY;<br>+               } else {<br>+                       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RSR);<br>+                       tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ);<br>+<br>
+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RSR, tmp);<br>+                       val |= AC_RECORD;<br>+               }<br>+<br>+               AUDIO_WRITE(nuc900_audio-&gt;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-&gt;mmio + ACTL_RESET);<br>+               if (PCM_TX == stype) {<br>
+                       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>+                       tmp &amp;= ~(SLOT3_VALID | SLOT4_VALID);<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, tmp);<br>
+<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_PSR, RESET_PRSR);<br>+                       val &amp;= ~AC_PLAY;<br>+               } else {<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RSR, RESET_PRSR);<br>
+                       val &amp;= ~AC_RECORD;<br>+               }<br>+<br>+               AUDIO_WRITE(nuc900_audio-&gt;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(&amp;ac97_mutex);<br>+<br>+       /* enable unit clock */<br>+       clk_enable(nuc900_audio-&gt;clk);<br>+<br>+       /* enable audio controller and AC-link interface */<br>
+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_CON);<br>+       val |= (IIS_AC_PIN_SEL | ACLINK_EN);<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_CON, val);<br>+<br>+       mutex_unlock(&amp;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-&gt;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                   = &quot;nuc900-ac97&quot;,<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 = &amp;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(&amp;nuc900_audio-&gt;lock);<br>
+<br>+       nuc900_audio-&gt;res = platform_get_resource(pdev, IORESOURCE_MEM, 0);<br>+       if (!nuc900_audio-&gt;res) {<br>+               ret = -ENODEV;<br>+               goto out0;<br>+       }<br>+<br>+       if (!request_mem_region(nuc900_audio-&gt;res-&gt;start,<br>
+                       resource_size(nuc900_audio-&gt;res), pdev-&gt;name)) {<br>+               ret = -EBUSY;<br>+               goto out0;<br>+       }<br>+<br>+       nuc900_audio-&gt;mmio = ioremap(nuc900_audio-&gt;res-&gt;start,<br>
+                                       resource_size(nuc900_audio-&gt;res));<br>+       if (!nuc900_audio-&gt;mmio) {<br>+               ret = -ENOMEM;<br>+               goto out1;<br>+       }<br>+<br>+       nuc900_audio-&gt;clk = clk_get(&amp;pdev-&gt;dev, NULL);<br>
+       if (IS_ERR(nuc900_audio-&gt;clk)) {<br>+               ret = PTR_ERR(nuc900_audio-&gt;clk);<br>+               goto out2;<br>+       }<br>+<br>+       nuc900_audio-&gt;irq_num = platform_get_irq(pdev, 0);<br>+       if (!nuc900_audio-&gt;irq_num) {<br>
+               ret = -EBUSY;<br>+               goto out2;<br>+       }<br>+<br>+       nuc900_ac97_data = nuc900_audio;<br>+<br>+       nuc900_audio-&gt;dev = nuc900_ac97_dai.dev =  &amp;pdev-&gt;dev;<br>+<br>+       ret = snd_soc_register_dai(&amp;nuc900_ac97_dai);<br>
+       if (ret)<br>+               goto out3;<br>+<br>+       mfp_set_groupg(nuc900_audio-&gt;dev); /* enbale ac97 multifunction pin*/<br>+<br>+       return 0;<br>+<br>+out3:<br>+       clk_put(nuc900_audio-&gt;clk);<br>
+out2:<br>+       iounmap(nuc900_audio-&gt;mmio);<br>+out1:<br>+       release_mem_region(nuc900_audio-&gt;res-&gt;start,<br>+                                       resource_size(nuc900_audio-&gt;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(&amp;nuc900_ac97_dai);<br>+<br>+       clk_put(nuc900_ac97_data-&gt;clk);<br>
+       iounmap(nuc900_ac97_data-&gt;mmio);<br>+       release_mem_region(nuc900_ac97_data-&gt;res-&gt;start,<br>+                               resource_size(nuc900_ac97_data-&gt;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   = &quot;nuc900-audio&quot;,<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(&amp;nuc900_ac97_driver);<br>
+}<br>+<br>+static void __exit nuc900_ac97_exit(void)<br>+{<br>+       platform_driver_unregister(&amp;nuc900_ac97_driver);<br>+}<br>+<br>+module_init(nuc900_ac97_init);<br>+module_exit(nuc900_ac97_exit);<br>+<br>+MODULE_AUTHOR(&quot;Wan ZongShun &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;&quot;);<br>
+MODULE_DESCRIPTION(&quot;NUC900 AC97 SoC driver!&quot;);<br>+MODULE_LICENSE(&quot;GPL&quot;);<br>+MODULE_ALIAS(&quot;platform:nuc900-ac97&quot;);<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 &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;<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 &lt;linux/module.h&gt;<br>+#include &lt;linux/moduleparam.h&gt;<br>+#include &lt;linux/timer.h&gt;<br>+#include &lt;linux/interrupt.h&gt;<br>+#include &lt;linux/platform_device.h&gt;<br>+<br>
+#include &lt;sound/core.h&gt;<br>+#include &lt;sound/pcm.h&gt;<br>+#include &lt;sound/soc.h&gt;<br>+#include &lt;sound/soc-dapm.h&gt;<br>+<br>+#include &quot;../codecs/ac97.h&quot;<br>+#include &quot;nuc900-auido.h&quot;<br>
+<br>+static struct snd_soc_dai_link nuc900evb_ac97_dai = {<br>+       .name           = &quot;AC97&quot;,<br>+       .stream_name    = &quot;AC97 HiFi&quot;,<br>+       .cpu_dai        = &amp;nuc900_ac97_dai,<br>+       .codec_dai      = &amp;ac97_dai,<br>
+};<br>+<br>+static struct snd_soc_card nuc900evb_audio_machine = {<br>+       .name           = &quot;NUC900EVB_AC97&quot;,<br>+       .dai_link       = &amp;nuc900evb_ac97_dai,<br>+       .num_links      = 1,<br>+       .platform       = &amp;nuc900_soc_platform,<br>
+};<br>+<br>+static struct snd_soc_device nuc900evb_ac97_devdata = {<br>+       .card           = &amp;nuc900evb_audio_machine,<br>+       .codec_dev      = &amp;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(&quot;soc-audio&quot;, -1);<br>+       if (!nuc900evb_asoc_dev)<br>
+               goto out;<br>+<br>+       /* nuc900 board audio device */<br>+       platform_set_drvdata(nuc900evb_asoc_dev, &amp;nuc900evb_ac97_devdata);<br>+<br>+       nuc900evb_ac97_devdata.dev = &amp;nuc900evb_asoc_dev-&gt;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(&quot;GPL&quot;);<br>
+MODULE_DESCRIPTION(&quot;NUC900 Series ASoC audio support&quot;);<br>+MODULE_AUTHOR(&quot;Wan ZongShun&quot;);<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 &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;<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 &lt;linux/io.h&gt;<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)-&gt;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 &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;<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 &lt;linux/module.h&gt;<br>+#include &lt;linux/init.h&gt;<br>+#include &lt;linux/io.h&gt;<br>+#include &lt;linux/platform_device.h&gt;<br>+#include &lt;linux/slab.h&gt;<br>+#include &lt;linux/dma-mapping.h&gt;<br>
+<br>+#include &lt;sound/core.h&gt;<br>+#include &lt;sound/pcm.h&gt;<br>+#include &lt;sound/pcm_params.h&gt;<br>+#include &lt;sound/soc.h&gt;<br>+<br>+#include &lt;mach/hardware.h&gt;<br>+<br>+#include &quot;nuc900-auido.h&quot;<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-&gt;runtime;<br>
+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       unsigned long flags, stype = SUBSTREAM_TYPE(substream);<br>+       int ret = 0;<br>+<br>+       spin_lock_irqsave(&amp;nuc900_audio-&gt;lock, flags);<br>
+<br>+       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));<br>+       if (ret &lt; 0)<br>+               return ret;<br>+<br>+       nuc900_audio-&gt;substream = substream;<br>+       nuc900_audio-&gt;dma_addr[stype] = runtime-&gt;dma_addr;<br>
+       nuc900_audio-&gt;buffersize[stype] = params_buffer_bytes(params);<br>+<br>+       spin_unlock_irqrestore(&amp;nuc900_audio-&gt;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-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       void __iomem *mmio_addr, *mmio_len;<br>
+<br>+       if (SUBSTREAM_TYPE(substream) == PCM_TX) {<br>+               mmio_addr = nuc900_audio-&gt;mmio + ACTL_PDSTB;<br>+               mmio_len = nuc900_audio-&gt;mmio + ACTL_PDST_LENGTH;<br>+       } else {<br>+               mmio_addr = nuc900_audio-&gt;mmio + ACTL_RDSTB;<br>
+               mmio_len = nuc900_audio-&gt;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-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       unsigned long val;<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_CON);<br>
+       val |= (T_DMA_IRQ | R_DMA_IRQ);<br>+       AUDIO_WRITE(nuc900_audio-&gt;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-&gt;runtime;<br>
+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       unsigned long val;<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_CON);<br>+       val &amp;= ~(T_DMA_IRQ | R_DMA_IRQ);<br>+       AUDIO_WRITE(nuc900_audio-&gt;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-&gt;runtime-&gt;private_data;<br>
+       unsigned long val;<br>+<br>+       spin_lock(&amp;nuc900_audio-&gt;lock);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_CON);<br>+<br>+       if (val &amp; R_DMA_IRQ) {<br>+               AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_CON, val | R_DMA_IRQ);<br>
+<br>+               val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RSR);<br>+<br>+               if (val &amp; R_DMA_MIDDLE_IRQ) {<br>+                       val |= R_DMA_MIDDLE_IRQ;<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RSR, val);<br>
+               }<br>+<br>+               if (val &amp; R_DMA_END_IRQ) {<br>+                       val |= R_DMA_END_IRQ;<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RSR, val);<br>+               }<br>
+       } else if (val &amp; T_DMA_IRQ) {<br>+               AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_CON, val | T_DMA_IRQ);<br>+<br>+               val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_PSR);<br>+<br>+               if (val &amp; P_DMA_MIDDLE_IRQ) {<br>
+                       val |= P_DMA_MIDDLE_IRQ;<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_PSR, val);<br>+               }<br>+<br>+               if (val &amp; P_DMA_END_IRQ) {<br>+                       val |= P_DMA_END_IRQ;<br>
+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_PSR, val);<br>+               }<br>+       } else {<br>+               dev_err(nuc900_audio-&gt;dev, &quot;Wrong DMA interrupt status!\n&quot;);<br>+               spin_unlock(&amp;nuc900_audio-&gt;lock);<br>
+               return IRQ_HANDLED;<br>+       }<br>+<br>+       spin_unlock(&amp;nuc900_audio-&gt;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-&gt;runtime;<br>
+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       unsigned long flags, val, stype = SUBSTREAM_TYPE(substream);;<br>+<br>+       spin_lock_irqsave(&amp;nuc900_audio-&gt;lock, flags);<br>+<br>
+       nuc900_update_dma_register(substream,<br>+               nuc900_audio-&gt;dma_addr[stype], nuc900_audio-&gt;buffersize[stype]);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>+<br>+       switch (runtime-&gt;channels) {<br>
+       case 1:<br>+               if (PCM_TX == stype) {<br>+                       val &amp;= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);<br>+                       val |= PLAY_RIGHT_CHNNEL;<br>+               } else {<br>
+                       val &amp;= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);<br>+                       val |= RECORD_RIGHT_CHNNEL;<br>+               }<br>+               AUDIO_WRITE(nuc900_audio-&gt;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-&gt;mmio + ACTL_RESET, val);<br>+               break;<br>+       default:<br>+               return -EINVAL;<br>+       }<br>+       spin_unlock_irqrestore(&amp;nuc900_audio-&gt;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-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+<br>+       if (src != NULL)<br>+               *src = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_PDSTC);<br>
+<br>+       if (dst != NULL)<br>+               *dst = AUDIO_READ(nuc900_audio-&gt;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-&gt;runtime;<br>+       dma_addr_t src, dst;<br>+       unsigned long res;<br>+<br>+       nuc900_dma_getposition(substream, &amp;src, &amp;dst);<br>+<br>+       if (substream-&gt;stream == SNDRV_PCM_STREAM_CAPTURE)<br>
+               res = dst - runtime-&gt;dma_addr;<br>+       else<br>+               res = src - runtime-&gt;dma_addr;<br>+<br>+       return bytes_to_frames(substream-&gt;runtime, res);<br>+}<br>+<br>+static int nuc900_dma_open(struct snd_pcm_substream *substream)<br>
+{<br>+       struct snd_pcm_runtime *runtime = substream-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio;<br>+<br>+       snd_soc_set_runtime_hwparams(substream, &amp;nuc900_pcm_hardware);<br>+<br>+       nuc900_audio = nuc900_ac97_data;<br>
+<br>+       if (request_irq(nuc900_audio-&gt;irq_num, nuc900_dma_interrupt,<br>+                       IRQF_DISABLED, &quot;nuc900-dma&quot;, substream))<br>+               return -EBUSY;<br>+<br>+       runtime-&gt;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-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>
+<br>+       free_irq(nuc900_audio-&gt;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-&gt;runtime;<br>
+<br>+       return dma_mmap_writecombine(substream-&gt;pcm-&gt;card-&gt;dev, vma,<br>+                                       runtime-&gt;dma_area,<br>+                                       runtime-&gt;dma_addr,<br>+                                       runtime-&gt;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-&gt;dev-&gt;dma_mask)<br>+               card-&gt;dev-&gt;dma_mask = &amp;nuc900_pcm_dmamask;<br>+       if (!card-&gt;dev-&gt;coherent_dma_mask)<br>
+               card-&gt;dev-&gt;coherent_dma_mask = DMA_BIT_MASK(32);<br>+<br>+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,<br>+               card-&gt;dev, 4 * 1024, (4 * 1024) - 1);<br>+<br>+       return 0;<br>
+}<br>+<br>+struct snd_soc_platform nuc900_soc_platform = {<br>+       .name           = &quot;nuc900-dma&quot;,<br>+       .pcm_ops        = &amp;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(&amp;nuc900_soc_platform);<br>+}<br>+<br>+static void __exit nuc900_soc_platform_exit(void)<br>
+{<br>+       snd_soc_unregister_platform(&amp;nuc900_soc_platform);<br>+}<br>+<br>+module_init(nuc900_soc_platform_init);<br>+module_exit(nuc900_soc_platform_exit);<br>+<br>+MODULE_AUTHOR(&quot;Wan ZongShun, &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;&quot;);<br>
+MODULE_DESCRIPTION(&quot;nuc900 Audio DMA module&quot;);<br>+MODULE_LICENSE(&quot;GPL&quot;);<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 &quot;SoC Audio for NUC900 series&quot;<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 &quot;NUC900 AC97 support for demo board&quot;<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 &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;<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 &lt;linux/init.h&gt;<br>+#include &lt;linux/module.h&gt;<br>+#include &lt;linux/slab.h&gt;<br>+#include &lt;linux/device.h&gt;<br>+#include &lt;linux/delay.h&gt;<br>+#include &lt;linux/mutex.h&gt;<br>
+#include &lt;linux/suspend.h&gt;<br>+#include &lt;sound/core.h&gt;<br>+#include &lt;sound/pcm.h&gt;<br>+#include &lt;sound/initval.h&gt;<br>+#include &lt;sound/soc.h&gt;<br>+#include &lt;linux/device.h&gt;<br>+#include &lt;linux/clk.h&gt;<br>
+<br>+#include &lt;mach/mfp.h&gt;<br>+<br>+#include &quot;nuc900-auido.h&quot;<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-&gt;mmio + ACTL_ACIS0) &amp; 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(&amp;ac97_mutex);<br>
+<br>+       val = nuc900_checkready();<br>+       if (!!val) {<br>+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 codec is not ready\n&quot;);<br>+               goto out;<br>+       }<br>+<br>+       /* set the R_WB bit and write register index */<br>
+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS1, R_WB | reg);<br>+<br>+       /* set the valid frame bit and valid slots */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>+       val |= (VALID_FRAME | SLOT1_VALID);<br>
+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, val);<br>+<br>+       udelay(100);<br>+<br>+       /* polling the AC_R_FINISH */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>+       val &amp;= AC_R_FINISH;<br>
+       while (!val &amp;&amp; timeout--)<br>+               mdelay(1);<br>+<br>+       if (!timeout) {<br>+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 read register time out !\n&quot;);<br>+               val = -EPERM;<br>
+               goto out;<br>+       }<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0) ;<br>+       val &amp;= ~SLOT1_VALID;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, val);<br>+<br>+       if (AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACIS1) &gt;&gt; 2 != reg) {<br>
+               dev_err(nuc900_audio-&gt;dev,<br>+                               &quot;R_INDEX of REG_ACTL_ACIS1 not match!\n&quot;);<br>+       }<br>+<br>+       udelay(100);<br>+       val = (AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACIS2) &amp; 0xFFFF);<br>
+<br>+out:<br>+       mutex_unlock(&amp;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(&amp;ac97_mutex);<br>+<br>+       tmp = nuc900_checkready();<br>+       if (!!tmp)<br>
+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 codec is not ready\n&quot;);<br>+<br>+       /* clear the R_WB bit and write register index */<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS1, reg);<br>+<br>
+       /* write register value */<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS2, val);<br>+<br>+       /* set the valid frame bit and valid slots */<br>+       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>
+       tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, tmp);<br>+<br>+       udelay(100);<br>+<br>+       /* polling the AC_W_FINISH */<br>+       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>
+       tmp &amp;= AC_W_FINISH;<br>+       while (tmp &amp;&amp; timeout--)<br>+               mdelay(1);<br>+<br>+       if (!timeout)<br>+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 write register time out !\n&quot;);<br>
+<br>+       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>+       tmp &amp;= ~(SLOT1_VALID | SLOT2_VALID);<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, tmp);<br>+<br>+       mutex_unlock(&amp;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(&amp;ac97_mutex);<br>
+<br>+       /* warm reset AC 97 */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>+       val |= AC_W_RES;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACCON, val);<br>+<br>+       udelay(1000);<br>
+<br>+       val = nuc900_checkready();<br>+       if (!!val)<br>+               dev_err(nuc900_audio-&gt;dev, &quot;AC97 codec is not ready\n&quot;);<br>+<br>+       mutex_unlock(&amp;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(&amp;ac97_mutex);<br>+<br>+       /* reset Audio Controller */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>
+       val |= ACTL_RESET_BIT;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RESET, val);<br>+<br>+       udelay(1000);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>+       val &amp;= (~ACTL_RESET_BIT);<br>
+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RESET, val);<br>+<br>+       udelay(1000);<br>+<br>+       /* reset AC-link interface */<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>+       val |= AC_RESET;<br>
+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RESET, val);<br>+<br>+       udelay(1000);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>+       val &amp;= ~AC_RESET;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RESET, val);<br>
+<br>+       udelay(1000);<br>+<br>+       /* cold reset AC 97 */<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>+       val |= AC_C_RES;<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACCON, val);<br>
+<br>+       udelay(1000);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACCON);<br>+       val &amp;= (~AC_C_RES);<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACCON, val);<br>+<br>+       udelay(1000);<br>
+<br>+       mutex_unlock(&amp;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-&gt;mmio + ACTL_RESET);<br>+               if (PCM_TX == stype) {<br>
+                       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>+                       tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME);<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, tmp);<br>
+<br>+                       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_PSR);<br>+                       tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ);<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_PSR, tmp);<br>
+                       val |= AC_PLAY;<br>+               } else {<br>+                       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RSR);<br>+                       tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ);<br>+<br>
+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RSR, tmp);<br>+                       val |= AC_RECORD;<br>+               }<br>+<br>+               AUDIO_WRITE(nuc900_audio-&gt;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-&gt;mmio + ACTL_RESET);<br>+               if (PCM_TX == stype) {<br>
+                       tmp = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_ACOS0);<br>+                       tmp &amp;= ~(SLOT3_VALID | SLOT4_VALID);<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_ACOS0, tmp);<br>
+<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_PSR, RESET_PRSR);<br>+                       val &amp;= ~AC_PLAY;<br>+               } else {<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RSR, RESET_PRSR);<br>
+                       val &amp;= ~AC_RECORD;<br>+               }<br>+<br>+               AUDIO_WRITE(nuc900_audio-&gt;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(&amp;ac97_mutex);<br>+<br>+       /* enable unit clock */<br>+       clk_enable(nuc900_audio-&gt;clk);<br>+<br>+       /* enable audio controller and AC-link interface */<br>
+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_CON);<br>+       val |= (IIS_AC_PIN_SEL | ACLINK_EN);<br>+       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_CON, val);<br>+<br>+       mutex_unlock(&amp;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-&gt;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                   = &quot;nuc900-ac97&quot;,<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 = &amp;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(&amp;nuc900_audio-&gt;lock);<br>
+<br>+       nuc900_audio-&gt;res = platform_get_resource(pdev, IORESOURCE_MEM, 0);<br>+       if (!nuc900_audio-&gt;res) {<br>+               ret = -ENODEV;<br>+               goto out0;<br>+       }<br>+<br>+       if (!request_mem_region(nuc900_audio-&gt;res-&gt;start,<br>
+                       resource_size(nuc900_audio-&gt;res), pdev-&gt;name)) {<br>+               ret = -EBUSY;<br>+               goto out0;<br>+       }<br>+<br>+       nuc900_audio-&gt;mmio = ioremap(nuc900_audio-&gt;res-&gt;start,<br>
+                                       resource_size(nuc900_audio-&gt;res));<br>+       if (!nuc900_audio-&gt;mmio) {<br>+               ret = -ENOMEM;<br>+               goto out1;<br>+       }<br>+<br>+       nuc900_audio-&gt;clk = clk_get(&amp;pdev-&gt;dev, NULL);<br>
+       if (IS_ERR(nuc900_audio-&gt;clk)) {<br>+               ret = PTR_ERR(nuc900_audio-&gt;clk);<br>+               goto out2;<br>+       }<br>+<br>+       nuc900_audio-&gt;irq_num = platform_get_irq(pdev, 0);<br>+       if (!nuc900_audio-&gt;irq_num) {<br>
+               ret = -EBUSY;<br>+               goto out2;<br>+       }<br>+<br>+       nuc900_ac97_data = nuc900_audio;<br>+<br>+       nuc900_audio-&gt;dev = nuc900_ac97_dai.dev =  &amp;pdev-&gt;dev;<br>+<br>+       ret = snd_soc_register_dai(&amp;nuc900_ac97_dai);<br>
+       if (ret)<br>+               goto out3;<br>+<br>+       mfp_set_groupg(nuc900_audio-&gt;dev); /* enbale ac97 multifunction pin*/<br>+<br>+       return 0;<br>+<br>+out3:<br>+       clk_put(nuc900_audio-&gt;clk);<br>
+out2:<br>+       iounmap(nuc900_audio-&gt;mmio);<br>+out1:<br>+       release_mem_region(nuc900_audio-&gt;res-&gt;start,<br>+                                       resource_size(nuc900_audio-&gt;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(&amp;nuc900_ac97_dai);<br>+<br>+       clk_put(nuc900_ac97_data-&gt;clk);<br>
+       iounmap(nuc900_ac97_data-&gt;mmio);<br>+       release_mem_region(nuc900_ac97_data-&gt;res-&gt;start,<br>+                               resource_size(nuc900_ac97_data-&gt;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   = &quot;nuc900-audio&quot;,<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(&amp;nuc900_ac97_driver);<br>
+}<br>+<br>+static void __exit nuc900_ac97_exit(void)<br>+{<br>+       platform_driver_unregister(&amp;nuc900_ac97_driver);<br>+}<br>+<br>+module_init(nuc900_ac97_init);<br>+module_exit(nuc900_ac97_exit);<br>+<br>+MODULE_AUTHOR(&quot;Wan ZongShun &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;&quot;);<br>
+MODULE_DESCRIPTION(&quot;NUC900 AC97 SoC driver!&quot;);<br>+MODULE_LICENSE(&quot;GPL&quot;);<br>+MODULE_ALIAS(&quot;platform:nuc900-ac97&quot;);<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 &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;<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 &lt;linux/module.h&gt;<br>+#include &lt;linux/moduleparam.h&gt;<br>+#include &lt;linux/timer.h&gt;<br>+#include &lt;linux/interrupt.h&gt;<br>+#include &lt;linux/platform_device.h&gt;<br>+<br>
+#include &lt;sound/core.h&gt;<br>+#include &lt;sound/pcm.h&gt;<br>+#include &lt;sound/soc.h&gt;<br>+#include &lt;sound/soc-dapm.h&gt;<br>+<br>+#include &quot;../codecs/ac97.h&quot;<br>+#include &quot;nuc900-auido.h&quot;<br>
+<br>+static struct snd_soc_dai_link nuc900evb_ac97_dai = {<br>+       .name           = &quot;AC97&quot;,<br>+       .stream_name    = &quot;AC97 HiFi&quot;,<br>+       .cpu_dai        = &amp;nuc900_ac97_dai,<br>+       .codec_dai      = &amp;ac97_dai,<br>
+};<br>+<br>+static struct snd_soc_card nuc900evb_audio_machine = {<br>+       .name           = &quot;NUC900EVB_AC97&quot;,<br>+       .dai_link       = &amp;nuc900evb_ac97_dai,<br>+       .num_links      = 1,<br>+       .platform       = &amp;nuc900_soc_platform,<br>
+};<br>+<br>+static struct snd_soc_device nuc900evb_ac97_devdata = {<br>+       .card           = &amp;nuc900evb_audio_machine,<br>+       .codec_dev      = &amp;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(&quot;soc-audio&quot;, -1);<br>+       if (!nuc900evb_asoc_dev)<br>
+               goto out;<br>+<br>+       /* nuc900 board audio device */<br>+       platform_set_drvdata(nuc900evb_asoc_dev, &amp;nuc900evb_ac97_devdata);<br>+<br>+       nuc900evb_ac97_devdata.dev = &amp;nuc900evb_asoc_dev-&gt;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(&quot;GPL&quot;);<br>
+MODULE_DESCRIPTION(&quot;NUC900 Series ASoC audio support&quot;);<br>+MODULE_AUTHOR(&quot;Wan ZongShun&quot;);<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 &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;<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 &lt;linux/io.h&gt;<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)-&gt;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 &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;<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 &lt;linux/module.h&gt;<br>+#include &lt;linux/init.h&gt;<br>+#include &lt;linux/io.h&gt;<br>+#include &lt;linux/platform_device.h&gt;<br>+#include &lt;linux/slab.h&gt;<br>+#include &lt;linux/dma-mapping.h&gt;<br>
+<br>+#include &lt;sound/core.h&gt;<br>+#include &lt;sound/pcm.h&gt;<br>+#include &lt;sound/pcm_params.h&gt;<br>+#include &lt;sound/soc.h&gt;<br>+<br>+#include &lt;mach/hardware.h&gt;<br>+<br>+#include &quot;nuc900-auido.h&quot;<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-&gt;runtime;<br>
+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       unsigned long flags, stype = SUBSTREAM_TYPE(substream);<br>+       int ret = 0;<br>+<br>+       spin_lock_irqsave(&amp;nuc900_audio-&gt;lock, flags);<br>
+<br>+       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));<br>+       if (ret &lt; 0)<br>+               return ret;<br>+<br>+       nuc900_audio-&gt;substream = substream;<br>+       nuc900_audio-&gt;dma_addr[stype] = runtime-&gt;dma_addr;<br>
+       nuc900_audio-&gt;buffersize[stype] = params_buffer_bytes(params);<br>+<br>+       spin_unlock_irqrestore(&amp;nuc900_audio-&gt;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-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       void __iomem *mmio_addr, *mmio_len;<br>
+<br>+       if (SUBSTREAM_TYPE(substream) == PCM_TX) {<br>+               mmio_addr = nuc900_audio-&gt;mmio + ACTL_PDSTB;<br>+               mmio_len = nuc900_audio-&gt;mmio + ACTL_PDST_LENGTH;<br>+       } else {<br>+               mmio_addr = nuc900_audio-&gt;mmio + ACTL_RDSTB;<br>
+               mmio_len = nuc900_audio-&gt;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-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       unsigned long val;<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_CON);<br>
+       val |= (T_DMA_IRQ | R_DMA_IRQ);<br>+       AUDIO_WRITE(nuc900_audio-&gt;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-&gt;runtime;<br>
+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       unsigned long val;<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_CON);<br>+       val &amp;= ~(T_DMA_IRQ | R_DMA_IRQ);<br>+       AUDIO_WRITE(nuc900_audio-&gt;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-&gt;runtime-&gt;private_data;<br>
+       unsigned long val;<br>+<br>+       spin_lock(&amp;nuc900_audio-&gt;lock);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_CON);<br>+<br>+       if (val &amp; R_DMA_IRQ) {<br>+               AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_CON, val | R_DMA_IRQ);<br>
+<br>+               val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RSR);<br>+<br>+               if (val &amp; R_DMA_MIDDLE_IRQ) {<br>+                       val |= R_DMA_MIDDLE_IRQ;<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RSR, val);<br>
+               }<br>+<br>+               if (val &amp; R_DMA_END_IRQ) {<br>+                       val |= R_DMA_END_IRQ;<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_RSR, val);<br>+               }<br>
+       } else if (val &amp; T_DMA_IRQ) {<br>+               AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_CON, val | T_DMA_IRQ);<br>+<br>+               val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_PSR);<br>+<br>+               if (val &amp; P_DMA_MIDDLE_IRQ) {<br>
+                       val |= P_DMA_MIDDLE_IRQ;<br>+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_PSR, val);<br>+               }<br>+<br>+               if (val &amp; P_DMA_END_IRQ) {<br>+                       val |= P_DMA_END_IRQ;<br>
+                       AUDIO_WRITE(nuc900_audio-&gt;mmio + ACTL_PSR, val);<br>+               }<br>+       } else {<br>+               dev_err(nuc900_audio-&gt;dev, &quot;Wrong DMA interrupt status!\n&quot;);<br>+               spin_unlock(&amp;nuc900_audio-&gt;lock);<br>
+               return IRQ_HANDLED;<br>+       }<br>+<br>+       spin_unlock(&amp;nuc900_audio-&gt;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-&gt;runtime;<br>
+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+       unsigned long flags, val, stype = SUBSTREAM_TYPE(substream);;<br>+<br>+       spin_lock_irqsave(&amp;nuc900_audio-&gt;lock, flags);<br>+<br>
+       nuc900_update_dma_register(substream,<br>+               nuc900_audio-&gt;dma_addr[stype], nuc900_audio-&gt;buffersize[stype]);<br>+<br>+       val = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_RESET);<br>+<br>+       switch (runtime-&gt;channels) {<br>
+       case 1:<br>+               if (PCM_TX == stype) {<br>+                       val &amp;= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);<br>+                       val |= PLAY_RIGHT_CHNNEL;<br>+               } else {<br>
+                       val &amp;= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);<br>+                       val |= RECORD_RIGHT_CHNNEL;<br>+               }<br>+               AUDIO_WRITE(nuc900_audio-&gt;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-&gt;mmio + ACTL_RESET, val);<br>+               break;<br>+       default:<br>+               return -EINVAL;<br>+       }<br>+       spin_unlock_irqrestore(&amp;nuc900_audio-&gt;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-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>+<br>+       if (src != NULL)<br>+               *src = AUDIO_READ(nuc900_audio-&gt;mmio + ACTL_PDSTC);<br>
+<br>+       if (dst != NULL)<br>+               *dst = AUDIO_READ(nuc900_audio-&gt;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-&gt;runtime;<br>+       dma_addr_t src, dst;<br>+       unsigned long res;<br>+<br>+       nuc900_dma_getposition(substream, &amp;src, &amp;dst);<br>+<br>+       if (substream-&gt;stream == SNDRV_PCM_STREAM_CAPTURE)<br>
+               res = dst - runtime-&gt;dma_addr;<br>+       else<br>+               res = src - runtime-&gt;dma_addr;<br>+<br>+       return bytes_to_frames(substream-&gt;runtime, res);<br>+}<br>+<br>+static int nuc900_dma_open(struct snd_pcm_substream *substream)<br>
+{<br>+       struct snd_pcm_runtime *runtime = substream-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio;<br>+<br>+       snd_soc_set_runtime_hwparams(substream, &amp;nuc900_pcm_hardware);<br>+<br>+       nuc900_audio = nuc900_ac97_data;<br>
+<br>+       if (request_irq(nuc900_audio-&gt;irq_num, nuc900_dma_interrupt,<br>+                       IRQF_DISABLED, &quot;nuc900-dma&quot;, substream))<br>+               return -EBUSY;<br>+<br>+       runtime-&gt;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-&gt;runtime;<br>+       struct nuc900_audio *nuc900_audio = runtime-&gt;private_data;<br>
+<br>+       free_irq(nuc900_audio-&gt;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-&gt;runtime;<br>
+<br>+       return dma_mmap_writecombine(substream-&gt;pcm-&gt;card-&gt;dev, vma,<br>+                                       runtime-&gt;dma_area,<br>+                                       runtime-&gt;dma_addr,<br>+                                       runtime-&gt;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-&gt;dev-&gt;dma_mask)<br>+               card-&gt;dev-&gt;dma_mask = &amp;nuc900_pcm_dmamask;<br>+       if (!card-&gt;dev-&gt;coherent_dma_mask)<br>
+               card-&gt;dev-&gt;coherent_dma_mask = DMA_BIT_MASK(32);<br>+<br>+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,<br>+               card-&gt;dev, 4 * 1024, (4 * 1024) - 1);<br>+<br>+       return 0;<br>
+}<br>+<br>+struct snd_soc_platform nuc900_soc_platform = {<br>+       .name           = &quot;nuc900-dma&quot;,<br>+       .pcm_ops        = &amp;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(&amp;nuc900_soc_platform);<br>+}<br>+<br>+static void __exit nuc900_soc_platform_exit(void)<br>
+{<br>+       snd_soc_unregister_platform(&amp;nuc900_soc_platform);<br>+}<br>+<br>+module_init(nuc900_soc_platform_init);<br>+module_exit(nuc900_soc_platform_exit);<br>+<br>+MODULE_AUTHOR(&quot;Wan ZongShun, &lt;<a href="http://mcuos.com/" target="_blank">mcuos.com</a>@<a href="http://gmail.com/" target="_blank">gmail.com</a>&gt;&quot;);<br>
+MODULE_DESCRIPTION(&quot;nuc900 Audio DMA module&quot;);<br>+MODULE_LICENSE(&quot;GPL&quot;);<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>