diff options
Diffstat (limited to 'sound/arm/aaci.c')
-rw-r--r-- | sound/arm/aaci.c | 315 |
1 files changed, 275 insertions, 40 deletions
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 53675cf4de44..5190d7acdb9f 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c | |||
@@ -65,10 +65,12 @@ static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97) | |||
65 | * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR | 65 | * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR |
66 | * register. | 66 | * register. |
67 | */ | 67 | */ |
68 | static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) | 68 | static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, |
69 | unsigned short val) | ||
69 | { | 70 | { |
70 | struct aaci *aaci = ac97->private_data; | 71 | struct aaci *aaci = ac97->private_data; |
71 | u32 v; | 72 | u32 v; |
73 | int timeout = 5000; | ||
72 | 74 | ||
73 | if (ac97->num >= 4) | 75 | if (ac97->num >= 4) |
74 | return; | 76 | return; |
@@ -89,7 +91,11 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned | |||
89 | */ | 91 | */ |
90 | do { | 92 | do { |
91 | v = readl(aaci->base + AACI_SLFR); | 93 | v = readl(aaci->base + AACI_SLFR); |
92 | } while (v & (SLFR_1TXB|SLFR_2TXB)); | 94 | } while ((v & (SLFR_1TXB|SLFR_2TXB)) && timeout--); |
95 | |||
96 | if (!timeout) | ||
97 | dev_err(&aaci->dev->dev, | ||
98 | "timeout waiting for write to complete\n"); | ||
93 | 99 | ||
94 | mutex_unlock(&aaci->ac97_sem); | 100 | mutex_unlock(&aaci->ac97_sem); |
95 | } | 101 | } |
@@ -101,6 +107,8 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | |||
101 | { | 107 | { |
102 | struct aaci *aaci = ac97->private_data; | 108 | struct aaci *aaci = ac97->private_data; |
103 | u32 v; | 109 | u32 v; |
110 | int timeout = 5000; | ||
111 | int retries = 10; | ||
104 | 112 | ||
105 | if (ac97->num >= 4) | 113 | if (ac97->num >= 4) |
106 | return ~0; | 114 | return ~0; |
@@ -119,7 +127,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | |||
119 | */ | 127 | */ |
120 | do { | 128 | do { |
121 | v = readl(aaci->base + AACI_SLFR); | 129 | v = readl(aaci->base + AACI_SLFR); |
122 | } while (v & SLFR_1TXB); | 130 | } while ((v & SLFR_1TXB) && timeout--); |
131 | |||
132 | if (!timeout) { | ||
133 | dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n"); | ||
134 | v = ~0; | ||
135 | goto out; | ||
136 | } | ||
123 | 137 | ||
124 | /* | 138 | /* |
125 | * Give the AC'97 codec more than enough time | 139 | * Give the AC'97 codec more than enough time |
@@ -130,21 +144,35 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | |||
130 | /* | 144 | /* |
131 | * Wait for slot 2 to indicate data. | 145 | * Wait for slot 2 to indicate data. |
132 | */ | 146 | */ |
147 | timeout = 5000; | ||
133 | do { | 148 | do { |
134 | cond_resched(); | 149 | cond_resched(); |
135 | v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); | 150 | v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); |
136 | } while (v != (SLFR_1RXV|SLFR_2RXV)); | 151 | } while ((v != (SLFR_1RXV|SLFR_2RXV)) && timeout--); |
137 | 152 | ||
138 | v = readl(aaci->base + AACI_SL1RX) >> 12; | 153 | if (!timeout) { |
139 | if (v == reg) { | 154 | dev_err(&aaci->dev->dev, "timeout on RX valid\n"); |
140 | v = readl(aaci->base + AACI_SL2RX) >> 4; | ||
141 | } else { | ||
142 | dev_err(&aaci->dev->dev, | ||
143 | "wrong ac97 register read back (%x != %x)\n", | ||
144 | v, reg); | ||
145 | v = ~0; | 155 | v = ~0; |
156 | goto out; | ||
146 | } | 157 | } |
147 | 158 | ||
159 | do { | ||
160 | v = readl(aaci->base + AACI_SL1RX) >> 12; | ||
161 | if (v == reg) { | ||
162 | v = readl(aaci->base + AACI_SL2RX) >> 4; | ||
163 | break; | ||
164 | } else if (--retries) { | ||
165 | dev_warn(&aaci->dev->dev, | ||
166 | "ac97 read back fail. retry\n"); | ||
167 | continue; | ||
168 | } else { | ||
169 | dev_warn(&aaci->dev->dev, | ||
170 | "wrong ac97 register read back (%x != %x)\n", | ||
171 | v, reg); | ||
172 | v = ~0; | ||
173 | } | ||
174 | } while (retries); | ||
175 | out: | ||
148 | mutex_unlock(&aaci->ac97_sem); | 176 | mutex_unlock(&aaci->ac97_sem); |
149 | return v; | 177 | return v; |
150 | } | 178 | } |
@@ -164,10 +192,70 @@ static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) | |||
164 | /* | 192 | /* |
165 | * Interrupt support. | 193 | * Interrupt support. |
166 | */ | 194 | */ |
167 | static void aaci_fifo_irq(struct aaci *aaci, u32 mask) | 195 | static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) |
168 | { | 196 | { |
197 | if (mask & ISR_ORINTR) { | ||
198 | dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel); | ||
199 | writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR); | ||
200 | } | ||
201 | |||
202 | if (mask & ISR_RXTOINTR) { | ||
203 | dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel); | ||
204 | writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR); | ||
205 | } | ||
206 | |||
207 | if (mask & ISR_RXINTR) { | ||
208 | struct aaci_runtime *aacirun = &aaci->capture; | ||
209 | void *ptr; | ||
210 | |||
211 | if (!aacirun->substream || !aacirun->start) { | ||
212 | dev_warn(&aaci->dev->dev, "RX interrupt???"); | ||
213 | writel(0, aacirun->base + AACI_IE); | ||
214 | return; | ||
215 | } | ||
216 | ptr = aacirun->ptr; | ||
217 | |||
218 | do { | ||
219 | unsigned int len = aacirun->fifosz; | ||
220 | u32 val; | ||
221 | |||
222 | if (aacirun->bytes <= 0) { | ||
223 | aacirun->bytes += aacirun->period; | ||
224 | aacirun->ptr = ptr; | ||
225 | spin_unlock(&aaci->lock); | ||
226 | snd_pcm_period_elapsed(aacirun->substream); | ||
227 | spin_lock(&aaci->lock); | ||
228 | } | ||
229 | if (!(aacirun->cr & CR_EN)) | ||
230 | break; | ||
231 | |||
232 | val = readl(aacirun->base + AACI_SR); | ||
233 | if (!(val & SR_RXHF)) | ||
234 | break; | ||
235 | if (!(val & SR_RXFF)) | ||
236 | len >>= 1; | ||
237 | |||
238 | aacirun->bytes -= len; | ||
239 | |||
240 | /* reading 16 bytes at a time */ | ||
241 | for( ; len > 0; len -= 16) { | ||
242 | asm( | ||
243 | "ldmia %1, {r0, r1, r2, r3}\n\t" | ||
244 | "stmia %0!, {r0, r1, r2, r3}" | ||
245 | : "+r" (ptr) | ||
246 | : "r" (aacirun->fifo) | ||
247 | : "r0", "r1", "r2", "r3", "cc"); | ||
248 | |||
249 | if (ptr >= aacirun->end) | ||
250 | ptr = aacirun->start; | ||
251 | } | ||
252 | } while(1); | ||
253 | aacirun->ptr = ptr; | ||
254 | } | ||
255 | |||
169 | if (mask & ISR_URINTR) { | 256 | if (mask & ISR_URINTR) { |
170 | writel(ICLR_TXUEC1, aaci->base + AACI_INTCLR); | 257 | dev_dbg(&aaci->dev->dev, "TX underrun on chan %d\n", channel); |
258 | writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR); | ||
171 | } | 259 | } |
172 | 260 | ||
173 | if (mask & ISR_TXINTR) { | 261 | if (mask & ISR_TXINTR) { |
@@ -192,7 +280,7 @@ static void aaci_fifo_irq(struct aaci *aaci, u32 mask) | |||
192 | snd_pcm_period_elapsed(aacirun->substream); | 280 | snd_pcm_period_elapsed(aacirun->substream); |
193 | spin_lock(&aaci->lock); | 281 | spin_lock(&aaci->lock); |
194 | } | 282 | } |
195 | if (!(aacirun->cr & TXCR_TXEN)) | 283 | if (!(aacirun->cr & CR_EN)) |
196 | break; | 284 | break; |
197 | 285 | ||
198 | val = readl(aacirun->base + AACI_SR); | 286 | val = readl(aacirun->base + AACI_SR); |
@@ -233,7 +321,7 @@ static irqreturn_t aaci_irq(int irq, void *devid) | |||
233 | u32 m = mask; | 321 | u32 m = mask; |
234 | for (i = 0; i < 4; i++, m >>= 7) { | 322 | for (i = 0; i < 4; i++, m >>= 7) { |
235 | if (m & 0x7f) { | 323 | if (m & 0x7f) { |
236 | aaci_fifo_irq(aaci, m); | 324 | aaci_fifo_irq(aaci, i, m); |
237 | } | 325 | } |
238 | } | 326 | } |
239 | } | 327 | } |
@@ -330,8 +418,9 @@ static struct snd_pcm_hardware aaci_hw_info = { | |||
330 | .periods_max = PAGE_SIZE / 16, | 418 | .periods_max = PAGE_SIZE / 16, |
331 | }; | 419 | }; |
332 | 420 | ||
333 | static int aaci_pcm_open(struct aaci *aaci, struct snd_pcm_substream *substream, | 421 | static int __aaci_pcm_open(struct aaci *aaci, |
334 | struct aaci_runtime *aacirun) | 422 | struct snd_pcm_substream *substream, |
423 | struct aaci_runtime *aacirun) | ||
335 | { | 424 | { |
336 | struct snd_pcm_runtime *runtime = substream->runtime; | 425 | struct snd_pcm_runtime *runtime = substream->runtime; |
337 | int ret; | 426 | int ret; |
@@ -380,7 +469,7 @@ static int aaci_pcm_close(struct snd_pcm_substream *substream) | |||
380 | struct aaci *aaci = substream->private_data; | 469 | struct aaci *aaci = substream->private_data; |
381 | struct aaci_runtime *aacirun = substream->runtime->private_data; | 470 | struct aaci_runtime *aacirun = substream->runtime->private_data; |
382 | 471 | ||
383 | WARN_ON(aacirun->cr & TXCR_TXEN); | 472 | WARN_ON(aacirun->cr & CR_EN); |
384 | 473 | ||
385 | aacirun->substream = NULL; | 474 | aacirun->substream = NULL; |
386 | free_irq(aaci->dev->irq[0], aaci); | 475 | free_irq(aaci->dev->irq[0], aaci); |
@@ -395,7 +484,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream) | |||
395 | /* | 484 | /* |
396 | * This must not be called with the device enabled. | 485 | * This must not be called with the device enabled. |
397 | */ | 486 | */ |
398 | WARN_ON(aacirun->cr & TXCR_TXEN); | 487 | WARN_ON(aacirun->cr & CR_EN); |
399 | 488 | ||
400 | if (aacirun->pcm_open) | 489 | if (aacirun->pcm_open) |
401 | snd_ac97_pcm_close(aacirun->pcm); | 490 | snd_ac97_pcm_close(aacirun->pcm); |
@@ -422,9 +511,15 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, | |||
422 | if (err < 0) | 511 | if (err < 0) |
423 | goto out; | 512 | goto out; |
424 | 513 | ||
425 | err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), | 514 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
426 | params_channels(params), | 515 | err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), |
427 | aacirun->pcm->r[0].slots); | 516 | params_channels(params), |
517 | aacirun->pcm->r[0].slots); | ||
518 | else | ||
519 | err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), | ||
520 | params_channels(params), | ||
521 | aacirun->pcm->r[1].slots); | ||
522 | |||
428 | if (err) | 523 | if (err) |
429 | goto out; | 524 | goto out; |
430 | 525 | ||
@@ -467,9 +562,9 @@ static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_str | |||
467 | * Playback specific ALSA stuff | 562 | * Playback specific ALSA stuff |
468 | */ | 563 | */ |
469 | static const u32 channels_to_txmask[] = { | 564 | static const u32 channels_to_txmask[] = { |
470 | [2] = TXCR_TX3 | TXCR_TX4, | 565 | [2] = CR_SL3 | CR_SL4, |
471 | [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8, | 566 | [4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8, |
472 | [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9, | 567 | [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9, |
473 | }; | 568 | }; |
474 | 569 | ||
475 | /* | 570 | /* |
@@ -504,7 +599,7 @@ aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule) | |||
504 | chan_mask); | 599 | chan_mask); |
505 | } | 600 | } |
506 | 601 | ||
507 | static int aaci_pcm_playback_open(struct snd_pcm_substream *substream) | 602 | static int aaci_pcm_open(struct snd_pcm_substream *substream) |
508 | { | 603 | { |
509 | struct aaci *aaci = substream->private_data; | 604 | struct aaci *aaci = substream->private_data; |
510 | int ret; | 605 | int ret; |
@@ -519,7 +614,12 @@ static int aaci_pcm_playback_open(struct snd_pcm_substream *substream) | |||
519 | if (ret) | 614 | if (ret) |
520 | return ret; | 615 | return ret; |
521 | 616 | ||
522 | return aaci_pcm_open(aaci, substream, &aaci->playback); | 617 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
618 | ret = __aaci_pcm_open(aaci, substream, &aaci->playback); | ||
619 | } else { | ||
620 | ret = __aaci_pcm_open(aaci, substream, &aaci->capture); | ||
621 | } | ||
622 | return ret; | ||
523 | } | 623 | } |
524 | 624 | ||
525 | static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, | 625 | static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, |
@@ -540,11 +640,11 @@ static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, | |||
540 | * FIXME: double rate slots? | 640 | * FIXME: double rate slots? |
541 | */ | 641 | */ |
542 | if (ret >= 0) { | 642 | if (ret >= 0) { |
543 | aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16; | 643 | aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; |
544 | aacirun->cr |= channels_to_txmask[channels]; | 644 | aacirun->cr |= channels_to_txmask[channels]; |
545 | 645 | ||
546 | aacirun->fifosz = aaci->fifosize * 4; | 646 | aacirun->fifosz = aaci->fifosize * 4; |
547 | if (aacirun->cr & TXCR_COMPACT) | 647 | if (aacirun->cr & CR_COMPACT) |
548 | aacirun->fifosz >>= 1; | 648 | aacirun->fifosz >>= 1; |
549 | } | 649 | } |
550 | return ret; | 650 | return ret; |
@@ -557,7 +657,7 @@ static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) | |||
557 | ie = readl(aacirun->base + AACI_IE); | 657 | ie = readl(aacirun->base + AACI_IE); |
558 | ie &= ~(IE_URIE|IE_TXIE); | 658 | ie &= ~(IE_URIE|IE_TXIE); |
559 | writel(ie, aacirun->base + AACI_IE); | 659 | writel(ie, aacirun->base + AACI_IE); |
560 | aacirun->cr &= ~TXCR_TXEN; | 660 | aacirun->cr &= ~CR_EN; |
561 | aaci_chan_wait_ready(aacirun); | 661 | aaci_chan_wait_ready(aacirun); |
562 | writel(aacirun->cr, aacirun->base + AACI_TXCR); | 662 | writel(aacirun->cr, aacirun->base + AACI_TXCR); |
563 | } | 663 | } |
@@ -567,7 +667,7 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) | |||
567 | u32 ie; | 667 | u32 ie; |
568 | 668 | ||
569 | aaci_chan_wait_ready(aacirun); | 669 | aaci_chan_wait_ready(aacirun); |
570 | aacirun->cr |= TXCR_TXEN; | 670 | aacirun->cr |= CR_EN; |
571 | 671 | ||
572 | ie = readl(aacirun->base + AACI_IE); | 672 | ie = readl(aacirun->base + AACI_IE); |
573 | ie |= IE_URIE | IE_TXIE; | 673 | ie |= IE_URIE | IE_TXIE; |
@@ -615,7 +715,7 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm | |||
615 | } | 715 | } |
616 | 716 | ||
617 | static struct snd_pcm_ops aaci_playback_ops = { | 717 | static struct snd_pcm_ops aaci_playback_ops = { |
618 | .open = aaci_pcm_playback_open, | 718 | .open = aaci_pcm_open, |
619 | .close = aaci_pcm_close, | 719 | .close = aaci_pcm_close, |
620 | .ioctl = snd_pcm_lib_ioctl, | 720 | .ioctl = snd_pcm_lib_ioctl, |
621 | .hw_params = aaci_pcm_playback_hw_params, | 721 | .hw_params = aaci_pcm_playback_hw_params, |
@@ -626,7 +726,133 @@ static struct snd_pcm_ops aaci_playback_ops = { | |||
626 | .mmap = aaci_pcm_mmap, | 726 | .mmap = aaci_pcm_mmap, |
627 | }; | 727 | }; |
628 | 728 | ||
729 | static int aaci_pcm_capture_hw_params(snd_pcm_substream_t *substream, | ||
730 | snd_pcm_hw_params_t *params) | ||
731 | { | ||
732 | struct aaci *aaci = substream->private_data; | ||
733 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
734 | int ret; | ||
735 | |||
736 | ret = aaci_pcm_hw_params(substream, aacirun, params); | ||
737 | |||
738 | if (ret >= 0) { | ||
739 | aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; | ||
740 | |||
741 | /* Line in record: slot 3 and 4 */ | ||
742 | aacirun->cr |= CR_SL3 | CR_SL4; | ||
743 | |||
744 | aacirun->fifosz = aaci->fifosize * 4; | ||
745 | |||
746 | if (aacirun->cr & CR_COMPACT) | ||
747 | aacirun->fifosz >>= 1; | ||
748 | } | ||
749 | return ret; | ||
750 | } | ||
751 | |||
752 | static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun) | ||
753 | { | ||
754 | u32 ie; | ||
755 | |||
756 | aaci_chan_wait_ready(aacirun); | ||
757 | |||
758 | ie = readl(aacirun->base + AACI_IE); | ||
759 | ie &= ~(IE_ORIE | IE_RXIE); | ||
760 | writel(ie, aacirun->base+AACI_IE); | ||
761 | |||
762 | aacirun->cr &= ~CR_EN; | ||
763 | |||
764 | writel(aacirun->cr, aacirun->base + AACI_RXCR); | ||
765 | } | ||
766 | |||
767 | static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) | ||
768 | { | ||
769 | u32 ie; | ||
770 | |||
771 | aaci_chan_wait_ready(aacirun); | ||
772 | |||
773 | #ifdef DEBUG | ||
774 | /* RX Timeout value: bits 28:17 in RXCR */ | ||
775 | aacirun->cr |= 0xf << 17; | ||
776 | #endif | ||
777 | |||
778 | aacirun->cr |= CR_EN; | ||
779 | writel(aacirun->cr, aacirun->base + AACI_RXCR); | ||
780 | |||
781 | ie = readl(aacirun->base + AACI_IE); | ||
782 | ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full | ||
783 | writel(ie, aacirun->base + AACI_IE); | ||
784 | } | ||
785 | |||
786 | static int aaci_pcm_capture_trigger(snd_pcm_substream_t *substream, int cmd){ | ||
787 | |||
788 | struct aaci *aaci = substream->private_data; | ||
789 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
790 | unsigned long flags; | ||
791 | int ret = 0; | ||
792 | |||
793 | spin_lock_irqsave(&aaci->lock, flags); | ||
794 | |||
795 | switch (cmd) { | ||
796 | case SNDRV_PCM_TRIGGER_START: | ||
797 | aaci_pcm_capture_start(aacirun); | ||
798 | break; | ||
799 | |||
800 | case SNDRV_PCM_TRIGGER_RESUME: | ||
801 | aaci_pcm_capture_start(aacirun); | ||
802 | break; | ||
803 | |||
804 | case SNDRV_PCM_TRIGGER_STOP: | ||
805 | aaci_pcm_capture_stop(aacirun); | ||
806 | break; | ||
807 | |||
808 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
809 | aaci_pcm_capture_stop(aacirun); | ||
810 | break; | ||
811 | |||
812 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
813 | break; | ||
814 | |||
815 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
816 | break; | ||
817 | |||
818 | default: | ||
819 | ret = -EINVAL; | ||
820 | } | ||
821 | |||
822 | spin_unlock_irqrestore(&aaci->lock, flags); | ||
823 | |||
824 | return ret; | ||
825 | } | ||
629 | 826 | ||
827 | static int aaci_pcm_capture_prepare(snd_pcm_substream_t *substream) | ||
828 | { | ||
829 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
830 | struct aaci *aaci = substream->private_data; | ||
831 | |||
832 | aaci_pcm_prepare(substream); | ||
833 | |||
834 | /* allow changing of sample rate */ | ||
835 | aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */ | ||
836 | aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); | ||
837 | aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate); | ||
838 | |||
839 | /* Record select: Mic: 0, Aux: 3, Line: 4 */ | ||
840 | aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404); | ||
841 | |||
842 | return 0; | ||
843 | } | ||
844 | |||
845 | static snd_pcm_ops_t aaci_capture_ops = { | ||
846 | .open = aaci_pcm_open, | ||
847 | .close = aaci_pcm_close, | ||
848 | .ioctl = snd_pcm_lib_ioctl, | ||
849 | .hw_params = aaci_pcm_capture_hw_params, | ||
850 | .hw_free = aaci_pcm_hw_free, | ||
851 | .prepare = aaci_pcm_capture_prepare, | ||
852 | .trigger = aaci_pcm_capture_trigger, | ||
853 | .pointer = aaci_pcm_pointer, | ||
854 | .mmap = aaci_pcm_mmap, | ||
855 | }; | ||
630 | 856 | ||
631 | /* | 857 | /* |
632 | * Power Management. | 858 | * Power Management. |
@@ -666,7 +892,7 @@ static int aaci_resume(struct amba_device *dev) | |||
666 | 892 | ||
667 | 893 | ||
668 | static struct ac97_pcm ac97_defs[] __devinitdata = { | 894 | static struct ac97_pcm ac97_defs[] __devinitdata = { |
669 | [0] = { /* Front PCM */ | 895 | [0] = { /* Front PCM */ |
670 | .exclusive = 1, | 896 | .exclusive = 1, |
671 | .r = { | 897 | .r = { |
672 | [0] = { | 898 | [0] = { |
@@ -740,6 +966,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) | |||
740 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); | 966 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); |
741 | if (ret) | 967 | if (ret) |
742 | goto out; | 968 | goto out; |
969 | aaci->ac97 = ac97; | ||
743 | 970 | ||
744 | /* | 971 | /* |
745 | * Disable AC97 PC Beep input on audio codecs. | 972 | * Disable AC97 PC Beep input on audio codecs. |
@@ -752,6 +979,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci) | |||
752 | goto out; | 979 | goto out; |
753 | 980 | ||
754 | aaci->playback.pcm = &ac97_bus->pcms[0]; | 981 | aaci->playback.pcm = &ac97_bus->pcms[0]; |
982 | aaci->capture.pcm = &ac97_bus->pcms[1]; | ||
755 | 983 | ||
756 | out: | 984 | out: |
757 | return ret; | 985 | return ret; |
@@ -801,7 +1029,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) | |||
801 | struct snd_pcm *pcm; | 1029 | struct snd_pcm *pcm; |
802 | int ret; | 1030 | int ret; |
803 | 1031 | ||
804 | ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm); | 1032 | ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm); |
805 | if (ret == 0) { | 1033 | if (ret == 0) { |
806 | aaci->pcm = pcm; | 1034 | aaci->pcm = pcm; |
807 | pcm->private_data = aaci; | 1035 | pcm->private_data = aaci; |
@@ -810,6 +1038,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) | |||
810 | strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); | 1038 | strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); |
811 | 1039 | ||
812 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); | 1040 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); |
1041 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); | ||
813 | } | 1042 | } |
814 | 1043 | ||
815 | return ret; | 1044 | return ret; |
@@ -817,15 +1046,15 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) | |||
817 | 1046 | ||
818 | static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) | 1047 | static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) |
819 | { | 1048 | { |
820 | void __iomem *base = aaci->base + AACI_CSCH1; | 1049 | struct aaci_runtime *aacirun = &aaci->playback; |
821 | int i; | 1050 | int i; |
822 | 1051 | ||
823 | writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR); | 1052 | writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR); |
824 | 1053 | ||
825 | for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++) | 1054 | for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++) |
826 | writel(0, aaci->base + AACI_DR1); | 1055 | writel(0, aacirun->fifo); |
827 | 1056 | ||
828 | writel(0, base + AACI_TXCR); | 1057 | writel(0, aacirun->base + AACI_TXCR); |
829 | 1058 | ||
830 | /* | 1059 | /* |
831 | * Re-initialise the AACI after the FIFO depth test, to | 1060 | * Re-initialise the AACI after the FIFO depth test, to |
@@ -872,6 +1101,12 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id) | |||
872 | aaci->playback.base = aaci->base + AACI_CSCH1; | 1101 | aaci->playback.base = aaci->base + AACI_CSCH1; |
873 | aaci->playback.fifo = aaci->base + AACI_DR1; | 1102 | aaci->playback.fifo = aaci->base + AACI_DR1; |
874 | 1103 | ||
1104 | /* | ||
1105 | * Capture uses AACI channel 0 | ||
1106 | */ | ||
1107 | aaci->capture.base = aaci->base + AACI_CSCH1; | ||
1108 | aaci->capture.fifo = aaci->base + AACI_DR1; | ||
1109 | |||
875 | for (i = 0; i < 4; i++) { | 1110 | for (i = 0; i < 4; i++) { |
876 | void __iomem *base = aaci->base + i * 0x14; | 1111 | void __iomem *base = aaci->base + i * 0x14; |
877 | 1112 | ||
@@ -907,7 +1142,7 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id) | |||
907 | ret = snd_card_register(aaci->card); | 1142 | ret = snd_card_register(aaci->card); |
908 | if (ret == 0) { | 1143 | if (ret == 0) { |
909 | dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, | 1144 | dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, |
910 | aaci->fifosize); | 1145 | aaci->fifosize); |
911 | amba_set_drvdata(dev, aaci->card); | 1146 | amba_set_drvdata(dev, aaci->card); |
912 | return ret; | 1147 | return ret; |
913 | } | 1148 | } |