Index: linux-2.6.14/sound/oss/Makefile
===================================================================
--- linux-2.6.14.orig/sound/oss/Makefile	2005-10-31 21:41:58.000000000 +0000
+++ linux-2.6.14/sound/oss/Makefile	2005-10-31 21:42:36.000000000 +0000
@@ -39,6 +39,8 @@
 obj-$(CONFIG_SOUND_AD1889)	+= ad1889.o ac97_codec.o
 obj-$(CONFIG_SOUND_ACI_MIXER)	+= aci.o
 obj-$(CONFIG_SOUND_AWE32_SYNTH)	+= awe_wave.o
+obj-$(CONFIG_SOUND_CORGI)	+= pxa-i2s_corgi.o pxa_audio.o wm8731.o
+
 
 obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o ac97_codec.o
 ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
Index: linux-2.6.14/sound/oss/Kconfig
===================================================================
--- linux-2.6.14.orig/sound/oss/Kconfig	2005-10-31 21:41:58.000000000 +0000
+++ linux-2.6.14/sound/oss/Kconfig	2005-10-31 21:42:36.000000000 +0000
@@ -831,6 +831,10 @@
 	  Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file,
 	  starting from /.
 
+config SOUND_CORGI
+	tristate "Sound on the Sharp SL-C7xx Series"
+	depends on SOUND_OSS
+
 config SOUND_SB
 	tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support"
 	depends on SOUND_OSS
Index: linux-2.6.14/sound/oss/pxa-i2s_corgi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.14/sound/oss/pxa-i2s_corgi.c	2005-10-31 21:42:36.000000000 +0000
@@ -0,0 +1,2120 @@
+/*
+ * Corgi Sound Driver
+ *
+ * Uses PXA I2S interface and a Wolfson wm8731 on the i2c bus
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/wait.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/dma.h>
+
+#include <asm/mach/arch.h>
+#include <asm/arch/corgi.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/hardware/scoop.h>
+
+#include "pxa_audio.h"
+#include "wm8731.h"
+
+
+struct wm8731_priv *wm8731;
+
+/*** Some declarations ***********************************************/
+//#define MY_TRACE	4
+
+#define DBG_ALWAYS	0
+#define DBG_LEVEL1	1
+#define DBG_LEVEL2	2
+#define DBG_LEVEL3	3
+
+#ifdef MY_TRACE
+#define PXAI2S_DBGPRINT(level, x, args...)	if (level <= MY_TRACE ) printk("%s: " x,__FUNCTION__ ,##args)
+#else
+#define PXAI2S_DBGPRINT(level, x, args...)	if (!level ) printk("%s: " x,__FUNCTION__ ,##args)
+#endif
+
+
+#define SND_DEV_STATUS		6	/* /dev/sndstat	 for Compatible for Collie */
+
+#define AUDIO_NBFRAGS_DEFAULT	8
+#define AUDIO_FRAGSIZE_DEFAULT	8192
+
+#define MAX_DMA_SIZE		4096
+
+#define CORGI_DEFAULT_FREQUENCY	44100
+
+#define IOCTL_IN(arg, ret) \
+	do { int error = get_user(ret, (int *)(arg)); \
+		if (error) return error; \
+	} while (0)
+#define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)
+
+#define WAIT_INIT_PLAY	(2*1000/10)
+#define WAIT_PLAY1	(50/10)
+#define WAIT_PLAY2	(30/10)
+
+#define AUDIO_DATA	0x00
+
+
+enum { CORGI_HP_AUDIO=0, CORGI_HP_BUZZER, CORGI_HP_SOUNDER, CORGI_HP_HP, CORGI_HP_BOTH, CORGI_HP_MIC, CORGI_HP_HEADSET};
+
+#define AUDIO_ALWAYS_SP_ON		1
+//#undef AUDIO_ALWAYS_SP_ON
+#define DMA_NO_INITIALIZED		1
+//#undef DMA_NO_INITIALIZED
+
+/* --- for AUDIO & REMOCON device --- */
+#define HPJACK_STATE_UNDETECT		(-1)
+#define HPJACK_STATE_NONE		(0)
+#define HPJACK_STATE_HEADPHONE		(1)
+#define HPJACK_STATE_REMOCON		(2)
+
+/**** valiables **********************************************************/
+
+static ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
+static ssize_t (*ct_read_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
+
+
+static DECLARE_WAIT_QUEUE_HEAD(hp_queue);
+static void corgi_hp_thread(void *private_);
+DECLARE_WORK(hp_proc, corgi_hp_thread, NULL);
+
+static int isPXAI2SReady = 0;
+static int isChkHPstatus = 0;
+int corgi_HPstatus = HPJACK_STATE_UNDETECT;
+
+/**** Prototype *******************************************************/
+static void CorgiInit(void);
+static void CorgiSetVolume(int);
+static int CorgiSetStereo(int);
+static int CorgiSetFormat(int);
+static int CorgiSetGain(int);
+static int CorgiGetGain(void);
+static int CorgiSetFormat(int);
+static int CorgiGetVolume(void);
+static int CorgiSetFreq(int);
+static int mixer_ioctl( struct inode *, struct file *,unsigned int, unsigned long);
+static void corgi_hp_mode(int mode);
+
+/**** Machine definitions ************************************************/
+typedef struct {
+	ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+} TRANS;
+
+
+/**** /dev/ setting ********************************************/
+/*	/dev/dsp	*/
+struct sound_settings {
+	TRANS *trans;		/* supported translations */
+	TRANS *trans_read;	/* supported translations */
+
+	int format;		/* AFMT_* */
+	int stereo;		/* 0 = mono, 1 = stereo */
+	int size;		/* 8/16 bit*/
+	int freq;		/* freq */
+
+	int volume_left;	/* volume (range is 0 - 100%) */
+	int volume_right;
+	int gain_left;		/* input gain (range is 0 - 100%) */
+	int gain_right;
+
+	int bass;		/* tone (not support) */
+	int treble;
+
+	/* device independ */
+	int gain_shift;		/* input gain shift */
+	int gain;		/* input gain */
+	int hw_freq;		/* hw freq */
+
+};
+static struct sound_settings sound;
+
+/*	/dev/mixer	*/
+struct sound_mixer {
+	int dev_mixer;
+	int busy;
+};
+static struct sound_mixer pxa_i2s_codec;
+
+/*	/dev/sndstat	*/
+struct sound_state {
+	int dev_state;
+	int busy;
+	char buf[512];
+	int len, ptr;
+};
+static struct sound_state pxa_i2s_state;
+
+typedef struct _input_gain_t {
+	int shift;
+	int gain;
+} input_gain_t;
+
+static input_gain_t input_gain[7] = {
+	{	1 ,	0 },
+	{	2 ,	0 },
+	{	0 ,	1 },
+	{	1 ,	1 },
+	{	2 ,	1 },
+	{	3 ,	1 },
+	{	4 ,	1 }
+};
+
+
+// FIXME !
+/**** data convert ****************************************************/
+
+/* 16 bit mu-law */
+
+static short ulaw2dma16[] = {
+	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,
+	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,
+	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,
+	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,
+	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,
+	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,
+	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,
+	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,
+	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,
+	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,
+	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,
+	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,
+	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,
+	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,
+	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,
+	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,
+	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,
+	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,
+	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,
+	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,
+	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,
+	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,
+	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,
+	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,
+	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,
+	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,
+	876,	844,	812,	780,	748,	716,	684,	652,
+	620,	588,	556,	524,	492,	460,	428,	396,
+	372,	356,	340,	324,	308,	292,	276,	260,
+	244,	228,	212,	196,	180,	164,	148,	132,
+	120,	112,	104,	96,	88,	80,	72,	64,
+	56,	48,	40,	32,	24,	16,	8,	0,
+};
+
+/* 16 bit A-law */
+
+static short alaw2dma16[] = {
+	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,
+	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,
+	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,
+	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,
+	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,
+	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,
+	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,
+	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,
+	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,
+	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,
+	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,
+	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,
+	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,
+	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,
+	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,
+	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,
+	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,
+	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,
+	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,
+	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,
+	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,
+	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,
+	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,
+	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,
+	344,	328,	376,	360,	280,	264,	312,	296,
+	472,	456,	504,	488,	408,	392,	440,	424,
+	88,	72,	120,	104,	24,	8,	56,	40,
+	216,	200,	248,	232,	152,	136,	184,	168,
+	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,
+	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,
+	688,	656,	752,	720,	560,	528,	624,	592,
+	944,	912,	1008,	976,	816,	784,	880,	848,
+};
+
+
+static ssize_t corgi_ct_law(const u_char *userPtr, size_t userCount,
+					 u_char frame[], ssize_t *frameUsed,
+					 ssize_t frameLeft)
+{
+	short *table = sound.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = sound.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+		if (get_user(data, userPtr++)) {
+			return -EFAULT;
+		}
+		val = table[data];
+		*p++ = val;		/* Left Ch. */
+		if (stereo) {
+			if (get_user(data, userPtr++)) {
+				return -EFAULT;
+			}
+			val = table[data];
+		}
+		*p++ = val;		/* Right Ch. */
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t corgi_ct_u8(const u_char *userPtr, size_t userCount,
+				u_char frame[], ssize_t *frameUsed,
+				ssize_t frameLeft)
+{
+	int ch = (sound.stereo)?2:1;
+	unsigned char *src = (unsigned char *)userPtr;
+	short *dstct = (short *)frame;
+	short tmpval;
+
+	if (sound.freq != sound.hw_freq ) {
+		int frameMax = frameLeft >> 2;
+		int arrayMax = (userCount>>(ch-1));
+		int userMax = ( arrayMax * sound.hw_freq ) / sound.freq;
+		int samplingCount = min(frameMax,userMax);
+		int whichLimit = (samplingCount==frameMax)?1:0; // which is minimum?
+		short *dstend = (short*)((int)frame+samplingCount*2*2);
+		unsigned char *srcval;
+		int idx;
+			
+		int cur=0,step = (sound.freq << 8 ) / sound.hw_freq; // fixed point (x256)
+
+		while (dstct<dstend) {
+			idx = (cur>>8);
+			if (idx>=arrayMax)
+				idx=arrayMax-1;
+			srcval = &src[idx*ch];
+			if (get_user(tmpval,srcval))
+				return -EFAULT;
+			*dstct++ = (tmpval-128)<<8;
+			if (ch>1) srcval++;
+			if (get_user(tmpval,srcval)) 
+				return -EFAULT;
+			*dstct++ = (tmpval-128)<<8;
+			cur += step;
+		}
+
+		*frameUsed = samplingCount*2*2; // // dma is always stereo 16bit
+		if (whichLimit) { // dma limit
+			return (cur>>8)*ch; // byte
+		} else { // user buffer limit
+			return userCount; // byte
+		}
+
+	} else { // hw_freq == freq
+		int frameMax = frameLeft >> 2;
+		int userMax = userCount >> (ch-1);
+		int idx,samplingCount = min(frameMax,userMax);
+
+		for (idx=0; idx<samplingCount; idx++) {
+			if (get_user(tmpval,src))
+				return -EFAULT;
+			*dstct++ = (tmpval-128)<<8;
+			if (ch>1) src++;
+			if (get_user(tmpval,src++))
+				return -EFAULT;
+			*dstct++ = (tmpval-128)<<8;
+		}
+
+		*frameUsed = samplingCount * 2 * 2; // dma is always stereo 16bit
+		return samplingCount * ch;
+	}
+}
+
+
+static ssize_t corgi_ct_s16(const u_char *userPtr, size_t userCount,
+				 u_char frame[], ssize_t *frameUsed,
+				 ssize_t frameLeft)
+{
+	int ch = (sound.stereo)?2:1;
+	short *src = (short *)userPtr;
+	short *dstct = (short *)frame;
+
+	if (sound.freq != sound.hw_freq ) {
+		int frameMax = frameLeft >> 2;
+		int arrayMax = (userCount>>ch);
+		int userMax = ( arrayMax * sound.hw_freq ) / sound.freq;
+		int samplingCount = min(frameMax,userMax);
+		int whichLimit = (samplingCount==frameMax)?1:0; // which is minimum?
+		short *dstend = (short*)((int)frame+samplingCount*2*2);
+		short *srcval;
+		int idx;
+			
+		int cur=0,step = (sound.freq << 8 ) / sound.hw_freq; // fixed point (x256)
+
+		while (dstct<dstend) {
+			idx = (cur>>8);
+			if (idx>=arrayMax) {
+			idx=arrayMax-1;
+			}
+			srcval = &src[idx*ch];
+			if (get_user(*dstct++,srcval)) 
+				return -EFAULT;
+			if (ch>1) srcval++;
+			if (get_user(*dstct++,srcval))
+				return -EFAULT;
+			cur += step;
+		}
+
+		*frameUsed = samplingCount*2*2; // // dma is always stereo 16bit
+		if (whichLimit) { // dma limit
+			return (cur>>8)*ch*2; // byte
+		} else { // user buffer limit
+			return userCount; // byte
+		}
+
+	} else { // hw_freq == freq
+		int frameMax = frameLeft >> 2;
+		int userMax = userCount >> ch;
+		int samplingCount = min(frameMax,userMax);
+
+		if (ch>1) { // stereo
+			if (copy_from_user(dstct,src,samplingCount * ch * 2)) {
+				return -EFAULT;
+			}
+		} else { // mono
+			int idx;
+			for (idx=0; idx<samplingCount; idx++) {
+				if (get_user(*dstct++,src) || get_user(*dstct++,src++)) {
+					return -EFAULT;
+				}
+			}
+		}
+
+		*frameUsed = samplingCount * 2 * 2; // dma is always stereo 16bit
+		return samplingCount * ch * 2;
+	}
+}
+
+static TRANS transCorgi = {
+	corgi_ct_law,corgi_ct_law,0,corgi_ct_u8,
+	0,0,corgi_ct_s16,0
+};
+
+/**** data convert for recording ****************************************************/
+
+static ssize_t corgi_ct_read_u8(const u_char *userPtr, size_t userCount,
+				u_char frame[], ssize_t *frameUsed,
+				ssize_t frameLeft)
+{
+	int ch = (sound.stereo)?2:1;
+	unsigned char *usrbuf = (unsigned char *)userPtr;
+	short *dmabuf = (short *)frame;
+	short tmpval;
+
+	if (sound.freq != sound.hw_freq ) {
+		int arrayMax = (frameLeft >> 2);
+		int dmaMax = (arrayMax * sound.freq) / sound.hw_freq; // dma is always stereo 16bit
+		int userMax = userCount >> (ch-1); // 8bit
+		int samplingCount = min(dmaMax,userMax);
+		int whichLimit = (samplingCount==dmaMax)?1:0; // which is minimum?
+		unsigned char *usrend = (unsigned char*)((int)usrbuf+samplingCount*ch);
+		short *srcval;
+		int idx;
+		int cur=0,step = (sound.hw_freq << 8 ) / sound.freq; // fixed point (x256)
+		dmaMax = frameLeft>>2; // array max index
+
+		while (usrbuf < usrend) {
+			idx = (cur>>8);
+			if (idx>=arrayMax) { // over flow?
+				idx = arrayMax-1;
+			}
+			srcval = &dmabuf[idx*2];
+			tmpval = (*srcval>>(8-sound.gain_shift));
+			if (tmpval>127) tmpval = 127;
+			else if (tmpval<-128) tmpval = -128;
+			if (put_user((unsigned char)(tmpval+128),usrbuf++))
+				return -EFAULT;
+			srcval++;
+			if (ch>1) {
+				tmpval = (*srcval>>(8-sound.gain_shift));
+				if (tmpval>127) tmpval = 127;
+				else if (tmpval<-128) tmpval = -128;
+				if (put_user((unsigned char)(tmpval+128),usrbuf++)) {
+					return -EFAULT;
+				}
+			}
+			cur += step;
+		}
+		*frameUsed = (whichLimit)?(frameLeft):((cur>>8) * 2 * 2); //	dma is always stereo
+		return samplingCount * ch;
+
+	} else { // hw_freq == freq
+		int dmaMax = frameLeft >> 2; // dma is always stereo
+		int userMax = userCount >> ch;
+		int ct,samplingCount = min(dmaMax,userMax);
+
+		for (ct=0; ct<samplingCount; ct++) {
+			tmpval = (*dmabuf>>(8-sound.gain_shift));
+			if (tmpval>127) tmpval = 127;
+			else if (tmpval<-128) tmpval = -128;
+			if (put_user((unsigned char)(tmpval+128),usrbuf++)) { // left channel
+				return -EFAULT;
+			}
+			dmabuf++;
+			if (ch>1) { // right channel
+				tmpval = (*dmabuf>>(8-sound.gain_shift));
+				if (tmpval>127) tmpval = 127;
+				else if (tmpval<-128) tmpval = -128;
+				if (put_user((unsigned char)(tmpval+128),usrbuf++)) {
+					return -EFAULT;
+				}
+			}
+			dmabuf++;
+		}
+		*frameUsed = samplingCount * 2 * 2; // dma is always stereo
+		return samplingCount * ch;
+	}
+}
+
+static ssize_t corgi_ct_read_s16(const u_char *userPtr, size_t userCount,
+				 u_char frame[], ssize_t *frameUsed,
+				 ssize_t frameLeft)
+{
+	int ch = (sound.stereo)?2:1;
+	short *usrbuf = (short *)userPtr;
+	short *dmabuf = (short *)frame;
+
+	if (sound.freq != sound.hw_freq ) {
+		int arrayMax = (frameLeft >> 2);
+		int dmaMax = (arrayMax * sound.freq) / sound.hw_freq; // dma is always stereo
+		int userMax = userCount >> ch;
+		int samplingCount = min(dmaMax,userMax);
+		int whichLimit = (samplingCount==dmaMax)?1:0; // which is minimum?
+		short *usrend = (short*)((int)usrbuf+samplingCount*ch*2);
+		short *srcval;
+		int idx;
+		int cur=0,step = (sound.hw_freq << 8 ) / sound.freq; // fixed point (x256)
+		dmaMax = frameLeft>>2; // array max index
+
+		while (usrbuf<usrend) {
+			idx = (cur>>8);
+			if (idx>=arrayMax) { // over flow?
+				idx = arrayMax-1;
+			}
+			srcval = &dmabuf[idx*2];
+			if (put_user((*srcval<<sound.gain_shift),usrbuf++)) {
+				return -EFAULT;
+			}
+			srcval++;
+			if (ch>1) {
+				if (put_user((*srcval<<sound.gain_shift),usrbuf++)) {
+					return -EFAULT;
+				}
+			}
+			cur += step;
+		}
+		*frameUsed = (whichLimit)?(frameLeft):((cur>>8) * 2 * 2); //	dma is always stereo
+		return samplingCount * ch * 2;
+
+	} else { // hw_freq == freq
+		int dmaMax = frameLeft >> 2; // dma is always stereo
+		int userMax = userCount >> ch;
+		int ct,samplingCount = min(dmaMax,userMax);
+
+		for (ct=0; ct<samplingCount; ct++) {
+			if (put_user((*dmabuf<<sound.gain_shift),usrbuf++)) { // left channel
+				return -EFAULT;
+			}
+			dmabuf++;
+			if (ch>1) { // right channel
+				if (put_user((*dmabuf<<sound.gain_shift),usrbuf++)) {
+					return -EFAULT;
+				}
+			}
+			dmabuf++;
+		}
+		*frameUsed = samplingCount * 2 * 2; // dma is always stereo
+		return samplingCount * ch * 2;
+	}
+}
+
+static TRANS transReadCorgi = {
+	0,0,0,corgi_ct_read_u8,
+	0,0,corgi_ct_read_s16,0
+};
+
+/**** low level stuff ****************************************************/
+
+/*** Common stuff ********************************************************/
+static inline int ioctl_return(int *addr, int value)
+{
+	if (value < 0) {
+		return(value);
+	}
+	return put_user(value, addr)? -EFAULT: 0;
+}
+
+
+
+/*
+ * The fops functions
+ */
+
+static int audio_write(struct file *file, const char *buffer,
+					 size_t count, loff_t * ppos)
+{
+	const char *buffer0 = buffer;
+	audio_state_t *state = (audio_state_t *)file->private_data;
+	audio_stream_t *s = state->output_stream;
+	int ret = 0;
+	ssize_t uUsed, bUsed, bLeft = 0;
+	u_char *dest;
+
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_write()\n");
+
+	// wait playing int sound.
+	//while(corgi_intmode_direct)
+	//	schedule();
+	if (s->mapped)
+		return -ENXIO;
+		
+	if (!s->buffers && audio_setup_buf(s,0))
+		return -ENOMEM;
+
+	while (count > 0) {
+		audio_buf_t *b = &s->buffers[s->usr_frag];
+
+
+					PXAI2S_DBGPRINT(DBG_LEVEL3, "audio_write count = %d\n",count);
+
+		/* Grab a fragment */
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			if (down_trylock(&s->sem))
+				break;
+		} else {
+			ret = -ERESTARTSYS;
+			if (down_interruptible(&s->sem))
+				break;
+		}
+
+		/* Feed the current buffer */
+		dest = b->data + b->offset;
+		bUsed = 0;
+		bLeft = s->fragsize - b->offset;
+
+		if (ct_func) {
+			uUsed = ct_func(buffer, count, dest, &bUsed, bLeft);
+		} else {
+			return -EFAULT;
+		}
+
+		//if (corgi_intmode ) {
+		//	corgi_intmode_mix(dest,bUsed);
+		//}
+
+		if (uUsed < 0) {
+			up(&s->sem);
+			return -EFAULT;
+		}
+		b->offset += bUsed;
+		buffer += uUsed;
+		count -= uUsed;
+
+		if (b->offset < s->fragsize) {
+			up(&s->sem);
+			break;
+		}
+		/* 
+		 * Activate DMA on current buffer.
+		 * We unlock this fragment's checkpoint descriptor and
+		 * kick DMA if it is idle.	Using checkpoint descriptors
+		 * allows for control operations without the need for 
+		 * stopping the DMA channel if it is already running.
+		 */
+		b->offset = 0;
+		b->dma_desc->ddadr &= ~DDADR_STOP;
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(s->dma_ch) & DCSR_STOPSTATE)||
+			!(DCSR(s->dma_ch) & DCSR_RUN)){
+			DDADR(s->dma_ch) = b->dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
+			DDADR(s->dma_ch) = b->dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#endif
+
+		/* move the index to the next fragment */
+		if (++s->usr_frag >= s->nbfrags)
+			s->usr_frag = 0;
+	}
+
+	if ((buffer - buffer0))
+		ret = buffer - buffer0;
+	return ret;
+}
+
+
+static int audio_read(struct file *file, char *buffer,
+					size_t count, loff_t * ppos)
+{
+	char *buffer0 = buffer;
+	audio_state_t *state = file->private_data;
+	audio_stream_t *s = state->input_stream;
+	int ret = 0;
+	ssize_t uUsed, bUsed, bLeft = 0;
+	u_char *dest;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_read()\n");
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (s->mapped)
+		return -ENXIO;
+	if (!s->buffers && audio_setup_buf(s,1))
+		return -ENOMEM;
+
+	while (count > 0) {
+		audio_buf_t *b = &s->buffers[s->usr_frag];
+
+		/* prime DMA */
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(s->dma_ch) & DCSR_STOPSTATE)||
+			!(DCSR(s->dma_ch) & DCSR_RUN)){
+			DDADR(s->dma_ch) = 
+				s->buffers[s->dma_frag].dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
+			DDADR(s->dma_ch) = 
+				s->buffers[s->dma_frag].dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#endif
+
+		/* Wait for a buffer to become full */
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			if (down_trylock(&s->sem))
+				break;
+		} else {
+			ret = -ERESTARTSYS;
+			if (down_interruptible(&s->sem))
+				break;
+		}
+
+		/* Grab data from current buffer */
+
+		dest = b->data + b->offset;
+		bUsed = 0;
+		bLeft = s->fragsize - b->offset;
+
+		if (ct_read_func) {
+			uUsed = ct_read_func(buffer, count, dest, &bUsed, bLeft);
+		} else {
+			return -EFAULT;
+		}
+
+		if (uUsed < 0) {
+			up(&s->sem);
+			return -EFAULT;
+		}
+		b->offset += bUsed;
+		buffer += uUsed;
+		count -= uUsed;
+
+		if (b->offset < s->fragsize) {
+			up(&s->sem);
+			break;
+		}
+
+		/* 
+		 * Make this buffer available for DMA again.
+		 * We unlock this fragment's checkpoint descriptor and
+		 * kick DMA if it is idle.	Using checkpoint descriptors
+		 * allows for control operations without the need for 
+		 * stopping the DMA channel if it is already running.
+		 */
+		b->offset = 0;
+		b->dma_desc->ddadr &= ~DDADR_STOP;
+
+		/* move the index to the next fragment */
+		if (++s->usr_frag >= s->nbfrags)
+			s->usr_frag = 0;
+	}
+
+	if ((buffer - buffer0))
+		ret = buffer - buffer0;
+	return ret;
+}
+
+static int audio_sync(struct file *file)
+{
+	audio_state_t *state = file->private_data;
+	audio_stream_t *s = state->output_stream;
+	audio_buf_t *b;
+	pxa_dma_desc *final_desc;
+	u_long dcmd_save = 0;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_sync()\n");
+
+	if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped)
+		return 0;
+
+	/*
+	 * Send current buffer if it contains data. Be sure to send
+	 * a full sample count.
+	 */
+	final_desc = NULL;
+	b = &s->buffers[s->usr_frag];
+	if (b->offset &= ~3) {
+		final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE];
+		b->offset &= (MAX_DMA_SIZE-1);
+		dcmd_save = final_desc->dcmd;
+		final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; 
+		final_desc->ddadr |= DDADR_STOP;
+		b->offset = 0;
+		b->dma_desc->ddadr &= ~DDADR_STOP;
+
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(s->dma_ch) & DCSR_STOPSTATE)||
+			!(DCSR(s->dma_ch) & DCSR_RUN)){
+			DDADR(s->dma_ch) = b->dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
+			DDADR(s->dma_ch) = b->dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#endif
+	}
+
+	/* Wait for DMA to complete. */
+	wait_event_interruptible(s->frag_wq, !(DCSR(s->dma_ch) & DCSR_RUN) );
+
+	//corgi_intmode = 0;
+
+	/* Restore the descriptor chain. */
+	if (final_desc) {
+		final_desc->dcmd = dcmd_save;
+		final_desc->ddadr &= ~DDADR_STOP;
+		b->dma_desc->ddadr |= DDADR_STOP;
+	}
+	
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_sync() exiting\n");
+	
+	return 0;
+}
+
+
+static unsigned int audio_poll(struct file *file,
+						 struct poll_table_struct *wait)
+{
+	audio_state_t *state = file->private_data;
+	audio_stream_t *is = state->input_stream;
+	audio_stream_t *os = state->output_stream;
+	unsigned int mask = 0;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_poll()\n");
+
+	if (file->f_mode & FMODE_READ) {
+		/* Start audio input if not already active */
+		if (!is->buffers && audio_setup_buf(is,1))
+			return -ENOMEM;
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(is->dma_ch) & DCSR_STOPSTATE)||
+			!(DCSR(is->dma_ch) & DCSR_RUN)){
+			DDADR(is->dma_ch) = 
+				is->buffers[is->dma_frag].dma_desc->ddadr;
+			DCSR(is->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(is->dma_ch) & DCSR_STOPSTATE) {
+			DDADR(is->dma_ch) = 
+				is->buffers[is->dma_frag].dma_desc->ddadr;
+			DCSR(is->dma_ch) = DCSR_RUN;
+		}
+#endif
+		poll_wait(file, &is->frag_wq, wait);
+	}
+
+	if (file->f_mode & FMODE_WRITE) {
+		if (!os->buffers && audio_setup_buf(os,1))
+			return -ENOMEM;
+		poll_wait(file, &os->frag_wq, wait);
+	}
+
+	if (file->f_mode & FMODE_READ)
+		if (( is->mapped && is->bytecount > 0) ||
+				(!is->mapped && atomic_read(&is->sem.count) > 0))
+			mask |= POLLIN | POLLRDNORM;
+
+	if (file->f_mode & FMODE_WRITE)
+		if (( os->mapped && os->bytecount > 0) ||
+				(!os->mapped && atomic_read(&os->sem.count) > 0))
+			mask |= POLLOUT | POLLWRNORM;
+
+	return mask;
+}
+
+
+static int audio_ioctl( struct inode *inode, struct file *file,
+			uint cmd, ulong arg)
+{
+	audio_state_t *state = file->private_data;
+	audio_stream_t *os = state->output_stream;
+	audio_stream_t *is = state->input_stream;
+	long val;
+	long fmt;
+	int data;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_ioctl(): %d\n",cmd);
+
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE)
+			return put_user(os->fragsize, (int *)arg);
+		else
+			return put_user(is->fragsize, (int *)arg);
+
+	case SNDCTL_DSP_GETCAPS:
+		val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP;
+		if (is && os)
+			val |= DSP_CAP_DUPLEX;
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		if (get_user(val, (long *) arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			int ret = audio_set_fragments(is, val);
+			if (ret < 0)
+				return ret;
+			ret = put_user(ret, (int *)arg);
+			if (ret)
+				return ret;
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			int ret = audio_set_fragments(os, val);
+			if (ret < 0)
+				return ret;
+			ret = put_user(ret, (int *)arg);
+			if (ret)
+				return ret;
+		}
+		return 0;
+
+	case SNDCTL_DSP_SYNC:
+		return audio_sync(file);
+
+	case SNDCTL_DSP_SETDUPLEX:
+		return 0;
+
+	case SNDCTL_DSP_POST:
+		return 0;
+
+	case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+		if (file->f_mode & FMODE_READ && DCSR(is->dma_ch) & DCSR_RUN)
+			val |= PCM_ENABLE_INPUT;
+		if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN)
+			val |= PCM_ENABLE_OUTPUT;
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_SETTRIGGER:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			if (val & PCM_ENABLE_INPUT) {
+				if (!is->buffers && audio_setup_buf(is,1))
+					return -ENOMEM;
+				if (!(DCSR(is->dma_ch) & DCSR_RUN)) {
+					audio_buf_t *b = &is->buffers[is->dma_frag];
+					DDADR(is->dma_ch) = b->dma_desc->ddadr;
+					DCSR(is->dma_ch) = DCSR_RUN;
+				}
+			} else {
+				DCSR(is->dma_ch) = 0;
+			}
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			if (val & PCM_ENABLE_OUTPUT) {
+				if (!os->buffers && audio_setup_buf(os,1))
+					return -ENOMEM;
+				if (!(DCSR(os->dma_ch) & DCSR_RUN)) {
+					audio_buf_t *b = &os->buffers[os->dma_frag];
+					DDADR(os->dma_ch) = b->dma_desc->ddadr;
+					DCSR(os->dma_ch) = DCSR_RUN;
+				}
+			} else {
+				DCSR(os->dma_ch) = 0;
+			}
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETOSPACE:
+			{
+		audio_buf_info inf = { 0, };
+		audio_stream_t *s = os;
+		int j,k;
+
+		if ((s == os && !(file->f_mode & FMODE_WRITE)))
+			return -EINVAL;
+		if (!s->buffers && audio_setup_buf(s,1))
+			return -ENOMEM;
+
+		j = s->usr_frag;
+		k = s->dma_frag;
+		if (atomic_read(&s->sem.count) > 0	) {
+			if (j > k ) {
+				inf.fragments = s->nbfrags - ( j - k );
+			} else if (j < k ) {
+				inf.fragments = k - j;
+			} else {
+				inf.fragments = s->nbfrags;
+			}
+		}
+		inf.bytes = s->fragsize * inf.fragments;
+
+		inf.fragsize = s->fragsize;
+		inf.fragstotal = s->nbfrags;
+		return copy_to_user((void *)arg, &inf, sizeof(inf));
+			}
+
+	case SNDCTL_DSP_GETISPACE:
+			{
+		audio_buf_info inf = { 0, };
+		audio_stream_t *s = is;
+		int j,k;
+
+		if ((s == is && !(file->f_mode & FMODE_READ)))
+			return -EINVAL;
+		if (!s->buffers && audio_setup_buf(s,1))
+			return -ENOMEM;
+
+		j = s->usr_frag;
+		k = s->dma_frag;
+
+		if (atomic_read(&s->sem.count) <= 0	) {
+				inf.fragments = 0;
+		} else {
+				inf.fragments = atomic_read(&s->sem.count);
+		}
+
+		inf.bytes = s->fragsize * inf.fragments;
+
+		inf.fragsize = s->fragsize;
+		inf.fragstotal = s->nbfrags;
+		return copy_to_user((void *)arg, &inf, sizeof(inf));
+			}
+
+
+
+	case SNDCTL_DSP_GETOPTR:
+	case SNDCTL_DSP_GETIPTR:
+			{
+		count_info inf = { 0, };
+		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
+		dma_addr_t ptr;
+		int bytecount, offset;
+		unsigned long flags;
+
+		if ((s == is && !(file->f_mode & FMODE_READ)) ||
+				(s == os && !(file->f_mode & FMODE_WRITE)))
+			return -EINVAL;
+		local_irq_save(flags); 
+		if (DCSR(s->dma_ch) & DCSR_RUN) {
+			audio_buf_t *b;
+			ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch);
+			b = &s->buffers[s->dma_frag];
+			offset = ptr - b->dma_desc->dsadr;
+			if (offset >= s->fragsize)
+				offset = s->fragsize - 4;
+		} else {
+			offset = 0;
+		}
+		inf.ptr = s->dma_frag * s->fragsize + offset;
+		bytecount = s->bytecount + offset;
+		s->bytecount = -offset;
+		inf.blocks = s->fragcount;
+		s->fragcount = 0;
+		local_irq_restore(flags);
+		if (bytecount < 0)
+			bytecount = 0;
+		inf.bytes = bytecount;
+		return copy_to_user((void *)arg, &inf, sizeof(inf));
+			}
+
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_RESET:
+		if (file->f_mode & FMODE_WRITE) 
+			pxa_audio_clear_buf(os);
+		if (file->f_mode & FMODE_READ)
+			pxa_audio_clear_buf(is);
+		return 0;
+
+	case SNDCTL_DSP_SPEED:
+		audio_sync(file);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, CorgiSetFreq(data));
+	case SNDCTL_DSP_STEREO:
+		audio_sync(file);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, CorgiSetStereo(data));
+	case SOUND_PCM_WRITE_CHANNELS:
+		audio_sync(file);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, CorgiSetStereo(data-1)+1);
+	case SNDCTL_DSP_SETFMT:
+		audio_sync(file);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, CorgiSetFormat(data));
+	case SNDCTL_DSP_GETFMTS:
+		fmt = 0;
+		if (sound.trans) {
+			if (sound.trans->ct_ulaw)
+				fmt |= AFMT_MU_LAW;
+			if (sound.trans->ct_alaw)
+				fmt |= AFMT_A_LAW;
+			if (sound.trans->ct_s8)
+				fmt |= AFMT_S8;
+			if (sound.trans->ct_u8)
+				fmt |= AFMT_U8;
+			if (sound.trans->ct_s16be)
+				fmt |= AFMT_S16_BE;
+			if (sound.trans->ct_u16be)
+				fmt |= AFMT_U16_BE;
+			if (sound.trans->ct_s16le)
+				fmt |= AFMT_S16_LE;
+			if (sound.trans->ct_u16le)
+				fmt |= AFMT_U16_LE;
+		}
+		return IOCTL_OUT(arg, fmt);
+
+	default:
+		return mixer_ioctl(inode, file, cmd, arg);
+	}
+	
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_ioctl() exiting\n");
+
+	return 0;
+}
+
+
+static int audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	audio_state_t *state = file->private_data;
+	audio_stream_t *s;
+	unsigned long size, vma_addr;
+	int i, ret;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_mmap()\n");
+
+	if (vma->vm_pgoff != 0)
+		return -EINVAL;
+
+	if (vma->vm_flags & VM_WRITE) {
+		if (!state->wr_ref)
+			return -EINVAL;;
+		s = state->output_stream;
+	} else if (vma->vm_flags & VM_READ) {
+		if (!state->rd_ref)
+			return -EINVAL;
+		s = state->input_stream;
+	} else return -EINVAL;
+
+	if (s->mapped)
+		return -EINVAL;
+	size = vma->vm_end - vma->vm_start;
+	if (size != s->fragsize * s->nbfrags)
+		return -EINVAL;
+	if (!s->buffers && audio_setup_buf(s,1))
+		return -ENOMEM;
+	vma_addr = vma->vm_start;
+	for (i = 0; i < s->nbfrags; i++) {
+		audio_buf_t *buf = &s->buffers[i];
+		if (!buf->master)
+			continue;
+		ret = remap_pfn_range(vma, vma_addr, buf->dma_desc->dsadr >> PAGE_SHIFT,
+							 buf->master, vma->vm_page_prot);
+		if (ret)
+			return ret;
+		vma_addr += buf->master;
+	}
+	for (i = 0; i < s->nbfrags; i++)
+		s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP;
+	s->mapped = 1;
+	return 0;
+}
+
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	audio_state_t *state = file->private_data;
+	int err;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_release()\n");
+
+	down(&state->sem);
+
+	//	HP & sounder & mic off
+#if (defined AUDIO_ALWAYS_SP_ON)
+	reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_MIC_BIAS );
+#else
+	reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON | CORGI_SCP_MIC_BIAS );
+#endif
+
+
+	if (file->f_mode & FMODE_READ) {
+		pxa_audio_clear_buf(state->input_stream);
+		*state->input_stream->drcmr = 0;
+		pxa_free_dma(state->input_stream->dma_ch);
+		state->rd_ref = 0;
+	}
+
+	if (file->f_mode & FMODE_WRITE) {
+		audio_sync(file);
+		pxa_audio_clear_buf(state->output_stream);
+		*state->output_stream->drcmr = 0;
+		pxa_free_dma(state->output_stream->dma_ch);
+		state->wr_ref = 0;
+	}
+
+	// Close wm8731
+	err = wm8731_close(wm8731);
+	if (err ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close wm8731\n");
+		return err;
+	}
+
+	// Close I2S
+	err = i2s_close();
+	if (err ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close i2s\n");
+		return err;
+	}
+
+	up(&state->sem);
+	return 0;
+}
+
+
+static int audio_open(struct inode *inode, struct file *file )
+{
+	audio_state_t	*state = &pxa_audio_state;
+	audio_stream_t *is = state->input_stream;
+	audio_stream_t *os = state->output_stream;
+	struct wm8731_settings settings;
+	int err;
+	int now;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_open()\n");
+
+	down(&state->sem);
+
+	/* access control */
+	err = -ENODEV;
+	if ((file->f_mode & FMODE_WRITE) && !os)
+		goto out;
+	if ((file->f_mode & FMODE_READ) && !is)
+		goto out;
+	err = -EBUSY;
+
+	while(1) {
+		if (isPXAI2SReady ) break;
+		schedule();
+	}
+
+	if (state->wr_ref || state->rd_ref)
+		goto out;
+
+	/* request DMA channels */
+	if (file->f_mode & FMODE_WRITE) {
+		err = pxa_request_dma(os->name, DMA_PRIO_LOW, audio_dma_irq, os);
+		if (err < 0 )
+			goto out;
+		os->dma_ch = err;
+	}
+	if (file->f_mode & FMODE_READ) {
+		err = pxa_request_dma(is->name, DMA_PRIO_LOW, audio_dma_irq, is);
+		if (err < 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				*os->drcmr = 0;
+				pxa_free_dma(os->dma_ch);
+			}
+			goto out;
+		}
+		is->dma_ch = err;
+	}
+
+	file->private_data	= state;
+
+	if ((file->f_mode & FMODE_WRITE)) {
+		state->wr_ref = 1;
+		os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+		os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+		os->output = 1;
+		os->mapped = 0;
+		init_waitqueue_head(&os->frag_wq);
+		init_waitqueue_head(&os->stop_wq);
+		*os->drcmr = os->dma_ch | DRCMR_MAPVLD;
+
+		settings.mode = WM8731_MODE_PLAY;
+	}
+	if (file->f_mode & FMODE_READ) {
+		state->rd_ref = 1;
+		is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+		is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+		is->output = 0;
+		is->mapped = 0;
+		init_waitqueue_head(&is->frag_wq);
+		init_waitqueue_head(&is->stop_wq);
+		*is->drcmr = is->dma_ch | DRCMR_MAPVLD;
+
+		settings.mode = WM8731_MODE_REC;
+	}
+
+	if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
+		CorgiSetFreq(8000);
+		CorgiSetStereo(0);
+		CorgiSetFormat(AFMT_MU_LAW);
+	}
+
+	settings.output_left  = sound.volume_left;
+	settings.output_right = sound.volume_right;
+	settings.input_left   = sound.gain_left;
+	settings.input_right  = sound.gain_right;
+	settings.frequency    = sound.hw_freq;
+
+	// Open wm8731
+	err = wm8731_open(wm8731, &settings, !corgi_HPstatus);
+	if (err ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open wm8731\n");
+		goto error;
+	}
+
+	// Open I2S
+	//err = i2s_open( CORGI_DEFAULT_FREQUENCY);
+	err = i2s_open( sound.hw_freq );
+	if (err ) {
+		wm8731_close(wm8731);
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open i2s\n");
+		goto error;
+	}
+
+	// play 50msec
+	now = jiffies;
+	while(1) {
+		corgi_i2s_write(AUDIO_DATA);
+		if (jiffies > ( now + WAIT_PLAY1 ) ) break;
+	}
+
+	if (settings.mode == WM8731_MODE_REC ){
+		if(file->f_mode & FMODE_WRITE){
+			// Read & Write means earphone mic mode
+			corgi_hp_mode( CORGI_HP_HEADSET );
+		} else{
+			// mic mode
+			corgi_hp_mode( CORGI_HP_MIC );
+		}
+	} else {
+		corgi_hp_mode(CORGI_HP_AUDIO);
+	}
+
+	err = nonseekable_open(inode, file);;
+out:
+	up(&state->sem);
+	return err;
+
+error:
+	up(&state->sem);
+	if ((file->f_mode & FMODE_WRITE) && (os->dma_ch >= 0)) {
+		*os->drcmr = 0;
+		pxa_free_dma(os->dma_ch);
+	}
+	if ((file->f_mode & FMODE_READ) && (is->dma_ch >= 0)) {
+		*is->drcmr = 0;
+		pxa_free_dma(is->dma_ch);
+	}
+	state->wr_ref = 0;
+	state->rd_ref = 0;
+	return err;
+}
+
+
+/*** Platform *************************************************************/
+static int CorgiSetFormat(int format)
+{
+	int size;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "CorgiSetFormat()\n");
+
+	switch (format) {
+	case AFMT_QUERY:
+		return(sound.format);
+	case AFMT_MU_LAW:
+		size = 8;
+		ct_func = sound.trans->ct_ulaw;
+		break;
+	case AFMT_A_LAW:
+		size = 8;
+		ct_func = sound.trans->ct_alaw;
+		break;
+#if 0 // unsupport
+	case AFMT_S8:
+		size = 8;
+		ct_func = sound.trans->ct_s8;
+		break;
+	case AFMT_S16_BE:
+		size = 16;
+		ct_func = sound.trans->ct_s16be;
+		break;
+	case AFMT_U16_BE:
+		size = 16;
+		ct_func = sound.trans->ct_u16be;
+		break;
+	case AFMT_U16_LE:
+		size = 16;
+		ct_func = sound.trans->ct_u16le;
+		break;
+#endif
+	case AFMT_U8:
+		size = 8;
+		ct_func = sound.trans->ct_u8;
+		ct_read_func = sound.trans_read->ct_u8;
+		break;
+	case AFMT_S16_LE:
+		size = 16;
+		ct_func = sound.trans->ct_s16le;
+		ct_read_func = sound.trans_read->ct_s16le;
+		break;
+	default: /* :-) */
+		size = 16;
+		format = AFMT_S16_LE;
+
+	}
+
+	sound.format = format;
+	sound.size = size;
+
+	return format;
+}
+
+static void CorgiVolumeMuteTemp(void)
+{
+	// If sound driver is opened , so update volume.
+	wm8731_set_output_volume(wm8731, 0, 0, !corgi_HPstatus);
+}
+
+static void CorgiUpdateVolume(void)
+{
+	// If sound driver is opened , so update volume.
+
+	wm8731_set_output_volume(wm8731, sound.volume_left, sound.volume_right, !corgi_HPstatus);
+}
+
+static void CorgiSetVolume(int volume)
+{
+	sound.volume_left = volume & 0xff;
+	if (sound.volume_left > 100 ) sound.volume_left = 100;
+
+	sound.volume_right = ( (volume & 0xff00) >> 8);
+	if (sound.volume_right > 100 ) sound.volume_right = 100;
+
+	CorgiUpdateVolume();
+
+}
+
+static int CorgiGetVolume(void)
+{
+	return ( sound.volume_right << 8 | sound.volume_left );
+}
+
+static int CorgiSetStereo(int stereo)
+{
+	if (stereo < 0) {
+		return(sound.stereo);
+	}
+
+	stereo = !!stereo;		/* should be 0 or 1 now */
+	sound.stereo = stereo;
+	return(stereo);
+}
+
+static int CorgiSetFreq(int speed)
+{
+	int err;
+
+	if (speed < 0) {
+		return(sound.freq);
+	}
+	sound.freq = speed;
+	switch (sound.freq) {
+	case 8000:
+	case 44100:
+	case 48000:
+		sound.hw_freq = sound.freq;
+		break;
+	case 11025:
+	case 22050:
+		sound.hw_freq = 44100;
+		break;
+	case 12000:
+	case 16000:
+	case 32000:
+	case 24000:
+		sound.hw_freq = 48000;
+		break;
+	default:
+		sound.hw_freq = 44100;
+		break;
+	}
+
+	wm8731_set_freq(wm8731, sound.hw_freq);
+
+	err = i2s_close();
+	if (err ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close i2s\n");
+	}
+	err = i2s_open( sound.hw_freq );
+	if (err ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open i2s\n");
+	}
+
+	return(sound.freq);
+}
+
+static void CorgiUpdateGain(void)
+{
+	sound.gain			 = input_gain[ ( ( 6 * sound.gain_left ) / 100 ) ].gain;
+	sound.gain_shift = input_gain[ ( ( 6 * sound.gain_left ) / 100 ) ].shift;
+
+	wm8731_set_mic_gain_boost(wm8731, sound.gain);
+}
+
+static int CorgiSetGain(int gain)
+{
+	sound.gain_left = gain & 0xff;
+	if (sound.gain_left > 100 ) sound.gain_left = 100;
+
+	sound.gain_right = ( (gain & 0xff00) >> 8);
+	if (sound.gain_right > 100 ) sound.gain_right = 100;
+
+	CorgiUpdateGain();
+
+	return 1;
+}
+
+static int CorgiGetGain(void)
+{
+	return ( sound.gain_right << 8 | sound.gain_left );
+}
+
+
+static irqreturn_t Corgi_hp_in_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "Corgi_hp_interrupt\n");
+	schedule_work(&hp_proc);
+	return IRQ_HANDLED;
+}
+
+
+static void corgi_hp_mode(int mode)
+{
+	int state;
+	
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "corgi_hp_mode()\n");
+
+	if (!isPXAI2SReady ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Currently audio driver is not ready\n");
+		return;
+	}
+
+	if (corgi_HPstatus < 0 ){
+		corgi_HPstatus = GPLR(CORGI_GPIO_AK_INT) & GPIO_bit(CORGI_GPIO_AK_INT);
+	}
+	state = corgi_HPstatus;
+
+	if(( mode == CORGI_HP_AUDIO )||( mode == CORGI_HP_BUZZER )){
+		if (state ) { 	// Insert HP
+			PXAI2S_DBGPRINT(DBG_LEVEL1, "Insert HP\n");
+			mode = CORGI_HP_HP;
+		} else {	// Not Insert HP
+			PXAI2S_DBGPRINT(DBG_LEVEL1, "Not Insert HP\n");
+			mode = CORGI_HP_SOUNDER;
+		}
+	}
+	switch( mode ){
+	case CORGI_HP_SOUNDER:
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON );	/* Speaker On */
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	/* HP off */
+		break;
+	case CORGI_HP_HP:
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON );	/* Speaker Off */
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	/* HP on */
+		break;
+	case CORGI_HP_BOTH:
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON | CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R ); /* All on */
+		break;
+	case CORGI_HP_MIC:
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS );	/* MIC bias on */
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON );
+		break;
+	case CORGI_HP_HEADSET:
+		if (state ) { 	// Insert HP
+			set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS | CORGI_SCP_MUTE_R );	//	MIC bias on
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_APM_ON );
+		} else {	// Not Insert HP
+			set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON);
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L );
+		}
+		break;
+	case CORGI_HP_AUDIO:
+	case CORGI_HP_BUZZER:
+	default:
+		return;
+	}
+
+	CorgiUpdateVolume();
+}
+
+static void corgi_hp_thread(void *private_)
+{
+	int count,err;
+	int state;
+	audio_state_t	*audio_state = &pxa_audio_state;
+
+	isChkHPstatus = 1;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "corgi_hp_thread()\n");
+
+	if (audio_state->wr_ref || audio_state->rd_ref) { /* sound is playing */
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON | CORGI_SCP_MIC_BIAS);	/* HP, Speaker & Mic off */
+		CorgiVolumeMuteTemp(); /* volume zero */
+	}
+
+	while(1) {
+
+		state = GPLR(CORGI_GPIO_AK_INT) & GPIO_bit(CORGI_GPIO_AK_INT);
+		count = 0;
+		err = 0;
+		while(1) {
+			schedule_timeout(5);
+
+			if (state == (GPLR(CORGI_GPIO_AK_INT) & GPIO_bit(CORGI_GPIO_AK_INT))) {
+				count++;
+			} else {
+				err++;
+				state = GPLR(CORGI_GPIO_AK_INT) & GPIO_bit(CORGI_GPIO_AK_INT);
+				count = 0;
+			}
+
+			if (count > 10) 
+				break;
+			if (err > 50) 
+				break;
+
+	 		}
+	 		if (count > 10 ) {
+				if (state) { 	// Insert HP
+		 			PXAI2S_DBGPRINT(DBG_LEVEL1, "Insert HP\n");
+					printk("Insert HP\n");
+					corgi_HPstatus = HPJACK_STATE_HEADPHONE;
+				} else {	// Not Insert HP
+					printk("Not Insert HP\n");
+					PXAI2S_DBGPRINT(DBG_LEVEL1, "Not Insert HP\n");
+					corgi_HPstatus = HPJACK_STATE_NONE;
+				}
+			} else {
+				printk("??? HP\n");
+				PXAI2S_DBGPRINT(DBG_LEVEL1, "??? HP\n");
+				corgi_HPstatus = HPJACK_STATE_NONE;
+			}
+			break;
+		}
+	/* sound is not playing , so HP/SP be disabled. */
+	if (!audio_state->wr_ref && !audio_state->rd_ref ) {
+		isChkHPstatus = 0;
+		return;
+	}
+	
+	if (audio_state->rd_ref) { /* mic mode */
+		corgi_hp_mode((audio_state->wr_ref)? CORGI_HP_HEADSET:CORGI_HP_MIC);
+	} else {
+		corgi_hp_mode((corgi_HPstatus == HPJACK_STATE_NONE)?
+		CORGI_HP_SOUNDER : CORGI_HP_HP);
+	}
+	isChkHPstatus = 0;
+}
+
+static void CorgiInit(void)
+{
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "CorgiInit()\n");
+
+	/* MUTE */
+	reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON | CORGI_SCP_MIC_BIAS );
+
+	/* GPIO15:Both Edge */
+ 	set_irq_type(CORGI_IRQ_GPIO_AK_INT, IRQT_BOTHEDGE);	
+
+	/* Register interrupt handler. */
+	if (request_irq(CORGI_IRQ_GPIO_AK_INT, Corgi_hp_in_interrupt,
+			SA_INTERRUPT, "Audio Headphone", Corgi_hp_in_interrupt)) 
+				PXAI2S_DBGPRINT(DBG_ALWAYS, "Request_irq(%d) failed.\n", CORGI_IRQ_GPIO_AK_INT);
+
+	isPXAI2SReady = 1;
+}
+
+/*****************************************************************/
+/*
+ * /dev/sndstat
+ *	Audio Stat stuff
+ *
+ */
+static int state_open(struct inode *inode, struct file *file)
+{
+	char *buffer = pxa_i2s_state.buf;
+	int len = 0;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "state_open()\n");
+
+	if (pxa_i2s_state.busy) {
+		return -EBUSY;
+	}
+
+	pxa_i2s_state.ptr = 0;
+	pxa_i2s_state.busy = 1;
+
+	len += sprintf(buffer+len, "	CORGI I2S sound driver:\n");
+
+	len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.format);
+	switch (sound.format) {
+	case AFMT_MU_LAW:
+		len += sprintf(buffer+len, " (mu-law)");
+		break;
+	case AFMT_A_LAW:
+		len += sprintf(buffer+len, " (A-law)");
+		break;
+	case AFMT_U8:
+		len += sprintf(buffer+len, " (unsigned 8 bit)");
+		break;
+	case AFMT_S8:
+		len += sprintf(buffer+len, " (signed 8 bit)");
+		break;
+	case AFMT_S16_BE:
+		len += sprintf(buffer+len, " (signed 16 bit big)");
+		break;
+	case AFMT_U16_BE:
+		len += sprintf(buffer+len, " (unsigned 16 bit big)");
+		break;
+	case AFMT_S16_LE:
+		len += sprintf(buffer+len, " (signed 16 bit little)");
+		break;
+	case AFMT_U16_LE:
+		len += sprintf(buffer+len, " (unsigned 16 bit little)");
+		break;
+	}
+	len += sprintf(buffer+len, "\n");
+	len += sprintf(buffer+len, "\tsound.speed = %dHz \n",sound.freq);
+	len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+					 sound.stereo, sound.stereo ? "stereo" : "mono");
+	pxa_i2s_state.len = len;
+
+	return 0;
+}
+
+
+static int state_release(struct inode *inode, struct file *file)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "state_release()\n");
+	
+	pxa_i2s_state.busy = 0;
+	return 0;
+}
+
+
+static ssize_t state_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	int n;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "state_read()\n");
+	
+	n = pxa_i2s_state.len - pxa_i2s_state.ptr;
+	if (n > count)
+		n = count;
+	if (n <= 0) {
+		return 0;
+	}
+	if (copy_to_user(buf, &pxa_i2s_state.buf[pxa_i2s_state.ptr], n)) {
+		return -EFAULT;
+	}
+	pxa_i2s_state.ptr += n;
+	return n;
+}
+
+static struct file_operations state_fops =
+{
+	llseek:	no_llseek,
+	read:		state_read,
+	open:		state_open,
+	release:	state_release,
+};
+
+static void __init state_init(void)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "state_init()\n");
+	
+	/* Register /dev/sndstat */
+	pxa_i2s_state.dev_state = register_sound_special(&state_fops, SND_DEV_STATUS);
+	if (pxa_i2s_state.dev_state < 0 ) {
+		return;
+	}
+	pxa_i2s_state.busy = 0;
+}
+
+
+/*****************************************************************/
+/*
+ *	/dev/mixer
+ *	Audio Mixer stuff
+ *
+ */
+
+static int mixer_ioctl( struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	int data;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "mixer_ioctl(): cmd: %d\n", cmd);
+
+	switch (cmd) {
+	case SOUND_MIXER_READ_DEVMASK:
+		return IOCTL_OUT(arg, (SOUND_MASK_VOLUME|SOUND_MASK_MIC) );
+	case SOUND_MIXER_READ_RECMASK:
+		return IOCTL_OUT(arg, 0);
+	case SOUND_MIXER_READ_STEREODEVS:
+		return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+	case SOUND_MIXER_READ_CAPS:
+		return IOCTL_OUT(arg, 0);
+	case SOUND_MIXER_WRITE_VOLUME:
+		IOCTL_IN(arg, data);
+		CorgiSetVolume(data);
+	case SOUND_MIXER_READ_VOLUME:
+		return IOCTL_OUT(arg, CorgiGetVolume());
+	case SOUND_MIXER_READ_TREBLE:
+		return IOCTL_OUT(arg, 0);
+	case SOUND_MIXER_WRITE_TREBLE:
+		return IOCTL_OUT(arg, 0);
+	case SOUND_MIXER_READ_SPEAKER:
+		return IOCTL_OUT(arg, 0);
+	case SOUND_MIXER_WRITE_SPEAKER:
+		return IOCTL_OUT(arg, 0);
+
+	case SOUND_MIXER_WRITE_MIC:
+		IOCTL_IN(arg, data);
+		//printk("<mic data>:%x\n",data);
+		CorgiSetGain(data);
+	case SOUND_MIXER_READ_MIC:
+		return IOCTL_OUT(arg, CorgiGetGain());
+
+	}
+
+	return -EINVAL;
+
+}
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "mixer_open()\n");
+	
+	if (pxa_i2s_codec.busy)
+		return -EBUSY;
+
+	pxa_i2s_codec.busy = 1;
+	return 0;
+}
+
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "mixer_release()\n");
+	
+	pxa_i2s_codec.busy = 0;
+	return 0;
+}
+
+
+static struct file_operations corgi_mixer_fops = {
+	ioctl:		mixer_ioctl,
+	llseek:		no_llseek,
+	open:		mixer_open,
+	release: 	mixer_release,
+	owner:		THIS_MODULE
+};
+
+static void __init mixer_init(void)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "mixer_init()\n");
+	
+	// Regist /dev/mixer.
+	pxa_i2s_codec.dev_mixer = register_sound_mixer(&corgi_mixer_fops, -1);
+	if (pxa_i2s_codec.dev_mixer < 0 ) {
+		return;
+	}
+	pxa_i2s_codec.busy = 0;
+}
+
+/*****************************************************************/
+/*
+ *	/dev/dsp
+ *	Audio stuff
+ */
+
+static struct file_operations corgi_audio_fops =
+{
+	llseek:		no_llseek,
+	write:		audio_write,
+	read:		audio_read,
+	poll:		audio_poll,
+	ioctl:		audio_ioctl,
+	open:		audio_open,
+	release:	audio_release,
+	mmap:		audio_mmap,
+};
+
+static void __init sq_init(void)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "sq_init()\n");
+	
+	// Regist /dev/dsp.
+	pxa_audio_state.dev_dsp = register_sound_dsp(&corgi_audio_fops, -1);
+	if (pxa_audio_state.dev_dsp < 0)
+		return;
+
+	pxa_audio_state.wr_ref = 0;
+	pxa_audio_state.rd_ref = 0;
+
+	// Set Default Settings
+	sound.format = AFMT_S16_LE;
+	sound.stereo = 1;
+	sound.freq = 44100;
+	sound.hw_freq = 44100;
+	sound.size = 16;
+	sound.trans = &transCorgi;
+	sound.trans_read = &transReadCorgi;
+
+	sound.volume_left = 80;
+	sound.volume_right = 80;
+
+	sound.gain_left = 40;
+	sound.gain_right = 40;
+
+	// Change Format
+	CorgiSetFormat(sound.format);
+
+}
+
+
+/*** Power Management ****************************************************/
+#ifdef CONFIG_PM
+static int corgi_snd_suspend(struct device *dev, pm_message_t state)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "corgi_snd_suspend()\n");
+
+	int err;
+
+	if (pxa_audio_state.rd_ref || pxa_audio_state.wr_ref) {
+		err = i2s_close();
+		if (err) {
+			PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close i2s\n");
+		}
+	}
+
+	if (pxa_audio_state.rd_ref != 0) {
+		pxa_audio_clear_buf(pxa_audio_state.input_stream);
+		*pxa_audio_state.input_stream->drcmr = 0;
+		pxa_free_dma(pxa_audio_state.input_stream->dma_ch);
+	}
+
+	if (pxa_audio_state.wr_ref != 0) {
+		pxa_audio_clear_buf(pxa_audio_state.output_stream);
+		*pxa_audio_state.output_stream->drcmr = 0;
+		pxa_free_dma(pxa_audio_state.output_stream->dma_ch);
+	}
+		
+	corgi_HPstatus = HPJACK_STATE_UNDETECT;
+
+	return 0;
+}
+
+
+static int corgi_snd_resume(struct device *dev)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "corgi_snd_resume()\n");
+
+
+	int err;
+	/* request DMA channels */
+	if (pxa_audio_state.wr_ref != 0 ) {
+		init_waitqueue_head(&pxa_audio_state.output_stream->frag_wq);
+		init_waitqueue_head(&pxa_audio_state.output_stream->stop_wq);
+		*pxa_audio_state.output_stream->drcmr = pxa_audio_state.output_stream->dma_ch | DRCMR_MAPVLD;
+		err = pxa_request_dma(pxa_audio_state.output_stream->name, DMA_PRIO_LOW,
+				audio_dma_irq, pxa_audio_state.output_stream);
+
+		if (err < 0 ) 
+			PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not get DMA\n");
+		pxa_audio_state.output_stream->dma_ch = err;
+	}
+
+	if (pxa_audio_state.rd_ref != 0) {
+		init_waitqueue_head(&pxa_audio_state.input_stream->frag_wq);
+		init_waitqueue_head(&pxa_audio_state.input_stream->stop_wq);
+		*pxa_audio_state.input_stream->drcmr = pxa_audio_state.input_stream->dma_ch | DRCMR_MAPVLD;
+
+		err = pxa_request_dma(pxa_audio_state.input_stream->name, DMA_PRIO_LOW,
+				audio_dma_irq, pxa_audio_state.input_stream);
+		if (err < 0) 
+			PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not get DMA\n");
+		pxa_audio_state.input_stream->dma_ch = err;
+	}
+
+	if (pxa_audio_state.rd_ref || pxa_audio_state.wr_ref) {
+		//wm8731_resume();
+		err = i2s_open(sound.hw_freq);
+		if (err)
+			PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open i2s\n");
+		schedule_work(&hp_proc);
+	}
+
+	return 0;
+}
+#else
+#define corgi_snd_suspend		NULL
+#define corgi_snd_resume		NULL
+#endif
+
+
+/*** Config & Setup *********************************************************/
+static int __init corgi_snd_probe(struct device *dev) 
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "corgi_snd_probe()\n");
+
+	printk("Corgi audio driver initialize\n");
+
+	CorgiInit();
+
+	/* Set default settings and /dev/dsp */
+	sq_init();
+
+	/* Set up /dev/sndstat. */
+	state_init();
+
+	/* Set up /dev/mixer. */
+	mixer_init();
+
+	return 0;
+}
+
+static int corgi_snd_remove(struct device *dev) 
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "corgi_snd_remove()\n");
+		// FIXME : release buffer
+	if (pxa_audio_state.dev_dsp >= 0 ) 
+		unregister_sound_dsp(pxa_audio_state.dev_dsp);
+	if (pxa_i2s_codec.dev_mixer >= 0 ) 
+		unregister_sound_mixer(pxa_i2s_codec.dev_mixer);
+	if (pxa_i2s_state.dev_state >= 0 )
+		unregister_sound_special(pxa_i2s_state.dev_state);
+		
+	return 0;
+}
+
+static struct device_driver corgi_snd_driver = {
+	.name		= "corgi-sound",
+	.bus		= &platform_bus_type,
+	.probe		= corgi_snd_probe,
+	.remove		= corgi_snd_remove,
+	.suspend	= corgi_snd_suspend,
+	.resume		= corgi_snd_resume,
+};
+
+static struct platform_device corgisound_device = {
+	.name		= "corgi-sound",
+	.id		= -1,
+};
+
+void corgisnd_wm8731_active(struct wm8731_priv *wm8731_priv)
+{
+	wm8731=wm8731_priv;
+	corgisound_device.dev.parent=&wm8731_priv->client.dev;
+	platform_device_register(&corgisound_device);
+}
+
+static int __devinit corgi_snd_init(void)
+{
+	int err;	
+	if (!(machine_is_corgi() || machine_is_shepherd() || machine_is_husky()))
+		return -ENODEV;
+	err = wm8731_activate(corgisnd_wm8731_active);
+	if (err)
+		return err;
+	return driver_register(&corgi_snd_driver);
+}
+
+static void __exit corgi_snd_exit(void)
+{
+ 	driver_unregister(&corgi_snd_driver);
+}
+
+module_init(corgi_snd_init);
+module_exit(corgi_snd_exit);
+
+//MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Corgi Sound Driver");
+MODULE_LICENSE("GPL");
Index: linux-2.6.14/sound/oss/pxa_audio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.14/sound/oss/pxa_audio.h	2005-10-31 21:42:36.000000000 +0000
@@ -0,0 +1,69 @@
+/*
+ *  linux/drivers/sound/pxa-audio.h -- audio interface for the Cotula chip
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	Aug 15, 2001
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <asm/dma.h>
+
+/* default combinations */
+#define DCMD_RXPCDR	(DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
+#define DCMD_RXMCDR	(DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
+#define DCMD_TXPCDR	(DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4)
+
+typedef struct {
+	int offset;			/* current buffer position */
+	char *data; 	           	/* actual buffer */
+	pxa_dma_desc *dma_desc;		/* pointer to the starting desc */
+	int master;             	/* owner for buffer allocation, contain size whn true */
+} audio_buf_t;
+
+typedef struct {
+	char *name;			/* stream identifier */
+	audio_buf_t *buffers;   	/* pointer to audio buffer array */
+	u_int usr_frag;			/* user fragment index */
+	u_int dma_frag;			/* DMA fragment index */
+	u_int fragsize;			/* fragment size */
+	u_int nbfrags;			/* number of fragments */
+	u_int dma_ch;			/* DMA channel number */
+	dma_addr_t dma_desc_phys;	/* phys addr of descriptor ring */
+	u_int descs_per_frag;		/* nbr descriptors per fragment */
+	int bytecount;			/* nbr of processed bytes */
+	int fragcount;			/* nbr of fragment transitions */
+	struct semaphore sem;		/* account for fragment usage */
+	wait_queue_head_t frag_wq;	/* for poll(), etc. */
+	wait_queue_head_t stop_wq;	/* for users of DCSR_STOPIRQEN */
+	u_long dcmd;			/* DMA descriptor dcmd field */
+	volatile u32 *drcmr;		/* the DMA request channel to use */
+	u_long dev_addr;		/* device physical address for DMA */
+	int mapped:1;			/* mmap()'ed buffers */
+	int output:1;			/* 0 for input, 1 for output */
+} audio_stream_t;
+	
+typedef struct {
+	audio_stream_t *output_stream;
+	audio_stream_t *input_stream;
+	int dev_dsp;			/* audio device handle */
+	int rd_ref:1;           /* open reference for recording */
+	int wr_ref:1;           /* open reference for playback */
+	int (*client_ioctl)(struct inode *, struct file *, uint, ulong);
+	struct semaphore sem;		/* prevent races in attach/release */
+} audio_state_t;
+
+extern void corgi_i2s_write(unsigned int data);
+
+extern void pxa_audio_clear_buf(audio_stream_t *s);
+extern audio_state_t pxa_audio_state;
+extern int audio_setup_buf(audio_stream_t * s, int is_clr);
+extern void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs);
+extern int audio_set_fragments(audio_stream_t *s, int val);
+
+int i2s_open(unsigned int);
+int i2s_close(void);
+
Index: linux-2.6.14/sound/oss/wm8731.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.14/sound/oss/wm8731.c	2005-10-31 21:42:36.000000000 +0000
@@ -0,0 +1,395 @@
+/*
+ * Audio driver for Wolfson WM8731
+ *
+ * Copyright (c) 2004 Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include "wm8731.h"
+
+static struct i2c_driver wm8731_driver;
+
+static void (*wm8731_startup_callback)(struct wm8731_priv *wm8731_priv);
+static unsigned short normal_i2c[] = {
+	WM8731_DEV_ADR0, WM8731_DEV_ADR1, I2C_CLIENT_END 
+};
+I2C_CLIENT_INSMOD;
+
+static unsigned int wm8731_volumes_heaphone[31] = {
+	  0,  65,  90,  94,  97, 100, 101, 102, 103, 104, 
+	105, 106, 107, 107, 108, 108, 109, 110, 110, 111, 
+	112, 112, 113, 113, 114, 114, 115, 115, 116, 117
+};
+
+static unsigned int wm8731_volumes_speaker[31] = {
+	  0,  50,  65,  70,  75,  80,  84,  87,  90,  92, 
+	 94,  95,  97,  99, 100, 102, 104, 106, 108, 110, 
+	111, 112, 113, 115, 116, 118, 120, 122, 125, 127
+};
+
+int wm8731_reg_write(struct i2c_client *clnt, unsigned char address, unsigned short data)
+{
+	char buffer[2];
+	int r;
+
+	printk("%s: writing %x, %x\n", __FUNCTION__, address, data);
+
+	buffer[0] = ((address << 1) | ((data >> 8) & 1));
+	buffer[1] = data & 0xff;
+
+	r = i2c_master_send(clnt, buffer, 2);
+	if (r != 2) {
+		printk(KERN_ERR "wm8731: Write failed, status %d\n", r);
+		return r;
+	}
+
+	if (address < MAX_REG_CACHE) {
+		struct wm8731_priv *wm8731 = i2c_get_clientdata(clnt);
+		wm8731->regs[address] = data;
+	}
+	return 0;
+}
+
+/* 
+ * Shadown Register Operations 
+ */
+static int wm8731_set_hpout_shadow(struct wm8731_priv *wm8731, int adr, int vol, int headphone)
+{
+	if ((vol < 0) || (vol > 100)) {
+		printk(KERN_ERR "wm8731: Incorrect volume setting.\n");
+		return -1;
+	}
+
+	if (headphone)
+		vol = wm8731_volumes_heaphone[29*vol/100];
+	else
+		vol = wm8731_volumes_speaker[29*vol/100];
+
+	if ((wm8731->regs[adr] & WM8731_HPOUT_VOL_MASK) != vol) {
+		wm8731->regs[adr] = (wm8731->regs[adr] & ~WM8731_HPOUT_VOL_MASK) | vol;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int wm8731_set_linein_shadow(struct wm8731_priv *wm8731, int adr, int vol)
+{
+	if ((vol < WM8731_LINEIN_VOL_MIN) && (vol > WM8731_LINEIN_VOL_MAX))
+		return -1;
+			 
+	if (vol == 0) {
+		if(wm8731->regs[adr] & WM8731_LINEIN_MUTE_ON)
+			return 0;
+		wm8731->regs[adr] |= WM8731_LINEIN_MUTE_ON;
+		return 1;
+	} 
+
+	if ((wm8731->regs[adr] & WM8731_LINEIN_MUTE_ON) 
+			|| ((wm8731->regs[adr] & WM8731_LINEIN_VOL_MASK) != vol)) {
+		wm8731->regs[adr] = (wm8731->regs[adr] & ~(WM8731_LINEIN_MUTE_ON | WM8731_LINEIN_VOL_MASK)) | vol;
+		return 1;
+	}
+	return 0;
+}
+
+static int wm8731_set_mic_boost_shadow(struct wm8731_priv *wm8731, int on)
+{
+	unsigned short reg = wm8731->regs[WM8731_ADR_AP_ANALOG];
+
+	if (on)
+		wm8731->regs[WM8731_ADR_AP_ANALOG] |= WM8731_AAP_MIC_BOOST;
+	else
+		wm8731->regs[WM8731_ADR_AP_ANALOG] &= ~WM8731_AAP_MIC_BOOST;
+
+	if (reg != wm8731->regs[WM8731_ADR_AP_ANALOG])
+		return 1;
+	return 0;
+}
+
+static int wm8731_set_freq_shadow(struct wm8731_priv *wm8731, int freq)
+{
+	unsigned short reg = wm8731->regs[WM8731_ADR_SAMPLING];
+
+	switch (freq) {
+	case 8000:
+		wm8731->regs[WM8731_ADR_SAMPLING] = (WM8731_SAMP_BOTH_48KHZ | WM8731_SAMP_NORMAL_MODE);
+		//wm8731->regs[WM8731_ADR_SAMPLING] = (WM8731_SAMP_BOTH_8KHZ | WM8731_SAMP_NORMAL_MODE );
+		break;
+
+	case 44100:
+		wm8731->regs[WM8731_ADR_SAMPLING] = (WM8731_SAMP_BOTH_44KHZ | WM8731_SAMP_NORMAL_MODE);
+		break;
+
+	case 48000:
+		wm8731->regs[WM8731_ADR_SAMPLING] = (WM8731_SAMP_BOTH_44KHZ | WM8731_SAMP_NORMAL_MODE);
+		break;
+
+	default:
+		wm8731->regs[WM8731_ADR_SAMPLING] = (WM8731_SAMP_BOTH_44KHZ | WM8731_SAMP_NORMAL_MODE);
+		break;
+	}
+	if (reg != wm8731->regs[WM8731_ADR_AP_ANALOG])
+		return 1;
+	return 0;
+}
+
+/*
+ * Public Funcitons
+ */
+int wm8731_set_output_volume(struct wm8731_priv *wm8731, int left, int right, int headphone)
+{
+	if (wm8731_set_hpout_shadow(wm8731, WM8731_ADR_HPOUT_L, left, headphone) > 0)
+		wm8731_reg_write(&wm8731->client, WM8731_ADR_HPOUT_L, wm8731->regs[WM8731_ADR_HPOUT_L]);
+
+	if (wm8731_set_hpout_shadow(wm8731, WM8731_ADR_HPOUT_R, right, headphone) > 0)
+		wm8731_reg_write(&wm8731->client, WM8731_ADR_HPOUT_R, wm8731->regs[WM8731_ADR_HPOUT_R]);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(wm8731_set_output_volume);
+
+int wm8731_set_input_volume(struct wm8731_priv *wm8731, int left, int right)
+{
+	if (wm8731_set_linein_shadow(wm8731, WM8731_ADR_LINEIN_L, left) > 0)
+		wm8731_reg_write(&wm8731->client, WM8731_ADR_LINEIN_L, wm8731->regs[WM8731_ADR_LINEIN_L]);
+
+	if (wm8731_set_linein_shadow(wm8731, WM8731_ADR_LINEIN_R, right) > 0)
+		wm8731_reg_write(&wm8731->client, WM8731_ADR_LINEIN_R, wm8731->regs[WM8731_ADR_LINEIN_R]);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(wm8731_set_input_volume);
+
+int wm8731_set_mic_gain_boost(struct wm8731_priv *wm8731, int on)
+{
+	if (wm8731_set_mic_boost_shadow(wm8731, on) > 0)
+		wm8731_reg_write(&wm8731->client,  WM8731_ADR_AP_ANALOG , wm8731->regs[WM8731_ADR_AP_ANALOG] );
+
+	return 0;
+}
+
+EXPORT_SYMBOL(wm8731_set_mic_gain_boost);
+
+int wm8731_set_freq(struct wm8731_priv *wm8731, int freq)
+{
+	if (wm8731_set_freq_shadow(wm8731, freq) > 0) 
+		wm8731_reg_write(&wm8731->client, WM8731_ADR_SAMPLING, wm8731->regs[WM8731_ADR_SAMPLING]);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(wm8731_set_freq);
+
+int wm8731_open(struct wm8731_priv *wm8731, struct wm8731_settings *settings, int headphone)
+{
+	int i;
+
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_RESET, 0);
+
+	switch (settings->mode) {
+		case WM8731_MODE_PLAY:
+			wm8731->regs[0] = WM8731_LINEIN_MUTE_ON | WM8731_LINEIN_VOL_INIT;
+			wm8731->regs[1] = WM8731_LINEIN_MUTE_ON | WM8731_LINEIN_VOL_INIT;
+			wm8731->regs[2] = WM8731_HPOUT_VOL_INIT;
+			wm8731->regs[3] = WM8731_HPOUT_VOL_INIT;
+			wm8731->regs[4] = WM8731_AAP_DAC_SELECT | WM8731_AAP_INPUT_LINE | WM8731_AAP_MIC_MUTE;
+			wm8731->regs[5] = 0;
+			wm8731->regs[6] = WM8731_PD_OSC | WM8731_PD_CLK | WM8731_PD_ADC | WM8731_PD_MIC | WM8731_PD_LIN;
+			wm8731->regs[7] = WM8731_DAIF_MS_SLAVE | WM8731_DAIF_IWL_16BIT | WM8731_DAIF_MODE_I2S;
+			wm8731->regs[8] = WM8731_SAMP_BOTH_44KHZ | WM8731_SAMP_NORMAL_MODE;
+			break;
+
+		case WM8731_MODE_REC:
+			wm8731->regs[0] = WM8731_LINEIN_VOL_INIT;
+			wm8731->regs[1] = WM8731_LINEIN_VOL_INIT;
+			wm8731->regs[2] = WM8731_HPOUT_VOL_INIT;
+			wm8731->regs[3] = WM8731_HPOUT_VOL_INIT;
+			wm8731->regs[4] = WM8731_AAP_MIC_BOOST | WM8731_AAP_INPUT_MIC | WM8731_AAP_DAC_SELECT;
+			wm8731->regs[5] = 0;
+			wm8731->regs[6] = WM8731_PD_OSC | WM8731_PD_CLK | WM8731_PD_LIN;
+			wm8731->regs[7] = WM8731_DAIF_MS_SLAVE | WM8731_DAIF_IWL_16BIT | WM8731_DAIF_MODE_I2S;
+			wm8731->regs[8] = WM8731_SAMP_BOTH_44KHZ | WM8731_SAMP_NORMAL_MODE;
+			break;
+
+		default:
+			return -1;
+	}
+
+	wm8731_set_hpout_shadow(wm8731, WM8731_ADR_HPOUT_L, settings->output_left, headphone);
+	wm8731_set_hpout_shadow(wm8731, WM8731_ADR_HPOUT_R, settings->output_right, headphone);
+	wm8731_set_linein_shadow(wm8731, WM8731_ADR_LINEIN_L, settings->input_left);
+	wm8731_set_linein_shadow(wm8731, WM8731_ADR_LINEIN_R, settings->input_right);
+	wm8731_set_freq_shadow(wm8731, settings->frequency);
+
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_PWRDOWN, wm8731->regs[WM8731_ADR_PWRDOWN]);
+
+	for(i=0; i<MAX_REG_CACHE; i++) {
+		if (i == WM8731_ADR_PWRDOWN) 
+			continue;
+		wm8731_reg_write(&wm8731->client, i, wm8731->regs[i]);
+	}
+
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_ACTIVATE, 1);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(wm8731_open);
+
+int wm8731_close(struct wm8731_priv *wm8731)
+{
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_ACTIVATE, 0);
+	mdelay(1);
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_RESET, 0);
+	mdelay(1);
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_PWRDOWN, WM8731_PD_OUT);
+	mdelay(1);
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_PWRDOWN, WM8731_PD_ALL);
+	return 0;
+}
+
+EXPORT_SYMBOL(wm8731_close);
+
+static int wm8731_command(struct i2c_client *clnt, unsigned int cmd, void *arg)
+{
+	int ret = -EINVAL;
+
+	//if (_IOC_TYPE(cmd) == 'M')
+	//	ret = wm8731_mixer_ioctl(clnt, cmd, arg);
+	//else if (cmd == I2C_WM8731_CONFIGURE)
+	//	ret = wm8731_configure(clnt, arg);
+	//else if (cmd == I2C_WM8731_OPEN)
+	//	ret = wm8731_open(clnt);
+	//else if (cmd == I2C_WM8731_CLOSE)
+	//	(ret = 0), wm8731_close(clnt);
+
+	return ret;
+}
+
+static int wm8731_attach(struct i2c_adapter *adap, int addr, int kind)		
+{
+	struct wm8731_priv *wm8731;
+	int i;
+
+	wm8731 = kcalloc(1, sizeof(*wm8731), GFP_KERNEL);
+	if (!wm8731)
+		return 0;
+
+	wm8731->client.addr = addr;
+	wm8731->client.adapter = adap;
+	wm8731->client.driver = &wm8731_driver;
+	strlcpy(wm8731->client.name, "wm8731", I2C_NAME_SIZE);
+
+	i2c_set_clientdata(&wm8731->client, wm8731);
+	i2c_attach_client(&wm8731->client);
+
+	for(i=0; i<MAX_REG_CACHE; i++)
+    		wm8731->regs[i]=0;
+
+	/* Reset and Powerdown all the wm8731 sections */
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_RESET, 0);
+	mdelay(1);
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_PWRDOWN, WM8731_PD_ALL);
+
+	wm8731_startup_callback(wm8731);
+	
+	return 0;
+}
+
+static int wm8731_attach_adapter(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, wm8731_attach);
+}
+
+static int wm8731_detach_client(struct i2c_client *clnt)
+{
+	int err = i2c_detach_client(clnt);
+
+	if (err)
+		return err;
+
+	kfree(i2c_get_clientdata(clnt));
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8731_suspend(struct device *dev, pm_message_t state)
+{
+	struct wm8731_priv *wm8731 = dev_get_drvdata(dev);
+
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_ACTIVATE, 0 );
+	mdelay(1);
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_RESET, 0);
+  	mdelay(1);
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_PWRDOWN, WM8731_PD_OUT);
+	mdelay(1);
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_PWRDOWN, WM8731_PD_ALL);
+
+	return 0;
+}
+static int wm8731_resume(struct device *dev)
+{
+	int i;
+	struct wm8731_priv *wm8731 = dev_get_drvdata(dev);
+
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_PWRDOWN, wm8731->regs[WM8731_ADR_PWRDOWN]);
+
+	for(i=0; i<MAX_REG_CACHE; i++) {
+		if (i == WM8731_ADR_PWRDOWN) 
+			continue;
+		wm8731_reg_write(&wm8731->client, i, wm8731->regs[i]);
+	}
+
+	wm8731_reg_write(&wm8731->client, WM8731_ADR_ACTIVATE, 1);
+
+	return 0;
+}
+#else
+#define wm8731_suspend		NULL
+#define wm8731_resume		NULL
+#endif
+
+static struct i2c_driver wm8731_driver = {
+	.owner          = THIS_MODULE,
+	.name		= "wm8731",
+	.id		= I2C_DRIVERID_EXP0,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= wm8731_attach_adapter,
+	.detach_client	= wm8731_detach_client,
+	.command        = wm8731_command,
+	.driver         = {
+		.resume    = wm8731_resume,
+ 		.suspend   = wm8731_suspend,
+	},
+};
+
+int wm8731_activate(void (*callback)(struct wm8731_priv *wm8731_priv))
+{
+	wm8731_startup_callback=callback;
+	return i2c_add_driver(&wm8731_driver);
+}
+
+EXPORT_SYMBOL(wm8731_activate);
+
+static int __init wm8731_init(void) 
+{
+	return 0;
+}
+
+static void __exit wm8731_exit(void) 
+{
+	i2c_del_driver(&wm8731_driver); 
+}
+
+module_init(wm8731_init);
+module_exit(wm8731_exit);
Index: linux-2.6.14/sound/oss/pxa_audio.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.14/sound/oss/pxa_audio.c	2005-10-31 22:15:21.000000000 +0000
@@ -0,0 +1,398 @@
+/*
+ * PXA I2S functions 
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <asm/arch/hardware.h>
+#include <asm/mach/arch.h>
+#include <asm/arch/pxa-regs.h>
+#include "pxa_audio.h"
+
+//#define MY_TRACE	4
+
+#define DBG_ALWAYS	0
+#define DBG_LEVEL1	1
+#define DBG_LEVEL2	2
+#define DBG_LEVEL3	3
+
+#ifdef MY_TRACE
+#define PXAI2S_DBGPRINT(level, x, args...)	if (level <= MY_TRACE ) printk("%s: " x,__FUNCTION__ ,##args)
+#else
+#define PXAI2S_DBGPRINT(level, x, args...)	if (!level ) printk("%s: " x,__FUNCTION__ ,##args)
+#endif
+
+#define AUDIO_BUFFER_SETUP_NOCLEAR	1
+//#undef AUDIO_BUFFER_SETUP_NOCLEAR
+
+static unsigned char isInUseI2S;
+
+#define SADIV_MASK       0x7f
+#define MAX_DMA_SIZE     4096
+#define DMA_DESC_SIZE    sizeof(pxa_dma_desc)
+
+int i2s_open(unsigned int freq)
+{
+	int div;
+
+	if (isInUseI2S) {
+		printk(KERN_ERR "i2s device is busy\n");
+		return -EBUSY;
+	}
+
+	//if (freq == 8000) 
+	//	freq = 48000;
+
+	freq /= 1000;			// calc sampling freq.
+	if ((freq > 48) || (freq < 8))
+		return -EINVAL;
+	div = (147600/(freq*64*4));
+
+	//printk(KERN_DEBUG "div = %x\n",div);
+
+	isInUseI2S = 1;
+
+	CKEN |= CKEN8_I2S;		// clock enable
+
+	SACR0 |= SACR0_RST;	// reset
+	SACR0 &= ~SACR0_ENB;	// disable module
+	SACR0 &= ~SACR0_RST;
+
+	SACR0 |= SACR0_BCKD;	// output BITCLK
+	SACR0 |= 0x7700;
+	SACR0 &= ~(SACR0_EFWR | SACR0_STRF);
+
+	SADR = 0x0000;
+	SADIV = (div & SADIV_MASK);
+	SACR1 &= ~(SACR1_AMSL | SACR1_DREC | SACR1_DRPL | SACR1_ENLBF);
+
+	SACR0 |= SACR0_ENB;	// enable module
+
+	return 0;
+}
+
+EXPORT_SYMBOL(i2s_open);
+
+int i2s_close()
+{
+	isInUseI2S = 0;
+
+	SACR0 |= SACR0_RST;	// reset
+	SACR0 &= ~SACR0_ENB;	// disable module
+	SACR0 &= ~SACR0_RST;
+
+	CKEN &= ~CKEN8_I2S;		// clock disable
+
+	return 0;
+}
+EXPORT_SYMBOL(i2s_close);
+
+inline void corgi_i2s_write(unsigned int data)
+{
+	if (SASR0 & SASR0_TUR )
+		SAICR = SASR0_TUR;
+	while((SASR0 & SASR0_TNF) == 0) 
+		{};
+	SADR = data;
+}
+
+EXPORT_SYMBOL(corgi_i2s_write);
+
+audio_stream_t pxa_audio_out = {
+	name:			"I2S audio out",
+	dcmd:			DCMD_TXPCDR,
+	drcmr:			&DRCMRTXSADR,
+	dev_addr:		__PREG(SADR),
+};
+
+audio_stream_t pxa_audio_in = {
+	name:			"I2S audio in",
+	dcmd:			DCMD_RXPCDR,
+	drcmr:			&DRCMRRXSADR,
+	dev_addr:		__PREG(SADR),
+};
+
+audio_state_t pxa_audio_state = {
+	output_stream:		&pxa_audio_out,
+	input_stream:		&pxa_audio_in,
+	sem:			__SEMAPHORE_INIT(pxa_audio_state.sem, 1),
+};
+
+EXPORT_SYMBOL(pxa_audio_state);
+
+/*
+ * This function frees all buffers
+ */
+void pxa_audio_clear_buf(audio_stream_t * s)
+{
+	int frag;
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "pxa_audio_clear_buf()\n");
+
+	if (!s->buffers)
+		return;
+
+
+	/* Only get a stop interrupt if DCMDx[LENGTH] != 0 so check */
+	if ((DCMD(s->dma_ch) & DCMD_LENGTH) && !(DCSR(s->dma_ch) & DCSR_STOPSTATE)) {
+		DEFINE_WAIT(wait);
+	    prepare_to_wait(&s->stop_wq, &wait, TASK_UNINTERRUPTIBLE);
+		/* Ensure DMA isn't running */
+		DCSR(s->dma_ch) = DCSR_STOPIRQEN;
+		schedule();
+    	finish_wait(&s->stop_wq, &wait);
+	}
+
+	/* free DMA buffers */
+	for (frag = 0; frag < s->nbfrags; frag++) {
+		audio_buf_t *b = &s->buffers[frag];
+		if (!b->master)
+			continue;
+		dma_free_coherent(NULL,b->master,b->data,	b->dma_desc->dsadr);
+	}
+
+	/* free descriptor ring */
+	if (s->buffers->dma_desc)
+		dma_free_coherent(NULL,	
+				s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE,s->buffers->dma_desc,
+				s->dma_desc_phys);
+
+	/* free buffer structure array */
+	kfree(s->buffers);
+	s->buffers = NULL;
+}
+
+EXPORT_SYMBOL(pxa_audio_clear_buf);
+
+int audio_setup_buf(audio_stream_t * s, int is_clr)
+{
+	pxa_dma_desc *dma_desc;
+	dma_addr_t dma_desc_phys;
+	int nb_desc, frag, i, buf_size = 0;
+	char *dma_buf = NULL;
+	dma_addr_t dma_buf_phys = 0;
+
+#ifdef AUDIO_BUFFER_SETUP_NOCLEAR
+	is_clr=1;
+#endif
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "Enter audio_setup buffer\n");
+
+	if (s->buffers)
+		return -EBUSY;
+
+	/* Our buffer structure array */
+	s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
+	if (!s->buffers)
+		goto err;
+	memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags);
+
+	/* 
+	 * Our DMA descriptor array:
+	 * for Each fragment we have one checkpoint descriptor plus one 
+	 * descriptor per MAX_DMA_SIZE byte data blocks.
+	 */
+	nb_desc = (1 + (s->fragsize + MAX_DMA_SIZE - 1)/MAX_DMA_SIZE) * s->nbfrags;
+	dma_desc = dma_alloc_coherent(NULL,
+						nb_desc * DMA_DESC_SIZE,
+						&dma_desc_phys,GFP_KERNEL);
+	if (!dma_desc)
+		goto err;
+	s->descs_per_frag = nb_desc / s->nbfrags;
+	s->buffers->dma_desc = dma_desc;
+	s->dma_desc_phys = dma_desc_phys;
+	for (i = 0; i < nb_desc - 1; i++)
+		dma_desc[i].ddadr = dma_desc_phys + (i + 1) * DMA_DESC_SIZE;
+	dma_desc[i].ddadr = dma_desc_phys;
+
+
+	/* Our actual DMA buffers */
+	for (frag = 0; frag < s->nbfrags; frag++) {
+		audio_buf_t *b = &s->buffers[frag];
+
+		/*
+		 * Let's allocate non-cached memory for DMA buffers.
+		 * We try to allocate all memory at once.
+		 * If this fails (a common reason is memory fragmentation),
+		 * then we'll try allocating smaller buffers.
+		 */
+		if (!buf_size) {
+			buf_size = (s->nbfrags - frag) * s->fragsize;
+			do {
+				dma_buf = dma_alloc_coherent(NULL,
+								 buf_size, 
+								 &dma_buf_phys,GFP_KERNEL);
+				if (!dma_buf)
+					buf_size -= s->fragsize;
+			} while (!dma_buf && buf_size);
+			if (!dma_buf)
+				goto err;
+			b->master = buf_size;
+
+			if (is_clr ){
+				memzero(dma_buf, buf_size);
+			}
+		}
+
+		/* 
+		 * Set up our checkpoint descriptor.	Since the count 
+		 * is always zero, we'll abuse the dsadr and dtadr fields
+		 * just in case this one is picked up by the hardware
+		 * while processing SOUND_DSP_GETPTR.
+		 */
+		dma_desc->dsadr = dma_buf_phys;
+		dma_desc->dtadr = dma_buf_phys;
+		dma_desc->dcmd = DCMD_ENDIRQEN;
+		if (s->output && !s->mapped)
+			dma_desc->ddadr |= DDADR_STOP;
+		b->dma_desc = dma_desc++;
+
+		/* set up the actual data descriptors */
+		for (i = 0; (i * MAX_DMA_SIZE) < s->fragsize; i++) {
+			dma_desc[i].dsadr = (s->output) ?
+				(dma_buf_phys + i*MAX_DMA_SIZE) : s->dev_addr;
+			dma_desc[i].dtadr = (s->output) ?
+				s->dev_addr : (dma_buf_phys + i*MAX_DMA_SIZE);
+			dma_desc[i].dcmd = s->dcmd |
+				((s->fragsize < MAX_DMA_SIZE) ?
+					s->fragsize : MAX_DMA_SIZE);
+
+			PXAI2S_DBGPRINT(DBG_LEVEL3, "dsadr[%8x],dtadr[%8x],dcmd[%8x]\n",
+					dma_desc[i].dsadr,dma_desc[i].dtadr,dma_desc[i].dcmd);
+
+		}
+		dma_desc += i;
+
+		/* handle buffer pointers */
+		b->data = dma_buf;
+		dma_buf += s->fragsize;
+		dma_buf_phys += s->fragsize;
+		buf_size -= s->fragsize;
+	}
+
+	s->usr_frag = s->dma_frag = 0;
+	s->bytecount = 0;
+	s->fragcount = 0;
+	sema_init(&s->sem, (s->output) ? s->nbfrags : 0);
+	return 0;
+
+err:
+	PXAI2S_DBGPRINT(DBG_ALWAYS, "unable to allocate audio memory\n ");
+	pxa_audio_clear_buf(s);
+	return -ENOMEM;
+}
+
+EXPORT_SYMBOL(audio_setup_buf);
+
+/*
+ * Our DMA interrupt handler
+ */
+void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs)
+{
+	audio_stream_t *s = dev_id;
+	u_int dcsr;
+
+	dcsr = DCSR(ch);
+	DCSR(ch) = dcsr & ~DCSR_STOPIRQEN;
+
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_dma_irq(): dcsr(ch) = %8x(%d)\n",dcsr,ch);
+
+	if (!s->buffers) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "I2S DMA: wow... received IRQ for channel %d but no buffer exists\n", ch);
+		return;
+	}
+
+	if (dcsr & DCSR_BUSERR)
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "I2S DMA: bus error interrupt on channel %d\n", ch);
+
+	if (dcsr & DCSR_ENDINTR) {
+		u_long cur_dma_desc;
+		u_int cur_dma_frag;
+
+		/* 
+		 * Find out which DMA desc is current.	Note that DDADR
+		 * points to the next desc, not the current one.
+		 */
+		cur_dma_desc = DDADR(ch) - s->dma_desc_phys - DMA_DESC_SIZE;
+
+		/*
+		 * Let the compiler nicely optimize constant divisors into
+		 * multiplications for the common cases which is much faster.
+		 * Common cases: x = 1 + (1 << y) for y = [0..3]
+		 */
+		switch (s->descs_per_frag) {
+		case 2:	cur_dma_frag = cur_dma_desc / (2*DMA_DESC_SIZE); break;
+		case 3:	cur_dma_frag = cur_dma_desc / (3*DMA_DESC_SIZE); break;
+		case 5:	cur_dma_frag = cur_dma_desc / (5*DMA_DESC_SIZE); break;
+		case 9:	cur_dma_frag = cur_dma_desc / (9*DMA_DESC_SIZE); break;
+		default: cur_dma_frag =
+					cur_dma_desc / (s->descs_per_frag * DMA_DESC_SIZE);
+		}
+
+		/* Account for possible wrap back of cur_dma_desc above */
+		if (cur_dma_frag >= s->nbfrags)
+			cur_dma_frag = s->nbfrags - 1;
+
+		while (s->dma_frag != cur_dma_frag) {
+			if (!s->mapped) {
+				/* 
+				 * This fragment is done - set the checkpoint
+				 * descriptor to STOP until it is gets
+				 * processed by the read or write function.
+				 */
+				s->buffers[s->dma_frag].dma_desc->ddadr |= DDADR_STOP;
+				up(&s->sem);
+			}
+			if (++s->dma_frag >= s->nbfrags)
+				s->dma_frag = 0;
+
+			/* Accounting */
+			s->bytecount += s->fragsize;
+			s->fragcount++;
+		}
+
+		/* ... and for polling processes */
+		wake_up_all(&s->frag_wq);
+	}
+
+	if ((dcsr & DCSR_STOPIRQEN) && (dcsr & DCSR_STOPSTATE))
+		wake_up_all(&s->stop_wq);
+}
+
+EXPORT_SYMBOL(audio_dma_irq);
+
+/*
+ * Validate and sets up buffer fragments, etc.
+ */
+int audio_set_fragments(audio_stream_t *s, int val)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "audio_set_fragments()\n");
+	
+	if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN)
+		return -EBUSY;
+	if (s->buffers)
+		pxa_audio_clear_buf(s);
+	s->nbfrags = (val >> 16) & 0x7FFF;
+	val &= 0xffff;
+	if (val < 5)
+		val = 5;
+	if (val > 15)
+		val = 15;
+	s->fragsize = 1 << val;
+	if (s->nbfrags < 2)
+		s->nbfrags = 2;
+	if (s->nbfrags * s->fragsize > 256 * 1024)
+		s->nbfrags = 256 * 1024 / s->fragsize;
+	if (audio_setup_buf(s,1))
+		return -ENOMEM;
+	return val|(s->nbfrags << 16);
+}
+
+EXPORT_SYMBOL(audio_set_fragments);
+
+MODULE_LICENSE("GPL");
Index: linux-2.6.14/sound/oss/wm8731.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.14/sound/oss/wm8731.h	2005-10-31 21:42:36.000000000 +0000
@@ -0,0 +1,124 @@
+/*
+ * Wolfson wm8731 Definitions
+ *
+ * Copyright (c) 2004 Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#define MAX_REG_CACHE 9
+
+struct wm8731_priv {
+	struct i2c_client client;
+	unsigned short regs[MAX_REG_CACHE];
+};
+
+struct wm8731_settings {
+	unsigned short mode;
+#define WM8731_MODE_PLAY    0x0001
+#define WM8731_MODE_REC     0x0002
+
+	int output_left;
+	int output_right;	
+	int input_left;
+	int input_right;
+	int frequency;
+};
+
+int wm8731_reg_write(struct i2c_client *clnt, unsigned char address, unsigned short data);
+int wm8731_set_output_volume(struct wm8731_priv *wm8731, int left, int right, int headphone);
+int wm8731_set_input_volume(struct wm8731_priv *wm8731, int left, int right);
+int wm8731_set_mic_gain_boost(struct wm8731_priv *wm8731, int on);
+int wm8731_set_freq(struct wm8731_priv *wm8731, int freq);
+
+int wm8731_activate(void (*callback)(struct wm8731_priv *wm8731_priv));
+int wm8731_open(struct wm8731_priv *wm8731, struct wm8731_settings *settings, int headphone);
+int wm8731_close(struct wm8731_priv *wm8731);
+
+
+#define WM8731_DEV_ADR0		0x1a
+#define WM8731_DEV_ADR1		0x1b
+
+#define WM8731_ADR_LINEIN_L	0x00
+#define WM8731_ADR_LINEIN_R	0x01
+#define WM8731_ADR_HPOUT_L	0x02
+#define WM8731_ADR_HPOUT_R	0x03
+#define WM8731_ADR_AP_ANALOG	0x04
+#define WM8731_ADR_AP_DIGITAL	0x05
+#define WM8731_ADR_PWRDOWN	0x06
+#define WM8731_ADR_FORMAT_DIGIN	0x07
+#define WM8731_ADR_SAMPLING	0x08
+#define WM8731_ADR_ACTIVATE	0x09
+#define WM8731_ADR_RESET	0x0f
+
+/* Power Down Control Register */
+#define WM8731_PD_OFF		(1U << 7)
+#define WM8731_PD_CLK		(1U << 6)
+#define WM8731_PD_OSC		(1U << 5)
+#define WM8731_PD_OUT		(1U << 4)
+#define WM8731_PD_DAC		(1U << 3)
+#define WM8731_PD_ADC		(1U << 2)
+#define WM8731_PD_MIC		(1U << 1)
+#define WM8731_PD_LIN		(1U << 0)
+#define WM8731_PD_ALL		(WM8731_PD_CLK | WM8731_PD_OSC | WM8731_PD_OUT | WM8731_PD_DAC | \
+				 WM8731_PD_ADC | WM8731_PD_MIC | WM8731_PD_LIN)
+#define WM8731_PD_DEC_ACTIVE	(WM8731_PD_OSC | WM8731_PD_ADC | WM8731_PD_MIC | WM8731_PD_LIN)
+#define WM8731_PD_ENC_ACTIVE	(WM8731_PD_OSC | WM8731_PD_DAC | WM8731_PD_MIC)
+
+/* HP Out Register */
+#define WM8731_HPOUT_VOL_INIT	(121)  /* 0dB */
+#define WM8731_HPOUT_VOL_MASK	(0x7f)
+#define WM8731_HPOUT_VOL_MAX	(127)
+#define WM8731_HPOUT_VOL_MIN	(0)
+
+/* Line In Register */
+#define WM8731_LINEIN_VOL_INIT	(23)  /* 0dB */
+#define WM8731_LINEIN_VOL_MASK	(0x1f)
+#define WM8731_LINEIN_VOL_MIN	(0)
+#define WM8731_LINEIN_VOL_MAX	(31)
+#define WM8731_LINEIN_MUTE_ON	(1 << 7)
+#define WM8731_LINEIN_MUTE_OFF	(0)
+
+/* Analog Audio Path Control Register */
+#define WM8731_AAP_ST_ATTN_6dB       (0 << 6)
+#define WM8731_AAP_ST_ATTN_9dB       (1 << 6)
+#define WM8731_AAP_ST_ATTN_12dB      (2 << 6)
+#define WM8731_AAP_ST_ATTN_15dB      (3 << 6)
+#define WM8731_AAP_SIDETONE_ENABLE   (1 << 5)
+#define WM8731_AAP_DAC_SELECT        (1 << 4)
+#define WM8731_AAP_BYPASS_ENABLE     (1 << 3)
+#define WM8731_AAP_INPUT_MIC         (1 << 2)
+#define WM8731_AAP_INPUT_LINE        (0 << 2)
+#define WM8731_AAP_MIC_MUTE          (1 << 1)
+#define WM8731_AAP_MIC_BOOST         (1 << 0)
+
+/* Digital Audio Path Control Register */
+#define WM8731_DAP_HPF_SO             (1 << 4)
+#define WM8731_DAP_DAC_MUTE           (1 << 3)
+#define WM8731_DAP_DEEMPHASIS_MODE(x) ((x&3) << 1)
+#define WM8731_DAP_DEEMPHASIS_MASK    (3 << 1)
+#define WM8731_DAP_ADC_HPF_ENABLE     (1 << 0)
+
+/* Sampling Control Register */
+#define WM8731_SAMP_CLKOUT_DIV       (1 << 7)
+#define WM8731_SAMP_CLKIN_DIV        (1 << 6)
+#define WM8731_SAMP_BOTH_48KHZ       (0 << 2)
+#define WM8731_SAMP_BOTH_44KHZ       (8 << 2)
+#define WM8731_SAMP_BOTH_8KHZ        (3 << 2)
+#define WM8731_SAMP_BOSR             (1 << 1)
+#define WM8731_SAMP_USB_MODE         (1 << 0)
+#define WM8731_SAMP_NORMAL_MODE      (0 << 0)
+
+/* Digital Audio Interface Format Register */
+#define WM8731_DAIF_MODE_I2S         (2 << 0)
+#define WM8731_DAIF_IWL_16BIT        (0 << 2)
+#define WM8731_DAIF_IWL_20BIT        (1 << 2)
+#define WM8731_DAIF_IWL_24BIT        (2 << 2)
+#define WM8731_DAIF_IWL_32BIT        (3 << 2)
+#define WM8731_DAIF_LRSWAP           (1 << 5)
+#define WM8731_DAIF_MS_SLAVE         (0 << 6)
+#define WM8731_DAIF_MS_MASTER        (1 << 6)
+
+

