📄 audio.patch
字号:
diff -Nbur linux26-cvs/sound/oss/au1550_ac97.c linux26-cvs.ac97/sound/oss/au1550_ac97.c--- linux26-cvs/sound/oss/au1550_ac97.c 2005-08-01 14:14:39.000000000 -0500+++ linux26-cvs.ac97/sound/oss/au1550_ac97.c 2005-08-01 14:13:56.000000000 -0500@@ -59,7 +59,27 @@ #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1xxx_psc.h> #include <asm/mach-au1x00/au1xxx_dbdma.h>++#ifdef CONFIG_PM+#include <asm/mach-au1x00/au1xxx_pm.h>+#endif++#ifdef CONFIG_MIPS_PB1550 #include <asm/mach-pb1x00/pb1550.h>+#endif++#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+ #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -71,7 +91,7 @@ * 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. */-#define NUM_DBDMA_DESCRIPTORS 4+#define NUM_DBDMA_DESCRIPTORS 16 #define err(format, arg...) printk(KERN_ERR format "\n" , ## arg) @@ -82,6 +102,31 @@ MODULE_PARM(vra, "i"); MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); ++#ifdef CONFIG_PM+++/*+ * 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 WAKE_ON_ACCESS 1+++/*+ * 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. + */+typedef struct+{+ 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 */ int dev_audio;@@ -131,9 +176,21 @@ unsigned ossfragshift; int ossmaxfrags; unsigned subdivision;+ +#ifdef CONFIG_PM+ pm_state pm;+#endif+ } dma_dac, dma_adc; } au1550_state; +/* Funtion Prototype*/++static void powerup_adc(struct au1550_state *s); +static void powerup_dac(struct au1550_state *s);+static void warm_codec_reset(void);++ static unsigned ld2(unsigned int x) {@@ -189,6 +246,16 @@ spin_lock_irqsave(&s->lock, flags); +#ifdef CONFIG_PM+ /* If both dac and adc are not awake, the the codec was+ put in lower power mode. We need to warm reset+ here in order to use AC'97 link.+ */+ if ( s->dma_dac.pm.dev->cur_state != AWAKE_STATE &&+ s->dma_adc.pm.dev->cur_state != AWAKE_STATE )+ warm_codec_reset();+#endif + for (i = 0; i < POLL_COUNT; i++) { val = au_readl(PSC_AC97STAT); au_sync();@@ -252,6 +319,15 @@ int i; spin_lock_irqsave(&s->lock, flags);+#ifdef CONFIG_PM+ /* If both dac and adc are not awake, the the codec was+ put in lower power mode. We need to warm reset+ here in order to use AC'97 link.+ */+ if ( s->dma_dac.pm.dev->cur_state != AWAKE_STATE &&+ s->dma_adc.pm.dev->cur_state != AWAKE_STATE )+ warm_codec_reset();+#endif for (i = 0; i < POLL_COUNT; i++) { val = au_readl(PSC_AC97STAT);@@ -454,7 +530,10 @@ unsigned long flags; if (db->stopped)+ {+ au1xxx_dbdma_reset(db->dmanr); return;+ } spin_lock_irqsave(&s->lock, flags); @@ -476,6 +555,35 @@ } static void+pause_dac(struct au1550_state *s)+{+ struct dmabuf *db = &s->dma_dac;+ u32 stat;+ unsigned long flags;++ if (db->stopped)+ return;++ spin_lock_irqsave(&s->lock, flags);++ au_writel(PSC_AC97PCR_TP, PSC_AC97PCR);+ au_sync();++ /* Wait for Transmit Busy to show disabled.+ */+ do {+ stat = readl((void *)PSC_AC97STAT);+ au_sync();+ } while ((stat & PSC_AC97STAT_TB) != 0);++ au1xxx_dbdma_stop(db->dmanr);++ db->stopped = 1;++ spin_unlock_irqrestore(&s->lock, flags);+}++static void stop_adc(struct au1550_state *s) { struct dmabuf *db = &s->dma_adc;@@ -504,7 +612,6 @@ spin_unlock_irqrestore(&s->lock, flags); } - static void set_xmit_slots(int num_channels) {@@ -648,6 +755,7 @@ return -ENOMEM; } + db->cnt_factor = 1; if (db->sample_size == 8) db->cnt_factor *= 2;@@ -998,7 +1106,7 @@ bufptr, partial)) < 0) return cnt; ret = cnt;- if ((cnt = translate_to_user(db, userbuf + partial,+ if ((cnt = translate_to_user(db, userbuf + (partial / db->cnt_factor), db->rawbuf, count - partial)) < 0) return cnt;@@ -1009,7 +1117,7 @@ return cnt; ret = cnt; if ((cnt = translate_from_user(db, db->rawbuf,- userbuf + partial,+ userbuf + (partial / db->cnt_factor), count - partial)) < 0) return cnt; ret += cnt;@@ -1041,6 +1149,24 @@ return -EFAULT; ret = 0; +#ifdef CONFIG_PM+#ifdef WAKE_ON_ACCESS+ if ( s->dma_adc.pm.dev->cur_state != AWAKE_STATE )+ {+ pm_state *pm= &s->dma_adc.pm;+ spin_lock_irqsave(&pm->lock, flags);+ pm->dev->cur_state = AWAKE_STATE;+ powerup_adc(s);+ spin_unlock_irqrestore(&pm->lock, flags);+ }+#else+ /* If not awake... then return EBUSY */+ if ( s->dma_adc.pm.dev->cur_state != AWAKE_STATE )+ return -EBUSY;+#endif+#endif++ count *= db->cnt_factor; down(&s->sem);@@ -1122,6 +1248,24 @@ if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + +#ifdef CONFIG_PM+#ifdef WAKE_ON_ACCESS+ if ( s->dma_dac.pm.dev->cur_state != AWAKE_STATE )+ {+ pm_state *pm= &s->dma_dac.pm;+ spin_lock_irqsave(&pm->lock, flags);+ pm->dev->cur_state = AWAKE_STATE;+ powerup_dac(s);+ spin_unlock_irqrestore(&pm->lock, flags);+ }+#else+ /* If not awake... then return EBUSY */+ if ( s->dma_dac.pm.dev->cur_state != AWAKE_STATE )+ return -EBUSY;+#endif // WAKE_ON_ACCESS+#endif + count *= db->cnt_factor; down(&s->sem); @@ -1581,7 +1725,7 @@ if (val & PCM_ENABLE_OUTPUT) start_dac(s); else- stop_dac(s);+ pause_dac(s); } return 0; @@ -1883,9 +2027,225 @@ release: au1550_release, }; +#ifdef CONFIG_PM++static void warm_codec_reset(void) {+ u32 ctrl, timeout=0;++ /* Suspend PSC clocking */+ ctrl = au_readl(AC97_PSC_CTRL);+ au_writel(PSC_CTRL_SUSPEND, AC97_PSC_CTRL);+ au_sync();+ au1550_delay(10);++ do+ {+ if ( !( au_readl(PSC_AC97STAT)& PSC_AC97STAT_CB))+ break;+ }while(++timeout < 0xFFFFF);++ if ( timeout >= 0xFFFFF) printk("CB detected ... we're screwed\n");+ /* warm reset the AC'97 to start the bitclk+ */+ au_writel(PSC_AC97RST_SNC, PSC_AC97RST);+ au_sync();+ udelay(2);+ au_writel(0, PSC_AC97RST);+ au_sync();+ au1550_delay(10);++ /* Endable PSC clocks again */+ au_writel(ctrl, AC97_PSC_CTRL);+ au_sync();+ au1550_delay(10);+}++static void powerdown_all(struct au1550_state *s)+{+ u16 tmp;+ + stop_dac(s);+ stop_adc(s);++ tmp = s->codec->codec_read(s->codec, AC97_POWER_CONTROL);+ /* We have no way to talk to CODEC if we shutdown AClink(PR4) */+ tmp |= AC97_PWR_PR0 | AC97_PWR_PR1 | AC97_PWR_PR2 | AC97_PWR_PR4 | AC97_PWR_PR5 | AC97_PWR_PR6;+ s->codec->codec_write(s->codec, AC97_POWER_CONTROL, tmp );+}+static void powerdown_dac(struct au1550_state *s) +{+ u16 tmp;++ if ( s->dma_adc.pm.dev->cur_state != AWAKE_STATE )+ return powerdown_all(s);++ + stop_dac(s);+ tmp = s->codec->codec_read(s->codec, AC97_POWER_CONTROL);+ tmp |= AC97_PWR_PR1;+ s->codec->codec_write(s->codec, AC97_POWER_CONTROL, tmp );+}+static void powerdown_adc(struct au1550_state *s) +{+ u16 tmp;++ if ( s->dma_dac.pm.dev->cur_state != AWAKE_STATE )+ return powerdown_all(s);++ + stop_adc(s);+ tmp = s->codec->codec_read(s->codec, AC97_POWER_CONTROL);+ tmp |= AC97_PWR_PR0;+ s->codec->codec_write(s->codec, AC97_POWER_CONTROL, tmp );+}++static void powerup_dac(struct au1550_state *s) +{+ u16 tmp;+ ++ if ( s->dma_dac.pm.dev->cur_state != AWAKE_STATE && + s->dma_adc.pm.dev->cur_state != AWAKE_STATE )+ warm_codec_reset(); ++ tmp = s->codec->codec_read(s->codec, AC97_POWER_CONTROL);+ tmp &= ~(AC97_PWR_PR1 | AC97_PWR_PR2 | AC97_PWR_PR5 | AC97_PWR_PR6);+ s->codec->codec_write(s->codec, AC97_POWER_CONTROL, tmp );+}+static void powerup_adc(struct au1550_state *s) +{+ u16 tmp;+ ++ if ( s->dma_dac.pm.dev->cur_state != AWAKE_STATE && + s->dma_adc.pm.dev->cur_state != AWAKE_STATE )+ warm_codec_reset(); ++ tmp = s->codec->codec_read(s->codec, AC97_POWER_CONTROL);+ tmp &= ~(AC97_PWR_PR0 | AC97_PWR_PR2 | AC97_PWR_PR5 | AC97_PWR_PR6);+ s->codec->codec_write(s->codec, AC97_POWER_CONTROL, tmp );+}+++int au1550_pm_callback( au1xxx_power_dev_t *dev, au1xxx_request_t request, void *data )+{+ u32 flags, isdac = (u32)data;+ struct au1550_state *s = &au1550_state;+ pm_state *pm;+ int ret=0;+ + if ( isdac ) pm = &s->dma_dac.pm;+ else pm = &s->dma_adc.pm;++ spin_lock_irqsave(&pm->lock, flags);+ switch ( request )+ {+ case AU1XXX_PM_SLEEP:+ + if (isdac) powerdown_dac(s);+ else powerdown_adc(s);++ break;++ case AU1XXX_PM_WAKEUP:+ if(dev->prev_state == SLEEP_STATE) {+ int val;+ /* The GPIO for the appropriate PSC was configured by the+ * board specific start up.+ *+ * configure PSC for AC'97+ */+ au_writel(0, AC97_PSC_CTRL); /* Disable PSC */+ au_sync();+ au_writel((PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE), AC97_PSC_SEL);+ au_sync();++ warm_codec_reset();+ /* warm reset the AC'97 to start the bitclk+ */+ au_writel(PSC_AC97RST_SNC, PSC_AC97RST);+ au_sync();+ udelay(100);+ au_writel(0, PSC_AC97RST);+ au_sync();+ ++ /* Enable PSC+ */+ au_writel(PSC_CTRL_ENABLE, AC97_PSC_CTRL);+ au_sync();++ /* Wait for PSC ready.+ */+ do {+ val = readl((void *)PSC_AC97STAT);+ au_sync();+ } while ((val & PSC_AC97STAT_SR) == 0);++ /* Configure AC97 controller.+ * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size.+ */+ val = PSC_AC97CFG_SET_LEN(16);+ val |= PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 ;++ /* Enable device so we can at least+ * talk over the AC-link.+ */+ au_writel(val, PSC_AC97CFG);+ au_writel(PSC_AC97MSK_ALLMASK, PSC_AC97MSK);+ au_sync();+ val |= PSC_AC97CFG_DE_ENABLE;+ au_writel(val, PSC_AC97CFG);+ au_sync();+++ /* Wait for Device ready.+ */+ do {+ val = readl((void *)PSC_AC97STAT);+ au_sync();+ } while ((val & PSC_AC97STAT_DR) == 0);+ }++ if (isdac) powerup_dac(s);+ else powerup_adc(s);+ ac97_restore_state(s->codec);+ break;++ case AU1XXX_PM_ACCESS:+ if (dev->cur_state != AWAKE_STATE) {+ /*do nothing */+ }+ else+ ret = -1;+ break;++ case AU1XXX_PM_GETSTATUS:+ + ret = dev->cur_state;+ break;++ default:+ case AU1XXX_PM_IDLE:+ case AU1XXX_PM_CLEANUP:+ + break;+ }++ spin_unlock_irqrestore(&pm->lock, flags);+ return ret;+}++#endif+ MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com"); MODULE_DESCRIPTION("Au1550 AC97 Audio Driver"); +static dbdev_tab_t au1xac97_mem_dbdev = {+ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 16, 0x00000000, 0, 0+};++ static int __devinit au1550_probe(void) {@@ -1918,7 +2278,9 @@ /* Allocate the DMA Channels */- if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN,+ int memid = au1xxx_ddma_add_device(&au1xac97_mem_dbdev);++ if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(memid, DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) { err("Can't get DAC DMA"); goto err_dma1;@@ -1931,7 +2293,7 @@ } if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN,- DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) {+ memid, adc_dma_interrupt, (void *)s)) == 0) { err("Can't get ADC DMA"); goto err_dma2; }@@ -1944,6 +2306,16 @@ pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_AC97_TX_CHAN, DBDMA_AC97_RX_CHAN); + +#ifdef CONFIG_PM+ spin_lock_init(&s->dma_dac.pm.lock);+ spin_lock_init(&s->dma_adc.pm.lock);+ /* Register the power management capibilites with the manager */+ s->dma_dac.pm.dev = new_au1xxx_power_device( "dac", au1550_pm_callback, (void*)1 );+ s->dma_adc.pm.dev = new_au1xxx_power_device( "adc", au1550_pm_callback, (void*)0 );+#endif+ + /* register devices */ if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0)diff -Nbur linux26-cvs/sound/oss/Kconfig linux26-cvs.ac97/sound/oss/Kconfig--- linux26-cvs/sound/oss/Kconfig 2005-08-01 14:14:39.000000000 -0500+++ linux26-cvs.ac97/sound/oss/Kconfig 2005-08-01 14:13:19.000000000 -0500@@ -222,11 +222,11 @@ config SOUND_AU1550_AC97 tristate "Au1550 AC97 Sound"- depends on SOUND_PRIME!=n && SOC_AU1550 && SOUND+ depends on SOUND_PRIME!=n && (SOC_AU1550 || SOC_AU1200) && SOUND config SOUND_AU1550_I2S tristate "Au1550 I2S Sound"- depends on SOUND_PRIME!=n && SOC_AU1550 && SOUND+ depends on SOUND_PRIME!=n && (SOC_AU1550 || SOC_AU1200) && SOUND config SOUND_TRIDENT tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -