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

📄 i2s.patch

📁 patches for linux-2.6.
💻 PATCH
📖 第 1 页 / 共 5 页
字号:
-	 */-	ip->psc_ctrl = PSC_CTRL_DISABLE;	/* Disable PSC */-	au_sync();-	ip->psc_sel = (PSC_SEL_CLK_INTCLK | PSC_SEL_PS_I2SMODE);-	au_sync();--	/* Enable PSC-	*/-	ip->psc_ctrl = PSC_CTRL_ENABLE;-	au_sync();--	/* Wait for PSC ready.-	*/-	do {-		val = ip->psc_i2sstat;-		au_sync();-	} while ((val & PSC_I2SSTAT_SR) == 0);--	/* Configure I2S controller.-	 * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size.-	 * Actual I2S mode (first bit delayed by one clock).-	 * Master mode (We provide the clock from the PSC).-	 */-	val = PSC_I2SCFG_SET_LEN(16);-#ifdef TRY_441KHz-	/* This really should be 250, but it appears that all of the-	 * PLLs, dividers and so on in the chain shift it.  That's the-	 * problem with sourceing the clock instead of letting the very-	 * stable codec provide it.  But, the PSC doesn't appear to want-	 * to work in slave mode, so this is what we get.  It's  not-	 * studio quality timing, but it's good enough for listening-	 * to mp3s.-	 */-	val |= PSC_I2SCFG_SET_WS(252);-#else-	val |= PSC_I2SCFG_SET_WS(250);-#endif-	val |= PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8 | \-					PSC_I2SCFG_BI | PSC_I2SCFG_XM;--	ip->psc_i2scfg = val;-	au_sync();-	val |= PSC_I2SCFG_DE_ENABLE;-	ip->psc_i2scfg = val;-	au_sync();--	/* Wait for Device ready.-	*/-	do {-		val = ip->psc_i2sstat;-		au_sync();-	} while ((val & PSC_I2SSTAT_DR) == 0);--	val = ip->psc_i2scfg;-	au_sync();--	s->codec->init_codec(s->codec);+	/* Initial settings for sample rates */+	s->dma_dac.sample_rate = s->dma_adc.sample_rate = 8000;+	set_adc_rate(s, 8000);  //Set default rate+	set_dac_rate(s, 8000);  //Set default rate  	return 0; +#if 0+ err_dev3:+	unregister_sound_mixer(s->codec->dev_mixer);+ err_dev2:+	unregister_sound_dsp(s->dev_audio);+#endif  err_dev2: 	unregister_sound_dsp(s->dev_audio);  err_dev1:@@ -1987,7 +1974,7 @@ au1550_probe(void)  err_dma2: 	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);  err_dma1:-	release_region(CPHYSADDR(I2S_PSC_BASE), 0x30);+	i2s_hw_cleanup(s->i2s);  	return -1; }@@ -1999,16 +1986,18 @@ au1550_remove(void)  	if (!s) 		return;-#ifdef AU1550_DEBUG+#ifdef DEBUG 	if (s->ps) 		remove_proc_entry(AU1000_MODULE_NAME, NULL); #endif /* AU1000_DEBUG */ 	synchronize_irq(); 	au1xxx_dbdma_chan_free(s->dma_adc.dmanr); 	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);-	release_region(CPHYSADDR(I2S_PSC_BASE), 0x30);+	i2s_hw_cleanup(s->i2s); 	unregister_sound_dsp(s->dev_audio);-	unregister_sound_mixer(s->dev_mixer);+#if 0+	unregister_sound_mixer(s->codec->dev_mixer);+#endif }  static int __init@@ -2026,5 +2015,27 @@ cleanup_au1550(void) module_init(init_au1550); module_exit(cleanup_au1550); -MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");-MODULE_DESCRIPTION("Au1550 I2S Audio Driver");+#ifndef MODULE++static int __init+au1550_setup(char *options)+{+	char           *this_opt;++	if (!options || !*options)+		return 0;++	while ((this_opt = strsep(&options, ","))) {+		if (!*this_opt)+			continue;+		if (!strncmp(this_opt, "vra", 3)) {+			vra = 1;+		}+	}++	return 1;+}++__setup("au1550_audio=", au1550_setup);++#endif /* MODULE */Index: linux-2.6.11-rc5/sound/oss/au1550_i2s.h===================================================================--- /dev/null+++ linux-2.6.11-rc5/sound/oss/au1550_i2s.h@@ -0,0 +1,135 @@+/*+ *      au1550_i2s_hw.c  --  Sound driver support for AMD Alchemy + *   			Au1550/Au1200 MIPS Processor Cores+ *+ */++#ifndef _AU1550_I2S_H+#define _AU1550_I2S_H++#ifdef CONFIG_MIPS_PB1550+#include <asm/mach-pb1x00/pb1550.h>+	#define WM8731+#endif++#ifdef CONFIG_MIPS_DB1550+#include <asm/mach-db1x00/db1x00.h>+	#define WM8731+#endif++#ifdef CONFIG_MIPS_PB1200+#include <asm/mach-pb1x00/pb1200.h>+	#define WM8731+#endif++#ifdef CONFIG_MIPS_DB1200+#include <asm/mach-db1x00/db1200.h>+	#define WM8731+#endif+++#define AU1XXX_MODULE_NAME "Au1xxx i2s audio"+#define PFX AU1XXX_MODULE_NAME++#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)+#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)++#define supported_mixer(FOO) ((FOO >= 0) && \+                                    (FOO < SOUND_MIXER_NRDEVICES) && \+                                    (s->i2s->input_mask | s->i2s->output_mask) & (1<<FOO) )++enum i2s_power_mode {DAC_OFF=0, ADC_OFF, ALL_OFF, DAC_ON, ADC_ON};++ struct i2s_hw {+	char *name;+	int	  codec_is_master;+	int   input_mask;+	int   output_mask;+	volatile psc_i2s_t *psc;+	unsigned int sr;+	void  (*codec_init)(struct i2s_hw *hw);+	void  (*wrcodec)(u8 ctlreg, u16 val);+	int   (*set_rates)(struct i2s_hw *hw, u32 *in, u32 *out);+	int   (*get_mixer)(struct i2s_hw *hw, u16 oss_channel);+	void  (*set_mixer)(struct i2s_hw *hw, u16 oss_channel, u16 val);+	void (*set_recsrc)(struct i2s_hw *hw, int src);+	int  (*get_recsrc)(void);+#ifdef CONFIG_PM+	  void  (*power)(struct i2s_hw *hw, int type);+#endif++};++	    	  	  ++/* Prototypes */+struct i2s_hw * i2s_hw_init(void);+void i2s_hw_cleanup(struct i2s_hw *hw);+extern struct i2s_hw * AMD_PbDb_setup(u32 psc, u32 clock);++/* Helper functions */+static inline void i2s_stop_xmit(struct i2s_hw *hw)+{+	volatile psc_i2s_t *ip = hw->psc;+	u32 stat;++	ip->psc_i2spcr = PSC_I2SPCR_TP;+	au_sync();++	/* Wait for Transmit Busy to show disabled.+	*/+	do {+		stat = ip->psc_i2sstat;+		au_sync();+	} while ((stat & PSC_I2SSTAT_TB) != 0);+}	+	+static inline void i2s_stop_recv(struct i2s_hw *hw)+{+	volatile psc_i2s_t *ip = hw->psc;+	u32 stat;++	ip->psc_i2spcr = PSC_I2SPCR_RP;+	au_sync();++	/* Wait for Transmit Busy to show disabled.+	*/+	do {+		stat = ip->psc_i2sstat;+		au_sync();+	} while ((stat & PSC_I2SSTAT_RB) != 0);+}	++static inline void i2s_start_xmit(struct i2s_hw *hw)+{+	volatile psc_i2s_t *ip = hw->psc;+	ip->psc_i2spcr = PSC_I2SPCR_TC;+	au_sync();+	ip->psc_i2spcr = PSC_I2SPCR_TS;+	au_sync();+}++static inline void i2s_start_recv(struct i2s_hw *hw)+{+	volatile psc_i2s_t *ip = hw->psc;+	ip->psc_i2spcr = PSC_I2SPCR_RC;+	au_sync();+	ip->psc_i2spcr = PSC_I2SPCR_RS;+	au_sync();+}++static inline unsigned i2s_status(struct i2s_hw *hw)+{+	volatile psc_i2s_t *ip = hw->psc;+	u32	i2s_stat;++	i2s_stat = ip->psc_i2sstat;+#ifdef AU1000_VERBOSE_DEBUG+	if (i2s_stat & (PSC_I2SSTAT_TF | PSC_I2SSTAT_TR | PSC_I2SSTAT_TF))+		dbg("I2S status = 0x%08x", i2s_stat);+#endif++	return(i2s_stat);+}++#endifIndex: linux-2.6.11-rc5/sound/oss/au1550_i2s_hw.c===================================================================--- /dev/null+++ linux-2.6.11-rc5/sound/oss/au1550_i2s_hw.c@@ -0,0 +1,672 @@+/*+ *      au1550_i2s_hw.c  --  Sound driver support for AMD Alchemy + *   			Au1550/Au1200 MIPS Processor Cores+ *+ * The WM8731 CODEC only has one input for ADC recording device. Below+ * is a snipet of code that illustrates how to swtich between MIC and+ * LINE for WM8731. This can be used for other CODECs as long as the+ * set_recsrc() routine is implemented properly.+ *+		#include <unistd.h>+		#include <stdlib.h>+		#include <stdio.h>+		#include <fcntl.h>+		#include <sys/soundcard.h>+		#include <sys/ioctl.h>++		int main (int argc, char **argv)+		{+			char *mixer="/dev/mixer";+			int fpmixer, insel=SOUND_MASK_LINE;+			int val;++			fpmixer = open(mixer, O_RDWR );+			if (-1 == fpmixer) {+				return -1;+			}+			if ( argc > 1 ) insel = SOUND_MASK_MIC;+			ioctl(fpmixer, SOUND_MIXER_WRITE_RECSRC, &insel);+			return 0;+		}+*/+++#include <linux/module.h>+#include <linux/version.h>+#include <linux/kernel.h>+#include <linux/ioport.h>+#include <linux/sound.h>+#include <linux/slab.h>+#include <linux/soundcard.h>+#include <linux/string.h>+#include <linux/errno.h>+#include <linux/bitops.h>+#include <linux/delay.h>+#include <linux/hardirq.h>+#include <asm/io.h>+#include <asm/uaccess.h>+#include <asm/mach-au1x00/au1000.h>+#include <asm/mach-au1x00/au1xxx_psc.h>++#include "au1550_i2s.h"+++#if !defined(CONFIG_I2C_AU1550)+	#error +	#error +	#error I2C Support is required for I2S Codec configuration. \+	Please enable Au1xxx I2C support and rebuild.+	#error +	#error +#endif++volatile int rec_src = 0;+volatile int pres_src = 0;++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);+	}+}++#if defined(WM8731) || defined(WM8721)++#define WM_VOLUME_MIN	47+#define WM_VOLUME_SCALE	80++volatile static struct i2s_ro_mixer {+	unsigned int value;+	unsigned int scale;+	unsigned int hw_min;+} i2s_ro_mixer[SOUND_MIXER_NRDEVICES]= {+	[SOUND_MIXER_PCM]	=	{0x5050,80,0x2F},+#if defined(WM8731)+	[SOUND_MIXER_LINE]	=	{0x4343,31,0},+	[SOUND_MIXER_MIC]	=	{0x4343,31,0},+#endif+};++#define WM_SC_SR_96000		(0x7<<2)+#define WM_SC_SR_88200		(0xF<<2)+#define WM_SC_SR_48000		(0x0<<2)+#define WM_SC_SR_44100		(0x8<<2)+#define WM_SC_SR_32000		(0x6<<2)+#define WM_SC_SR_8018		(0x9<<2)+#define WM_SC_SR_8000		(0x1<<2)+#define WM_SC_MODE_USB		1+#define WM_SC_MODE_NORMAL	0+#define WM_SC_BOSR_250FS	(0<<1)+#define WM_SC_BOSR_272FS	(1<<1)+#define WM_SC_BOSR_256FS	(0<<1)+#define WM_SC_BOSR_128FS	(0<<1)+#define WM_SC_BOSR_384FS	(1<<1)+#define WM_SC_BOSR_192FS	(1<<1)++/* Power Control Register Bit values*/++#define WM_PWR_LINEINPD        (1<<0)+#define WM_PWR_MICPD           (1<<1)+#define WM_PWR_ADCPD           (1<<2)+#define WM_PWR_DACPD           (1<<3)+#define WM_PWR_OUTPD           (1<<4)+#define WM_PWR_OSCPD           (1<<5) +#define WM_PWR_CLKOUTPD        (1<<6)+#define WM_PWR_POWEROFF        (1<<7)	++enum wolfson_registers {+	L_LINE_IN=0,+	R_LINE_IN,+	L_HEADPHONE_OUT,			+	R_HEADPHONE_OUT,			+	ANALOGUE_AUDIO_PATH_CTRL,+	DIGITAL_AUDIO_PATH_CTRL,	+	POWER_DOWN_CTRL,+	DIGITAL_AUDIO_IF,			+	SAMPLING_CONTROL, 		+	ACTIVE_CTRL,+	RESET=0xF };+++#ifdef CONFIG_PM+/*No Warm Codec Reset for I2S (different than AC'97)*/+++static void wm87x1_power(struct i2s_hw *hw, int type)+{++u16 tmp=0;++switch(type){++case DAC_OFF:{+                 tmp |= WM_PWR_DACPD;+ 				  break;}++case ADC_OFF: {+				 tmp |= WM_PWR_ADCPD;+				 break;}+case ALL_OFF:{+               /*No Read for Wolfson codec only write*/+        	 tmp |=WM_PWR_LINEINPD | WM_PWR_MICPD |WM_PWR_ADCPD |+	         WM_PWR_DACPD | WM_PWR_OUTPD |WM_PWR_OSCPD |+	         WM_PWR_CLKOUTPD;  +			  break;+              }+case DAC_ON:{ +              tmp &=~(WM_PWR_LINEINPD | WM_PWR_MICPD |+	          WM_PWR_DACPD | WM_PWR_OUTPD |WM_PWR_OSCPD |+	          WM_PWR_CLKOUTPD);  +	  		  break;+             }+case ADC_ON: { +			  tmp &=~(WM_PWR_LINEINPD | WM_PWR_MICPD |+	          WM_PWR_ADCPD | WM_PWR_OUTPD |WM_PWR_OSCPD |+	          WM_PWR_CLKOUTPD);  +	  		  break;+			 }+}++hw->wrcodec(POWER_DOWN_CTRL, tmp);+}+#endif++++static void wm87x1_wrcodec(u8 ctlreg, u16 val)+{+	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 << 1) | ((val >> 8) & 0x01), +					(u8) (val & 0x00FF)) != 1) && +			(rcnt < 50)) {+		rcnt++;+	}+	if ( rcnt >= 50 ) printk("timeout wm87x1_wrcodec: reg:%x val:%x\n", ctlreg, val);+

⌨️ 快捷键说明

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