📄 i2s.patch
字号:
if (nonblock) return -EBUSY;- tmo = 1000 * count / SAMP_RATE;++ tmo = 1000 * count / ((s->dma_dac.src_factor!=1) ?+ s->i2s->sr : s->dma_dac.sample_rate);+ tmo /= s->dma_dac.dma_bytes_per_sample; au1550_delay(tmo); }@@ -848,8 +791,7 @@ static inline s16 U8_TO_S16(u8 ch) * If interpolating (no VRA), duplicate every audio frame src_factor times. */ static int-translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf,- int dmacount)+translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf, int dmacount) { int sample, i; int interp_bytes_per_sample;@@ -887,11 +829,12 @@ translate_from_user(struct dmabuf *db, c /* duplicate every audio frame src_factor times */- for (i = 0; i < db->src_factor; i++)+ for (i = 0; i < db->src_factor; i++) { memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);+ dmabuf += interp_bytes_per_sample;+ } userbuf += db->user_bytes_per_sample;- dmabuf += interp_bytes_per_sample; } return num_samples * interp_bytes_per_sample;@@ -965,7 +908,7 @@ copy_dmabuf_user(struct dmabuf *db, char 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;@@ -976,7 +919,7 @@ copy_dmabuf_user(struct dmabuf *db, char 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;@@ -991,6 +934,7 @@ copy_dmabuf_user(struct dmabuf *db, char return ret; } + static ssize_t au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) {@@ -1006,6 +950,25 @@ au1550_read(struct file *file, char *buf if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0;+/*Power Management*/+ +#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; @@ -1081,15 +1044,31 @@ au1550_write(struct file *file, const ch unsigned long flags; int cnt, usercnt, avail; -#ifdef AU1000_VERBOSE_DEBUG- dbg("write: count=%d", count);-#endif+ pr_debug("write: count=%d\n", count); if (db->mapped) return -ENXIO; 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); @@ -1141,15 +1120,14 @@ au1550_write(struct file *file, const ch * on the dma queue. If the queue count reaches zero, * we know the dma has stopped. */- while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {+ while ((db->dma_qcount < MIN_Q_COUNT) && (db->count >= db->fragsize)) { if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut, db->fragsize) == 0) {- pr_error("qcount < 2 and no ring room!");+ err("qcount < MIN_Q_COUNT and no ring room!"); } db->nextOut += db->fragsize; if (db->nextOut >= db->rawbuf + db->dmasize) db->nextOut -= db->dmasize;- db->count -= db->fragsize; db->total_bytes += db->dma_fragsize; if (db->dma_qcount == 0) start_dac(s);@@ -1162,7 +1140,6 @@ au1550_write(struct file *file, const ch buffer += usercnt; ret += usercnt; } /* while (count > 0) */- out: up(&s->sem); out2:@@ -1239,8 +1216,7 @@ au1550_mmap(struct file *file, struct vm ret = -EINVAL; goto out; }- if (remap_pfn_range(vma, vma->vm_start,- page_to_pfn(virt_to_page(db->rawbuf)),+ if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page(db->rawbuf)), size, vma->vm_page_prot)) { ret = -EAGAIN; goto out;@@ -1254,7 +1230,7 @@ out: } -#ifdef AU1000_VERBOSE_DEBUG+#ifdef DEBUG static struct ioctl_str_t { unsigned int cmd; const char *str;@@ -1320,15 +1296,15 @@ au1550_ioctl(struct inode *inode, struct mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); -#ifdef AU1000_VERBOSE_DEBUG+#ifdef DEBUG for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) { if (ioctl_str[count].cmd == cmd) break; } if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0]))- dbg("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg);+ pr_debug("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg); else- dbg("ioctl 0x%x unknown, arg=0x%lx", cmd, arg);+ pr_debug("ioctl 0x%x unknown, arg=0x%lx", cmd, arg); #endif switch (cmd) {@@ -1383,6 +1359,7 @@ au1550_ioctl(struct inode *inode, struct if ((ret = prog_dmabuf_dac(s))) return ret; }+ return put_user((file->f_mode & FMODE_READ) ? s->dma_adc.sample_rate : s->dma_dac.sample_rate,@@ -1499,7 +1476,7 @@ au1550_ioctl(struct inode *inode, struct if (val & PCM_ENABLE_OUTPUT) start_dac(s); else- stop_dac(s);+ pause_dac(s); } return 0; @@ -1517,9 +1494,6 @@ au1550_ioctl(struct inode *inode, struct s->dma_dac.cnt_factor; abinfo.fragstotal = s->dma_dac.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;-#ifdef AU1000_VERBOSE_DEBUG- dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments);-#endif return copy_to_user((void *) arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; @@ -1682,8 +1656,8 @@ au1550_ioctl(struct inode *inode, struct case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL;+ default: break; }- return 0; } @@ -1696,11 +1670,11 @@ au1550_open(struct inode *inode, struct struct au1550_state *s = &au1550_state; int ret; -#ifdef AU1000_VERBOSE_DEBUG+#ifdef DEBUG if (file->f_flags & O_NONBLOCK)- dbg(__FUNCTION__ ": non-blocking");+ pr_debug(__FUNCTION__ ": non-blocking"); else- dbg(__FUNCTION__ ": blocking");+ pr_debug(__FUNCTION__ ": blocking"); #endif file->private_data = s;@@ -1791,7 +1765,7 @@ au1550_release(struct inode *inode, stru return 0; } -static struct file_operations au1550_audio_fops = {+static /*const */ struct file_operations au1550_audio_fops = { owner: THIS_MODULE, llseek: au1550_llseek, read: au1550_read,@@ -1803,55 +1777,119 @@ static struct file_operations au1550_aud release: au1550_release, }; -/* Set up an internal clock for the PSC3. This will then get- * driven out of the Au1550 as the master.- */-static void-intclk_setup(void)+#ifdef CONFIG_PM+/*No Warm Codec Reset for I2S (different than AC'97)*/++static void powerdown_all(struct au1550_state *s) {- uint clk, rate;+ struct i2s_hw *hw;+ hw=s->i2s;+ stop_dac(s);+ stop_adc(s); - /* Wire up Freq4 as a clock for the PSC3.- * We know SMBus uses Freq3.- * By making changes to this rate, plus the word strobe- * size, we can make fine adjustments to the actual data rate.- */- rate = get_au1x00_speed();-#ifdef TRY_441KHz- rate /= (11 * 1000000);-#else- rate /= (12 * 1000000);-#endif+ hw->power(hw, ALL_OFF);+}+static void powerdown_dac(struct au1550_state *s) +{+ struct i2s_hw *hw;+ hw=s->i2s; - /* The FRDIV in the frequency control is (FRDIV + 1) * 2- */- rate /=2;- rate--;- clk = au_readl(SYS_FREQCTRL1);- au_sync();- clk &= ~(SYS_FC_FRDIV4_MASK | SYS_FC_FS4);;- clk |= (rate << SYS_FC_FRDIV4_BIT);- clk |= SYS_FC_FE4;- au_writel(clk, SYS_FREQCTRL1);- au_sync();+ if ( s->dma_adc.pm.dev->cur_state != AWAKE_STATE )+ return powerdown_all(s);+ + stop_dac(s);+ hw->power(hw, DAC_OFF);+}+static void powerdown_adc(struct au1550_state *s) +{+ struct i2s_hw *hw;+ hw=s->i2s; - /* Set up the clock source routing to get Freq4 to PSC3_intclk.- */- clk = au_readl(SYS_CLKSRC);- au_sync();- clk &= ~0x01f00000;- clk |= (6 << 22);- au_writel(clk, SYS_CLKSRC);- au_sync();+ if ( s->dma_dac.pm.dev->cur_state != AWAKE_STATE )+ return powerdown_all(s);++ stop_adc(s);+ hw->power(hw, ADC_OFF);++}+static void powerup_dac(struct au1550_state *s) +{+ struct i2s_hw *hw;+ hw=s->i2s;+ + hw->power(hw, DAC_ON); + +}++static void powerup_adc(struct au1550_state *s) +{+ struct i2s_hw *hw;+ hw=s->i2s;+ + hw->power(hw, ADC_ON);+}+++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:+ s->i2s = AMD_PbDb_setup(I2S_PSC_BASE, PSC_SEL_CLK_SERCLK);+ if (isdac) powerup_dac(s);+ else powerup_adc(s);+ break;++ case AU1XXX_PM_ACCESS:+ + if (dev->cur_state != AWAKE_STATE) {+ + }+ else+ ret = -1;+ break;++ case AU1XXX_PM_GETSTATUS:+ ret = dev->cur_state;+ break;++ default:+ case AU1XXX_PM_IDLE:+ case AU1XXX_PM_CLEANUP:+ printk("default\n");+ break;+ }++ spin_unlock_irqrestore(&pm->lock, flags);+ return ret; } +#endif++MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");+MODULE_DESCRIPTION("Au1550 Audio Driver");++ static int __devinit au1550_probe(void) { struct au1550_state *s = &au1550_state;- int val;- volatile psc_i2s_t *ip;-#ifdef AU1550_DEBUG+#ifdef DEBUG char proc_str[80]; #endif @@ -1863,123 +1901,72 @@ au1550_probe(void) init_MUTEX(&s->open_sem); spin_lock_init(&s->lock); - s->codec = &au1550_i2s_codec;- s->psc_addr = (volatile psc_i2s_t *)I2S_PSC_BASE;- ip = s->psc_addr;-- if (!request_region(CPHYSADDR(ip),- 0x30, AU1550_MODULE_NAME)) {- pr_error("I2S Audio ports in use");- }+ s->i2s = i2s_hw_init(); /* Allocate the DMA Channels */ if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN, DBDMA_I2S_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) {- pr_error("Can't get DAC DMA");+ err("Can't get DAC DMA"); goto err_dma1; } au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16); if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr, NUM_DBDMA_DESCRIPTORS) == 0) {- pr_error("Can't get DAC DMA descriptors");+ err("Can't get DAC DMA descriptors"); goto err_dma1; } if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_I2S_RX_CHAN, DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) {- pr_error("Can't get ADC DMA");+ err("Can't get ADC DMA"); goto err_dma2; } au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16); if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr, NUM_DBDMA_DESCRIPTORS) == 0) {- pr_error("Can't get ADC DMA descriptors");+ err("Can't get ADC DMA descriptors"); goto err_dma2; } - pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_I2S_TX_CHAN, DBDMA_I2S_RX_CHAN);+ info("%s CODEC", s->i2s->name );+ info("DAC: DMA%d, ADC: DMA%d", DBDMA_I2S_TX_CHAN, DBDMA_I2S_RX_CHAN); - /* register devices */ +#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) goto err_dev1; if ((s->dev_mixer = register_sound_mixer(&au1550_mixer_fops, -1)) < 0) goto err_dev2; -#ifdef AU1550_DEBUG+#ifdef DEBUG /* intialize the debug proc device */ s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL, proc_au1550_dump, NULL); #endif /* AU1550_DEBUG */ - intclk_setup();-- /* The GPIO for the appropriate PSC was configured by the- * board specific start up.- *- * configure PSC for I2S Audio
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -