⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2s.patch

📁 patches for linux-2.6.
💻 PATCH
📖 第 1 页 / 共 5 页
字号:
Index: linux-2.6.11-rc5/include/asm-mips/mach-au1x00/au1xxx_psc.h===================================================================--- linux-2.6.11-rc5.orig/include/asm-mips/mach-au1x00/au1xxx_psc.h+++ linux-2.6.11-rc5/include/asm-mips/mach-au1x00/au1xxx_psc.h@@ -230,6 +230,7 @@ typedef struct	psc_i2s {  #define PSC_I2SCFG_DD_DISABLE	(1 << 27) #define PSC_I2SCFG_DE_ENABLE	(1 << 26)+#define PSC_I2SCFG_WS_MASK		(0x3F<<16) #define PSC_I2SCFG_SET_WS(x)	(((((x) / 2) - 1) & 0x7f) << 16) #define PSC_I2SCFG_WI		(1 << 15) Index: linux-2.6.11-rc5/sound/oss/au1550_i2s.c===================================================================--- linux-2.6.11-rc5.orig/sound/oss/au1550_i2s.c+++ linux-2.6.11-rc5/sound/oss/au1550_i2s.c@@ -4,21 +4,35 @@  *  * Copyright 2004 Embedded Edge, LLC  *	dan@embeddededge.com- * Copyright 2005 Matt Porter <mporter@kernel.crashing.org>  *- * Mostly copied from the au1550_psc.c driver and some from the- * PowerMac dbdma driver.- * We assume the processor can do memory coherent DMA.+ * Modified for platform independence -- 5/2/2005+ *  Chris Gray (chris.gray@amd.com)  *- * WM8731 mixer support, codec framework, cleanup, and 2.6 port- * Matt Porter <mporter@kernel.crashing.org>+ * This module was reworked to support some of the various hw+ * platforms that use Au1550/Au1200 and I2S codecs. Most of+ * the Wolfson CODECs I have encountred do not implement readable+ * registers. Because of this, I implemented local copy of hw+ * mixer settings. Another drawback is that I2S will often mux+ * inputs to ADC.   *- * The SMBus (I2C) is required for the control of the + * Anyway, because of the limitations and "funkiness" of I2S, I+ * created another file for platform specific implementation. I + * I gave it the name au1550_i2s_hw.c, for the lack of creativity.+ *+ * Mostly copied from the au1550_psc.c.+ *+ * The SMBus (I2C) is required for the control of the codec.  It  * appears at I2C address 0x36 (I2C binary 0011011).  The Pb1550  * uses the Wolfson WM8731 codec, which is controlled over the I2C.+ * + * Pb/Db1550 Pb/Db1200 Notes:  * It's connected to a 12MHz clock, so we can only reliably support- * 96KHz, 48KHz, 32KHz, and 8KHz data rates.  Variable rate audio is- * unsupported, we currently force it to 48KHz.+ * 96KHz, 48KHz, 32KHz, and 8KHz data rates.  The framework for variable+ * rate audio is in place, but we currently force it to 48KHz. This+ * is only true of the PSC is running as the I2S Master.+ * In the au1550_i2s_hw.c file I configure the CODEC to run as + * I2S Master while the Au1xxx device is slave running in slave mode+ * (SERCLK). We can now support any sample rate the CODEC supports.  *  *  This program is free software; you can redistribute  it and/or modify it  *  under  the terms of  the GNU General  Public License as published by the@@ -40,15 +54,15 @@  *  with this program; if not, write  to the Free Software Foundation, Inc.,  *  675 Mass Ave, Cambridge, MA 02139, USA.  *+ *  */+ #include <linux/version.h> #include <linux/module.h> #include <linux/string.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/delay.h>-#include <linux/fs.h>-#include <linux/hardirq.h> #include <linux/sound.h> #include <linux/slab.h> #include <linux/soundcard.h>@@ -59,220 +73,78 @@ #include <linux/proc_fs.h> #include <linux/spinlock.h> #include <linux/smp_lock.h>-+#include <linux/hardirq.h> #include <asm/io.h> #include <asm/uaccess.h>-#include <asm/hardirq.h>- #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1xxx_psc.h> #include <asm/mach-au1x00/au1xxx_dbdma.h>-#include <asm/mach-pb1x00/pb1550.h> -#undef OSS_DOCUMENTED_MIXER_SEMANTICS+/*Power Management*/ -#define AU1550_MODULE_NAME "Au1550 I2S Audio"-#define PFX AU1550_MODULE_NAME+#ifdef CONFIG_PM+#include <asm/mach-au1x00/au1xxx_pm.h>+#endif -/* Define this if you want to try running at the 44.1 KHz rate.- * It's just a little off, I think it's actually 44117 or something.- * I did this for debugging, since many programs, including this- * driver, will try to upsample from 44.1 to 48 KHz.- * Seems to work well, we'll just leave it this way.- */-#define TRY_441KHz+#ifdef CONFIG_MIPS_PB1550+#include <asm/mach-pb1x00/pb1550.h>+#endif -#ifdef TRY_441KHz-#define SAMP_RATE	44100-#else-#define SAMP_RATE	48000+#ifdef CONFIG_MIPS_DB1550+#include <asm/mach-db1x00/db1x00.h>+#endif++#ifdef CONFIG_MIPS_PB1200+#include <asm/mach-pb1x00/pb1200.h> #endif +#ifdef CONFIG_MIPS_DB1200+#include <asm/mach-db1x00/db1200.h>+#endif++#include "au1550_i2s.h"++#undef OSS_DOCUMENTED_MIXER_SEMANTICS++static int      vra = 0;+ /* The number of DBDMA ring descriptors to allocate.  No sense making  * this too large....if you can't keep up with a few you aren't likely  * to be able to with lots of them, either.+ *+ * CTG -- by cranking these up I was able to play 88200 correctly. 4/26/05  */-#define NUM_DBDMA_DESCRIPTORS 4+#define NUM_DBDMA_DESCRIPTORS 16+#define MIN_Q_COUNT		4 -#define pr_error(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)+MODULE_PARM(vra, "i");+MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); -static void-au1550_delay(int msec)-{-	unsigned long   tmo;-	signed long     tmo2;+/*Power Management*/ -	if (in_interrupt())-		return;+#ifdef CONFIG_PM -	tmo = jiffies + (msec * HZ) / 1000;-	for (;;) {-		tmo2 = tmo - jiffies;-		if (tmo2 <= 0)-			break;-		schedule_timeout(tmo2);-	}-}  /*- * Codec framework. If somebody supports another codec, they- * should hopefully be able to define another struct i2s_codec- * definition, and #ifdef the support for it and the WM8731 so- * they can be selected via a CONFIG option. For now, we just- * hardcode WM8731_CODEC.+ *  This will enable the device/codec to be powered up when write() or read()+ *  is called. If this is not defined, the driver will return -EBUSY.  */-#define i2s_supported_mixer(CODEC,FOO) ((FOO >= 0) && \-                                    (FOO < SOUND_MIXER_NRDEVICES) && \-                                    (CODEC)->supported_mixers & (1<<FOO) )--struct i2s_codec {-	int			modcnt;-	int			supported_mixers;-	int			stereo_mixers;-	int			record_sources;-	unsigned int		mixer_state[SOUND_MIXER_NRDEVICES];-	void			*data;-	int			(*set_mixer) (struct i2s_codec *codec, unsigned int oss_mixer, unsigned int val);-	void			(*init_codec) (struct i2s_codec *codec);-};+#define WAKE_ON_ACCESS 1+ -#define WM8731_CODEC-#ifdef WM8731_CODEC /*- * WM8731 codec support+ *	Support two nodes in this driver, ADC and DAC. They are seperate in regards to+ *  power management control. But the driver needs to check both when determining+ *  the overall power management of the CODEC. If ADC is being told to turn off,+ *  and the DAC is already off... then we can safely turn off everything else in + *  the CODEC.   */-#define WM8731_SUPPORTED_MASK (WM8731_STEREO_MASK|WM8731_RECORD_MASK)-#define WM8731_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_LINE)-#define WM8731_RECORD_MASK (SOUND_MASK_MIC|SOUND_MASK_LINE)--static struct codec_data {-	u16			audio_path;-} wm8731_data;--static void-wm8731_wrcodec(u8 ctlreg, u8 val)+typedef struct {-	int	rcnt;-	extern int pb1550_wm_codec_write(u8 addr, u8 reg, u8 val);--	/* The codec is a write only device, with a 16-bit control/data-	 * word.  Although it is written as two bytes on the I2C, the-	 * format is actually 7 bits of register and 9 bits of data.-	 * The ls bit of the first byte is the ms bit of the data.-	 */-	rcnt = 0;-	while ((pb1550_wm_codec_write((0x36 >> 1), ctlreg, val) != 1) -							&& (rcnt < 50)) {-		rcnt++;-	}-}--static int-wm8731_set_mixer(struct i2s_codec *codec, unsigned int oss_mixer, unsigned int val)-{-	unsigned int lvol, rvol;-	struct codec_data *cdata = (struct codec_data *)codec->data;--	switch (oss_mixer) {-		case SOUND_MIXER_VOLUME:-			/* normalize OSS range to fit codec volume control */-			lvol = ((((val & 0x7f00) >> 8) * 0x60) / 0x64) + 0x1f;-			rvol = (((val & 0x7f) * 0x60) / 0x64) + 0x1f;-			lvol |= 0x80;-			rvol |= 0x80;-			wm8731_wrcodec(0x04, lvol);-			au1550_delay(10);-			wm8731_wrcodec(0x06, rvol);-			au1550_delay(10);-			codec->mixer_state[oss_mixer] = val;-			break;-		case SOUND_MIXER_LINE:-			/* normalize OSS range to fit codec line control */-			lvol = ((((val & 0x7f00) >> 8) * 0x1f) / 0x64);-			rvol = (((val & 0x7f) * 0x1f) / 0x64);-			if (!(val & 0x1f00))-				lvol |= 0x80;-			else-				lvol &= ~0x80;-			if (!(val & 0x001f))-				rvol |= 0x80;-			else-				rvol &= ~0x80;-			wm8731_wrcodec(0x00, lvol);-			au1550_delay(10);-			wm8731_wrcodec(0x02, rvol);-			au1550_delay(10);-			codec->mixer_state[oss_mixer] = val;-			break;-		case SOUND_MIXER_MIC:-			if (!val)-				cdata->audio_path |= 0x02;-			else {-				if (val >= 0x32)-					cdata->audio_path |= 0x01;-				else-					cdata->audio_path &= ~0x01;-				cdata->audio_path &= ~0x02;-			}-			wm8731_wrcodec(0x08, cdata->audio_path);-			au1550_delay(10);-			codec->mixer_state[oss_mixer] = val;-			break;-		case SOUND_MIXER_RECSRC:-			if (val & SOUND_MASK_LINE)-				cdata->audio_path &= ~0x04;-			else-				cdata->audio_path |= 0x04;-			wm8731_wrcodec(0x08, cdata->audio_path);-			au1550_delay(10);-			codec->mixer_state[oss_mixer] = val;-			break;-		default:-			return -EINVAL;-	}--	return 0;-}--void-wm8731_init_codec(struct i2s_codec *codec)-{-	struct codec_data *cdata = (struct codec_data *)codec->data;--	wm8731_wrcodec(0x1e, 0x00);	/* Reset */-	au1550_delay(200);-	wm8731_wrcodec(0x0c, 0x00);	/* Power up everything */-	au1550_delay(10);-	wm8731_wrcodec(0x12, 0x00);	/* Deactivate codec */-	au1550_delay(10);-	cdata->audio_path = 0x10;-	/* Select DAC outputs to line out */-	wm8731_wrcodec(0x08, cdata->audio_path);-	au1550_delay(10);-	wm8731_wrcodec(0x0a, 0x00);	/* Disable output mute */-	au1550_delay(10);-	wm8731_wrcodec(0x0e, 0x02);	/* Set slave, 16-bit, I2S modes */-	au1550_delay(10);-	wm8731_wrcodec(0x10, 0x01);	/* 12MHz (USB), 250fs */-	au1550_delay(10);-	wm8731_wrcodec(0x12, 0x01);	/* Activate codec */-	au1550_delay(10);--	codec->set_mixer(codec, SOUND_MIXER_VOLUME, 0x5050);-	codec->set_mixer(codec, SOUND_MIXER_LINE, 0x0000);-	codec->set_mixer(codec, SOUND_MIXER_MIC, 0x00);-	codec->mixer_state[SOUND_MIXER_RECSRC] = SOUND_MIXER_LINE;-}--static struct i2s_codec au1550_i2s_codec = {-	.supported_mixers	= WM8731_SUPPORTED_MASK,-	.stereo_mixers		= WM8731_STEREO_MASK,-	.record_sources		= WM8731_RECORD_MASK,-	.init_codec		= &wm8731_init_codec,-	.set_mixer		= &wm8731_set_mixer,-	.data			= &wm8731_data,-};-#endif /* WM8731_CODEC */+	spinlock_t	lock;			/* Used to block on state transitions */+	au1xxx_power_dev_t *dev;	/* Power Managers device structure */+} pm_state;+#endif   static struct au1550_state { 	/* soundcore stuff */@@ -284,8 +156,13 @@ static struct au1550_state { 	struct semaphore	sem; 	mode_t			open_mode; 	wait_queue_head_t	open_wait;-	volatile psc_i2s_t	*psc_addr;-	struct i2s_codec	*codec;+	int			no_vra;+	struct i2s_hw	* i2s;++	int level_line;+	int level_mic;+	int level_left;+	int level_right;  	struct dmabuf { 		u32		dmanr;@@ -321,12 +198,16 @@ static struct au1550_state { 		unsigned        ossfragshift; 		int             ossmaxfrags; 		unsigned        subdivision;--		/* Mixer stuff */-		int		dev_mixer;+#ifdef CONFIG_PM+		pm_state		pm;+#endif 	} dma_dac, dma_adc; } au1550_state; +static void  powerup_adc(struct au1550_state *s); +static void  powerup_dac(struct au1550_state *s);++ static unsigned ld2(unsigned int x) {@@ -353,18 +234,202 @@ ld2(unsigned int x) 	return r; } +static void+au1550_delay(int msec)+{+	unsigned long   tmo;+	signed long     tmo2;++	if (in_interrupt())+		return;++	tmo = jiffies + (msec * HZ) / 1000;+	for (;;) {+		tmo2 = tmo - jiffies;+		if (tmo2 <= 0)+			break;+		schedule_timeout(tmo2);+	}+}++static int+au1550_open_mixdev(struct inode *inode, struct file *file)+{+	file->private_data = &au1550_state;+	return 0;+}++static int+au1550_release_mixdev(struct inode *inode, struct file *file)+{+	return 0;+}++static int+au1550_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)+{+	struct au1550_state *s = (struct au1550_state *)file->private_data;++	int i, val = 0;++	if (cmd == SOUND_MIXER_INFO) {+		mixer_info info;+		strncpy(info.id, s->i2s->name, sizeof(info.id));+		strncpy(info.name, s->i2s->name, sizeof(info.name));+		info.modify_counter = 0;+		if (copy_to_user((void *)arg, &info, sizeof(info)))+			return -EFAULT;+		return 0;+	}+	if (cmd == SOUND_OLD_MIXER_INFO) {+		_old_mixer_info info;+		strncpy(info.id, s->i2s->name, sizeof(info.id));+		strncpy(info.name, s->i2s->name, sizeof(info.name));+		if (copy_to_user((void *)arg, &info, sizeof(info)))+			return -EFAULT;+		return 0;+	}++	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))+		return -EINVAL;++	if (cmd == OSS_GETVERSION)+		return put_user(SOUND_VERSION, (int *)arg);++	if (_SIOC_DIR(cmd) == _SIOC_READ) {+		switch (_IOC_NR(cmd)) {+		case SOUND_MIXER_RECSRC: /* give them the current record src */+		  +		  +		     if (!s->i2s->input_mask){+		     	 val=0;+			 }+			 else+			  {+			      val=s->i2s->get_recsrc();+			  }+			   +		   	break;++		case SOUND_MIXER_DEVMASK: /* give them the supported mixers */+			val = s->i2s->output_mask | s->i2s->input_mask;+			break;++		case SOUND_MIXER_RECMASK: +			/* Arg contains a bit for each supported recording +			 * source */+			val = s->i2s->input_mask;+			break;++		case SOUND_MIXER_STEREODEVS: +			/* Mixer channels supporting stereo */+			val = s->i2s->output_mask;+			break;++		case SOUND_MIXER_CAPS:+			val = SOUND_CAP_EXCL_INPUT;+			break;++		default: /* read a specific mixer */+			i = _IOC_NR(cmd);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -