Loading sound/arm/aaci.c +232 −26 Original line number Diff line number Diff line Loading @@ -166,6 +166,65 @@ static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) */ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) { if (mask & ISR_ORINTR) { dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel); writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR); } if (mask & ISR_RXTOINTR) { dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel); writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR); } if (mask & ISR_RXINTR) { struct aaci_runtime *aacirun = &aaci->capture; void *ptr; if (!aacirun->substream || !aacirun->start) { dev_warn(&aaci->dev->dev, "RX interrupt???"); writel(0, aacirun->base + AACI_IE); return; } ptr = aacirun->ptr; do { unsigned int len = aacirun->fifosz; u32 val; if (aacirun->bytes <= 0) { aacirun->bytes += aacirun->period; aacirun->ptr = ptr; spin_unlock(&aaci->lock); snd_pcm_period_elapsed(aacirun->substream); spin_lock(&aaci->lock); } if (!(aacirun->cr & CR_EN)) break; val = readl(aacirun->base + AACI_SR); if (!(val & SR_RXHF)) break; if (!(val & SR_RXFF)) len >>= 1; aacirun->bytes -= len; /* reading 16 bytes at a time */ for( ; len > 0; len -= 16) { asm( "ldmia %1, {r0, r1, r2, r3}\n\t" "stmia %0!, {r0, r1, r2, r3}" : "+r" (ptr) : "r" (aacirun->fifo) : "r0", "r1", "r2", "r3", "cc"); if (ptr >= aacirun->end) ptr = aacirun->start; } } while(1); aacirun->ptr = ptr; } if (mask & ISR_URINTR) { dev_dbg(&aaci->dev->dev, "TX underrun on chan %d\n", channel); writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR); Loading Loading @@ -193,7 +252,7 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) snd_pcm_period_elapsed(aacirun->substream); spin_lock(&aaci->lock); } if (!(aacirun->cr & TXCR_TXEN)) if (!(aacirun->cr & CR_EN)) break; val = readl(aacirun->base + AACI_SR); Loading Loading @@ -331,7 +390,8 @@ static struct snd_pcm_hardware aaci_hw_info = { .periods_max = PAGE_SIZE / 16, }; static int aaci_pcm_open(struct aaci *aaci, struct snd_pcm_substream *substream, static int __aaci_pcm_open(struct aaci *aaci, struct snd_pcm_substream *substream, struct aaci_runtime *aacirun) { struct snd_pcm_runtime *runtime = substream->runtime; Loading Loading @@ -381,7 +441,7 @@ static int aaci_pcm_close(struct snd_pcm_substream *substream) struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; WARN_ON(aacirun->cr & TXCR_TXEN); WARN_ON(aacirun->cr & CR_EN); aacirun->substream = NULL; free_irq(aaci->dev->irq[0], aaci); Loading @@ -396,7 +456,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream) /* * This must not be called with the device enabled. */ WARN_ON(aacirun->cr & TXCR_TXEN); WARN_ON(aacirun->cr & CR_EN); if (aacirun->pcm_open) snd_ac97_pcm_close(aacirun->pcm); Loading @@ -423,9 +483,15 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto out; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), params_channels(params), aacirun->pcm->r[0].slots); else err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), params_channels(params), aacirun->pcm->r[1].slots); if (err) goto out; Loading Loading @@ -468,9 +534,9 @@ static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_str * Playback specific ALSA stuff */ static const u32 channels_to_txmask[] = { [2] = TXCR_TX3 | TXCR_TX4, [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8, [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9, [2] = CR_SL3 | CR_SL4, [4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8, [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9, }; /* Loading Loading @@ -505,7 +571,7 @@ aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule) chan_mask); } static int aaci_pcm_playback_open(struct snd_pcm_substream *substream) static int aaci_pcm_open(struct snd_pcm_substream *substream) { struct aaci *aaci = substream->private_data; int ret; Loading @@ -520,7 +586,12 @@ static int aaci_pcm_playback_open(struct snd_pcm_substream *substream) if (ret) return ret; return aaci_pcm_open(aaci, substream, &aaci->playback); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ret = __aaci_pcm_open(aaci, substream, &aaci->playback); } else { ret = __aaci_pcm_open(aaci, substream, &aaci->capture); } return ret; } static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, Loading @@ -541,11 +612,11 @@ static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, * FIXME: double rate slots? */ if (ret >= 0) { aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16; aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; aacirun->cr |= channels_to_txmask[channels]; aacirun->fifosz = aaci->fifosize * 4; if (aacirun->cr & TXCR_COMPACT) if (aacirun->cr & CR_COMPACT) aacirun->fifosz >>= 1; } return ret; Loading @@ -558,7 +629,7 @@ static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) ie = readl(aacirun->base + AACI_IE); ie &= ~(IE_URIE|IE_TXIE); writel(ie, aacirun->base + AACI_IE); aacirun->cr &= ~TXCR_TXEN; aacirun->cr &= ~CR_EN; aaci_chan_wait_ready(aacirun); writel(aacirun->cr, aacirun->base + AACI_TXCR); } Loading @@ -568,7 +639,7 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) u32 ie; aaci_chan_wait_ready(aacirun); aacirun->cr |= TXCR_TXEN; aacirun->cr |= CR_EN; ie = readl(aacirun->base + AACI_IE); ie |= IE_URIE | IE_TXIE; Loading Loading @@ -616,7 +687,7 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm } static struct snd_pcm_ops aaci_playback_ops = { .open = aaci_pcm_playback_open, .open = aaci_pcm_open, .close = aaci_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = aaci_pcm_playback_hw_params, Loading @@ -627,7 +698,133 @@ static struct snd_pcm_ops aaci_playback_ops = { .mmap = aaci_pcm_mmap, }; static int aaci_pcm_capture_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params) { struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; int ret; ret = aaci_pcm_hw_params(substream, aacirun, params); if (ret >= 0) { aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; /* Line in record: slot 3 and 4 */ aacirun->cr |= CR_SL3 | CR_SL4; aacirun->fifosz = aaci->fifosize * 4; if (aacirun->cr & CR_COMPACT) aacirun->fifosz >>= 1; } return ret; } static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun) { u32 ie; aaci_chan_wait_ready(aacirun); ie = readl(aacirun->base + AACI_IE); ie &= ~(IE_ORIE | IE_RXIE); writel(ie, aacirun->base+AACI_IE); aacirun->cr &= ~CR_EN; writel(aacirun->cr, aacirun->base + AACI_RXCR); } static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) { u32 ie; aaci_chan_wait_ready(aacirun); #ifdef DEBUG /* RX Timeout value: bits 28:17 in RXCR */ aacirun->cr |= 0xf << 17; #endif aacirun->cr |= CR_EN; writel(aacirun->cr, aacirun->base + AACI_RXCR); ie = readl(aacirun->base + AACI_IE); ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full writel(ie, aacirun->base + AACI_IE); } static int aaci_pcm_capture_trigger(snd_pcm_substream_t *substream, int cmd){ struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; unsigned long flags; int ret = 0; spin_lock_irqsave(&aaci->lock, flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: aaci_pcm_capture_start(aacirun); break; case SNDRV_PCM_TRIGGER_RESUME: aaci_pcm_capture_start(aacirun); break; case SNDRV_PCM_TRIGGER_STOP: aaci_pcm_capture_stop(aacirun); break; case SNDRV_PCM_TRIGGER_SUSPEND: aaci_pcm_capture_stop(aacirun); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: break; default: ret = -EINVAL; } spin_unlock_irqrestore(&aaci->lock, flags); return ret; } static int aaci_pcm_capture_prepare(snd_pcm_substream_t *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct aaci *aaci = substream->private_data; aaci_pcm_prepare(substream); /* allow changing of sample rate */ aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */ aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate); /* Record select: Mic: 0, Aux: 3, Line: 4 */ aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404); return 0; } static snd_pcm_ops_t aaci_capture_ops = { .open = aaci_pcm_open, .close = aaci_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = aaci_pcm_capture_hw_params, .hw_free = aaci_pcm_hw_free, .prepare = aaci_pcm_capture_prepare, .trigger = aaci_pcm_capture_trigger, .pointer = aaci_pcm_pointer, .mmap = aaci_pcm_mmap, }; /* * Power Management. Loading Loading @@ -741,6 +938,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); if (ret) goto out; aaci->ac97 = ac97; /* * Disable AC97 PC Beep input on audio codecs. Loading @@ -753,6 +951,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) goto out; aaci->playback.pcm = &ac97_bus->pcms[0]; aaci->capture.pcm = &ac97_bus->pcms[1]; out: return ret; Loading Loading @@ -802,7 +1001,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) struct snd_pcm *pcm; int ret; ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm); ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm); if (ret == 0) { aaci->pcm = pcm; pcm->private_data = aaci; Loading @@ -811,6 +1010,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); } return ret; Loading @@ -818,15 +1018,15 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) { void __iomem *base = aaci->base + AACI_CSCH1; struct aaci_runtime *aacirun = &aaci->playback; int i; writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR); writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR); for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++) writel(0, aaci->base + AACI_DR1); for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++) writel(0, aacirun->fifo); writel(0, base + AACI_TXCR); writel(0, aacirun->base + AACI_TXCR); /* * Re-initialise the AACI after the FIFO depth test, to Loading Loading @@ -873,6 +1073,12 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id) aaci->playback.base = aaci->base + AACI_CSCH1; aaci->playback.fifo = aaci->base + AACI_DR1; /* * Capture uses AACI channel 0 */ aaci->capture.base = aaci->base + AACI_CSCH1; aaci->capture.fifo = aaci->base + AACI_DR1; for (i = 0; i < 4; i++) { void __iomem *base = aaci->base + i * 0x14; Loading sound/arm/aaci.h +21 −20 Original line number Diff line number Diff line Loading @@ -49,27 +49,27 @@ #define AACI_DR4 0x0f0 /* data read/written fifo 4 */ /* * transmit fifo control register. P48 */ #define TXCR_FEN (1 << 16) /* fifo enable */ #define TXCR_COMPACT (1 << 15) /* compact mode */ #define TXCR_TSZ16 (0 << 13) /* 16 bits */ #define TXCR_TSZ18 (1 << 13) /* 18 bits */ #define TXCR_TSZ20 (2 << 13) /* 20 bits */ #define TXCR_TSZ12 (3 << 13) /* 12 bits */ #define TXCR_TX12 (1 << 12) /* transmits slot 12 */ #define TXCR_TX11 (1 << 11) /* transmits slot 12 */ #define TXCR_TX10 (1 << 10) /* transmits slot 12 */ #define TXCR_TX9 (1 << 9) /* transmits slot 12 */ #define TXCR_TX8 (1 << 8) /* transmits slot 12 */ #define TXCR_TX7 (1 << 7) /* transmits slot 12 */ #define TXCR_TX6 (1 << 6) /* transmits slot 12 */ #define TXCR_TX5 (1 << 5) /* transmits slot 12 */ #define TXCR_TX4 (1 << 4) /* transmits slot 12 */ #define TXCR_TX3 (1 << 3) /* transmits slot 12 */ #define TXCR_TX2 (1 << 2) /* transmits slot 12 */ #define TXCR_TX1 (1 << 1) /* transmits slot 12 */ #define TXCR_TXEN (1 << 0) /* transmit enable */ * TX/RX fifo control register (CR). P48 */ #define CR_FEN (1 << 16) /* fifo enable */ #define CR_COMPACT (1 << 15) /* compact mode */ #define CR_SZ16 (0 << 13) /* 16 bits */ #define CR_SZ18 (1 << 13) /* 18 bits */ #define CR_SZ20 (2 << 13) /* 20 bits */ #define CR_SZ12 (3 << 13) /* 12 bits */ #define CR_SL12 (1 << 12) #define CR_SL11 (1 << 11) #define CR_SL10 (1 << 10) #define CR_SL9 (1 << 9) #define CR_SL8 (1 << 8) #define CR_SL7 (1 << 7) #define CR_SL6 (1 << 6) #define CR_SL5 (1 << 5) #define CR_SL4 (1 << 4) #define CR_SL3 (1 << 3) #define CR_SL2 (1 << 2) #define CR_SL1 (1 << 1) #define CR_EN (1 << 0) /* transmit enable */ /* * status register bits. P49 Loading Loading @@ -229,6 +229,7 @@ struct aaci { /* AC'97 */ struct mutex ac97_sem; ac97_bus_t *ac97_bus; ac97_t *ac97; u32 maincr; spinlock_t lock; Loading Loading
sound/arm/aaci.c +232 −26 Original line number Diff line number Diff line Loading @@ -166,6 +166,65 @@ static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) */ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) { if (mask & ISR_ORINTR) { dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel); writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR); } if (mask & ISR_RXTOINTR) { dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel); writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR); } if (mask & ISR_RXINTR) { struct aaci_runtime *aacirun = &aaci->capture; void *ptr; if (!aacirun->substream || !aacirun->start) { dev_warn(&aaci->dev->dev, "RX interrupt???"); writel(0, aacirun->base + AACI_IE); return; } ptr = aacirun->ptr; do { unsigned int len = aacirun->fifosz; u32 val; if (aacirun->bytes <= 0) { aacirun->bytes += aacirun->period; aacirun->ptr = ptr; spin_unlock(&aaci->lock); snd_pcm_period_elapsed(aacirun->substream); spin_lock(&aaci->lock); } if (!(aacirun->cr & CR_EN)) break; val = readl(aacirun->base + AACI_SR); if (!(val & SR_RXHF)) break; if (!(val & SR_RXFF)) len >>= 1; aacirun->bytes -= len; /* reading 16 bytes at a time */ for( ; len > 0; len -= 16) { asm( "ldmia %1, {r0, r1, r2, r3}\n\t" "stmia %0!, {r0, r1, r2, r3}" : "+r" (ptr) : "r" (aacirun->fifo) : "r0", "r1", "r2", "r3", "cc"); if (ptr >= aacirun->end) ptr = aacirun->start; } } while(1); aacirun->ptr = ptr; } if (mask & ISR_URINTR) { dev_dbg(&aaci->dev->dev, "TX underrun on chan %d\n", channel); writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR); Loading Loading @@ -193,7 +252,7 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) snd_pcm_period_elapsed(aacirun->substream); spin_lock(&aaci->lock); } if (!(aacirun->cr & TXCR_TXEN)) if (!(aacirun->cr & CR_EN)) break; val = readl(aacirun->base + AACI_SR); Loading Loading @@ -331,7 +390,8 @@ static struct snd_pcm_hardware aaci_hw_info = { .periods_max = PAGE_SIZE / 16, }; static int aaci_pcm_open(struct aaci *aaci, struct snd_pcm_substream *substream, static int __aaci_pcm_open(struct aaci *aaci, struct snd_pcm_substream *substream, struct aaci_runtime *aacirun) { struct snd_pcm_runtime *runtime = substream->runtime; Loading Loading @@ -381,7 +441,7 @@ static int aaci_pcm_close(struct snd_pcm_substream *substream) struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; WARN_ON(aacirun->cr & TXCR_TXEN); WARN_ON(aacirun->cr & CR_EN); aacirun->substream = NULL; free_irq(aaci->dev->irq[0], aaci); Loading @@ -396,7 +456,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream) /* * This must not be called with the device enabled. */ WARN_ON(aacirun->cr & TXCR_TXEN); WARN_ON(aacirun->cr & CR_EN); if (aacirun->pcm_open) snd_ac97_pcm_close(aacirun->pcm); Loading @@ -423,9 +483,15 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto out; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), params_channels(params), aacirun->pcm->r[0].slots); else err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), params_channels(params), aacirun->pcm->r[1].slots); if (err) goto out; Loading Loading @@ -468,9 +534,9 @@ static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_str * Playback specific ALSA stuff */ static const u32 channels_to_txmask[] = { [2] = TXCR_TX3 | TXCR_TX4, [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8, [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9, [2] = CR_SL3 | CR_SL4, [4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8, [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9, }; /* Loading Loading @@ -505,7 +571,7 @@ aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule) chan_mask); } static int aaci_pcm_playback_open(struct snd_pcm_substream *substream) static int aaci_pcm_open(struct snd_pcm_substream *substream) { struct aaci *aaci = substream->private_data; int ret; Loading @@ -520,7 +586,12 @@ static int aaci_pcm_playback_open(struct snd_pcm_substream *substream) if (ret) return ret; return aaci_pcm_open(aaci, substream, &aaci->playback); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ret = __aaci_pcm_open(aaci, substream, &aaci->playback); } else { ret = __aaci_pcm_open(aaci, substream, &aaci->capture); } return ret; } static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, Loading @@ -541,11 +612,11 @@ static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, * FIXME: double rate slots? */ if (ret >= 0) { aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16; aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; aacirun->cr |= channels_to_txmask[channels]; aacirun->fifosz = aaci->fifosize * 4; if (aacirun->cr & TXCR_COMPACT) if (aacirun->cr & CR_COMPACT) aacirun->fifosz >>= 1; } return ret; Loading @@ -558,7 +629,7 @@ static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) ie = readl(aacirun->base + AACI_IE); ie &= ~(IE_URIE|IE_TXIE); writel(ie, aacirun->base + AACI_IE); aacirun->cr &= ~TXCR_TXEN; aacirun->cr &= ~CR_EN; aaci_chan_wait_ready(aacirun); writel(aacirun->cr, aacirun->base + AACI_TXCR); } Loading @@ -568,7 +639,7 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) u32 ie; aaci_chan_wait_ready(aacirun); aacirun->cr |= TXCR_TXEN; aacirun->cr |= CR_EN; ie = readl(aacirun->base + AACI_IE); ie |= IE_URIE | IE_TXIE; Loading Loading @@ -616,7 +687,7 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm } static struct snd_pcm_ops aaci_playback_ops = { .open = aaci_pcm_playback_open, .open = aaci_pcm_open, .close = aaci_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = aaci_pcm_playback_hw_params, Loading @@ -627,7 +698,133 @@ static struct snd_pcm_ops aaci_playback_ops = { .mmap = aaci_pcm_mmap, }; static int aaci_pcm_capture_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params) { struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; int ret; ret = aaci_pcm_hw_params(substream, aacirun, params); if (ret >= 0) { aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; /* Line in record: slot 3 and 4 */ aacirun->cr |= CR_SL3 | CR_SL4; aacirun->fifosz = aaci->fifosize * 4; if (aacirun->cr & CR_COMPACT) aacirun->fifosz >>= 1; } return ret; } static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun) { u32 ie; aaci_chan_wait_ready(aacirun); ie = readl(aacirun->base + AACI_IE); ie &= ~(IE_ORIE | IE_RXIE); writel(ie, aacirun->base+AACI_IE); aacirun->cr &= ~CR_EN; writel(aacirun->cr, aacirun->base + AACI_RXCR); } static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) { u32 ie; aaci_chan_wait_ready(aacirun); #ifdef DEBUG /* RX Timeout value: bits 28:17 in RXCR */ aacirun->cr |= 0xf << 17; #endif aacirun->cr |= CR_EN; writel(aacirun->cr, aacirun->base + AACI_RXCR); ie = readl(aacirun->base + AACI_IE); ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full writel(ie, aacirun->base + AACI_IE); } static int aaci_pcm_capture_trigger(snd_pcm_substream_t *substream, int cmd){ struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; unsigned long flags; int ret = 0; spin_lock_irqsave(&aaci->lock, flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: aaci_pcm_capture_start(aacirun); break; case SNDRV_PCM_TRIGGER_RESUME: aaci_pcm_capture_start(aacirun); break; case SNDRV_PCM_TRIGGER_STOP: aaci_pcm_capture_stop(aacirun); break; case SNDRV_PCM_TRIGGER_SUSPEND: aaci_pcm_capture_stop(aacirun); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: break; default: ret = -EINVAL; } spin_unlock_irqrestore(&aaci->lock, flags); return ret; } static int aaci_pcm_capture_prepare(snd_pcm_substream_t *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct aaci *aaci = substream->private_data; aaci_pcm_prepare(substream); /* allow changing of sample rate */ aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */ aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate); /* Record select: Mic: 0, Aux: 3, Line: 4 */ aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404); return 0; } static snd_pcm_ops_t aaci_capture_ops = { .open = aaci_pcm_open, .close = aaci_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = aaci_pcm_capture_hw_params, .hw_free = aaci_pcm_hw_free, .prepare = aaci_pcm_capture_prepare, .trigger = aaci_pcm_capture_trigger, .pointer = aaci_pcm_pointer, .mmap = aaci_pcm_mmap, }; /* * Power Management. Loading Loading @@ -741,6 +938,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); if (ret) goto out; aaci->ac97 = ac97; /* * Disable AC97 PC Beep input on audio codecs. Loading @@ -753,6 +951,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) goto out; aaci->playback.pcm = &ac97_bus->pcms[0]; aaci->capture.pcm = &ac97_bus->pcms[1]; out: return ret; Loading Loading @@ -802,7 +1001,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) struct snd_pcm *pcm; int ret; ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm); ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm); if (ret == 0) { aaci->pcm = pcm; pcm->private_data = aaci; Loading @@ -811,6 +1010,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); } return ret; Loading @@ -818,15 +1018,15 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) { void __iomem *base = aaci->base + AACI_CSCH1; struct aaci_runtime *aacirun = &aaci->playback; int i; writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR); writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR); for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++) writel(0, aaci->base + AACI_DR1); for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++) writel(0, aacirun->fifo); writel(0, base + AACI_TXCR); writel(0, aacirun->base + AACI_TXCR); /* * Re-initialise the AACI after the FIFO depth test, to Loading Loading @@ -873,6 +1073,12 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id) aaci->playback.base = aaci->base + AACI_CSCH1; aaci->playback.fifo = aaci->base + AACI_DR1; /* * Capture uses AACI channel 0 */ aaci->capture.base = aaci->base + AACI_CSCH1; aaci->capture.fifo = aaci->base + AACI_DR1; for (i = 0; i < 4; i++) { void __iomem *base = aaci->base + i * 0x14; Loading
sound/arm/aaci.h +21 −20 Original line number Diff line number Diff line Loading @@ -49,27 +49,27 @@ #define AACI_DR4 0x0f0 /* data read/written fifo 4 */ /* * transmit fifo control register. P48 */ #define TXCR_FEN (1 << 16) /* fifo enable */ #define TXCR_COMPACT (1 << 15) /* compact mode */ #define TXCR_TSZ16 (0 << 13) /* 16 bits */ #define TXCR_TSZ18 (1 << 13) /* 18 bits */ #define TXCR_TSZ20 (2 << 13) /* 20 bits */ #define TXCR_TSZ12 (3 << 13) /* 12 bits */ #define TXCR_TX12 (1 << 12) /* transmits slot 12 */ #define TXCR_TX11 (1 << 11) /* transmits slot 12 */ #define TXCR_TX10 (1 << 10) /* transmits slot 12 */ #define TXCR_TX9 (1 << 9) /* transmits slot 12 */ #define TXCR_TX8 (1 << 8) /* transmits slot 12 */ #define TXCR_TX7 (1 << 7) /* transmits slot 12 */ #define TXCR_TX6 (1 << 6) /* transmits slot 12 */ #define TXCR_TX5 (1 << 5) /* transmits slot 12 */ #define TXCR_TX4 (1 << 4) /* transmits slot 12 */ #define TXCR_TX3 (1 << 3) /* transmits slot 12 */ #define TXCR_TX2 (1 << 2) /* transmits slot 12 */ #define TXCR_TX1 (1 << 1) /* transmits slot 12 */ #define TXCR_TXEN (1 << 0) /* transmit enable */ * TX/RX fifo control register (CR). P48 */ #define CR_FEN (1 << 16) /* fifo enable */ #define CR_COMPACT (1 << 15) /* compact mode */ #define CR_SZ16 (0 << 13) /* 16 bits */ #define CR_SZ18 (1 << 13) /* 18 bits */ #define CR_SZ20 (2 << 13) /* 20 bits */ #define CR_SZ12 (3 << 13) /* 12 bits */ #define CR_SL12 (1 << 12) #define CR_SL11 (1 << 11) #define CR_SL10 (1 << 10) #define CR_SL9 (1 << 9) #define CR_SL8 (1 << 8) #define CR_SL7 (1 << 7) #define CR_SL6 (1 << 6) #define CR_SL5 (1 << 5) #define CR_SL4 (1 << 4) #define CR_SL3 (1 << 3) #define CR_SL2 (1 << 2) #define CR_SL1 (1 << 1) #define CR_EN (1 << 0) /* transmit enable */ /* * status register bits. P49 Loading Loading @@ -229,6 +229,7 @@ struct aaci { /* AC'97 */ struct mutex ac97_sem; ac97_bus_t *ac97_bus; ac97_t *ac97; u32 maincr; spinlock_t lock; Loading