]> git.sur5r.net Git - freertos/blob - Demo/Common/drivers/Atmel/at91lib/peripherals/ac97c/ac97c.c
Atmel provided hardware specifics.
[freertos] / Demo / Common / drivers / Atmel / at91lib / peripherals / ac97c / ac97c.c
1 /* ----------------------------------------------------------------------------\r
2  *         ATMEL Microcontroller Software Support \r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2008, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 //------------------------------------------------------------------------------\r
31 //         Headers\r
32 //------------------------------------------------------------------------------\r
33 \r
34 #include "ac97c.h"\r
35 #include <board.h>\r
36 #include <aic/aic.h>\r
37 #include <utility/assert.h>\r
38 #include <utility/trace.h>\r
39 #include <utility/math.h>\r
40 \r
41 //------------------------------------------------------------------------------\r
42 //         Local constants\r
43 //------------------------------------------------------------------------------\r
44 \r
45 /// Maximum size of one PDC buffer (in bytes).\r
46 #define MAX_PDC_COUNTER 65535\r
47 \r
48 //------------------------------------------------------------------------------\r
49 //         Local types\r
50 //------------------------------------------------------------------------------\r
51 \r
52 //------------------------------------------------------------------------------\r
53 /// AC97 transfer descriptor. Tracks the status and parameters of a transfer\r
54 /// on the AC97 bus.\r
55 //------------------------------------------------------------------------------\r
56 typedef struct _Ac97Transfer {\r
57 \r
58         /// Buffer containing the slots to send.\r
59         unsigned char *pBuffer;\r
60         /// Total number of samples to send.\r
61         volatile unsigned int numSamples;\r
62         /// Optional callback function.\r
63         Ac97Callback callback;\r
64         /// Optional argument to the callback function.\r
65         void *pArg;\r
66 \r
67 } Ac97Transfer;\r
68 \r
69 //------------------------------------------------------------------------------\r
70 /// AC97 controller driver structure. Monitors the status of transfers on all\r
71 /// AC97 channels.\r
72 //------------------------------------------------------------------------------\r
73 typedef struct _Ac97c {\r
74 \r
75     /// List of transfers occuring on each channel.\r
76         Ac97Transfer transfers[5];\r
77 } Ac97c;\r
78 \r
79 //------------------------------------------------------------------------------\r
80 //         Local variables\r
81 //------------------------------------------------------------------------------\r
82 \r
83 /// Global AC97 controller instance.\r
84 static Ac97c ac97c;\r
85 \r
86 //------------------------------------------------------------------------------\r
87 //         Local functions\r
88 //------------------------------------------------------------------------------\r
89 \r
90 //------------------------------------------------------------------------------\r
91 /// Returns the size of one sample (in bytes) on the given channel.\r
92 /// \param channel  Channel number.\r
93 //------------------------------------------------------------------------------\r
94 static unsigned char GetSampleSize(unsigned char channel)\r
95 {\r
96     unsigned int size = 0;\r
97 \r
98     SANITY_CHECK((channel == AC97C_CHANNEL_A)\r
99                  || (channel == AC97C_CHANNEL_B)\r
100                  || (channel == AC97C_CHANNEL_CODEC));\r
101 \r
102     // Check selected channel\r
103     switch (channel) {\r
104         case AC97C_CHANNEL_CODEC: return 2;\r
105         case AC97C_CHANNEL_A: size = (AT91C_BASE_AC97C->AC97C_CAMR & AT91C_AC97C_SIZE) >> 16; break;\r
106         case AC97C_CHANNEL_B: size = (AT91C_BASE_AC97C->AC97C_CBMR & AT91C_AC97C_SIZE) >> 16; break;\r
107     }\r
108 \r
109     // Compute size in bytes given SIZE field\r
110     if ((size & 2) != 0) {\r
111 \r
112         return 2;\r
113     }\r
114     else {\r
115 \r
116         return 4;\r
117     }\r
118 }\r
119 \r
120 //------------------------------------------------------------------------------\r
121 /// Interrupt service routine for Codec, is invoked by AC97C_Handler.\r
122 //------------------------------------------------------------------------------\r
123 static void CodecHandler(void)\r
124 {\r
125     unsigned int status;\r
126     unsigned int data;\r
127     Ac97Transfer *pTransfer = &(ac97c.transfers[AC97C_CODEC_TRANSFER]);\r
128 \r
129     // Read CODEC status register\r
130     status = AT91C_BASE_AC97C->AC97C_COSR;\r
131     status &= AT91C_BASE_AC97C->AC97C_COMR;\r
132 \r
133     // A sample has been transmitted\r
134     if (status & AT91C_AC97C_TXRDY) {\r
135 \r
136         pTransfer->numSamples--;\r
137 \r
138         // If there are remaining samples, transmit one\r
139         if (pTransfer->numSamples > 0) {\r
140 \r
141             data = *((unsigned int *) pTransfer->pBuffer);\r
142             AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_TXRDY);\r
143             AT91C_BASE_AC97C->AC97C_COTHR = data;\r
144 \r
145             // Check if transfer is read or write\r
146             if ((data & AT91C_AC97C_READ) != 0) {\r
147     \r
148                 AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;\r
149             }\r
150             else {\r
151             \r
152                 pTransfer->pBuffer += sizeof(unsigned int);\r
153                 AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;\r
154             }\r
155         }\r
156         // Transfer finished\r
157         else {\r
158 \r
159             AT91C_BASE_AC97C->AC97C_IDR = AT91C_AC97C_COEVT;\r
160             AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_TXRDY);\r
161             if (pTransfer->callback) {\r
162 \r
163                 pTransfer->callback(pTransfer->pArg, 0, 0);\r
164             }\r
165         }   \r
166     }\r
167 \r
168     // A sample has been received\r
169     if (status & AT91C_AC97C_RXRDY) {\r
170 \r
171         // Store sample\r
172         data = AT91C_BASE_AC97C->AC97C_CORHR;\r
173         *((unsigned int *) pTransfer->pBuffer) = data;\r
174 \r
175         pTransfer->pBuffer += sizeof(unsigned int);\r
176         pTransfer->numSamples--;\r
177 \r
178         // Transfer finished\r
179         if (pTransfer->numSamples > 0) {\r
180 \r
181             data = *((unsigned int *) pTransfer->pBuffer);\r
182             AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_RXRDY);\r
183             AT91C_BASE_AC97C->AC97C_COTHR = data;\r
184 \r
185             // Check if transfer is read or write\r
186             if ((data & AT91C_AC97C_READ) != 0) {\r
187     \r
188                 AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;\r
189             }\r
190             else {\r
191             \r
192                 pTransfer->pBuffer += sizeof(unsigned int);\r
193                 AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;\r
194             }\r
195         }\r
196         else {\r
197 \r
198             AT91C_BASE_AC97C->AC97C_IDR = AT91C_AC97C_COEVT;\r
199             AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_RXRDY);\r
200             if (pTransfer->callback) {\r
201 \r
202                 pTransfer->callback(pTransfer->pArg, 0, 0);\r
203             }\r
204         }\r
205     }\r
206 }\r
207 \r
208 //------------------------------------------------------------------------------\r
209 /// Interrupt service routine for channel A, is invoked by AC97C_Handler.\r
210 //------------------------------------------------------------------------------\r
211 static void ChannelAHandler(void)\r
212 {\r
213     unsigned int status;\r
214     Ac97Transfer *pTransmit = &(ac97c.transfers[AC97C_CHANNEL_A_TRANSMIT]);\r
215     Ac97Transfer *pReceive = &(ac97c.transfers[AC97C_CHANNEL_A_RECEIVE]);\r
216 \r
217     // Read channel A status register\r
218     status = AT91C_BASE_AC97C->AC97C_CASR;\r
219 \r
220     // A buffer has been transmitted\r
221     if ((status & AT91C_AC97C_ENDTX) != 0) {\r
222 \r
223         // Update transfer information\r
224         if (pTransmit->numSamples > MAX_PDC_COUNTER) {\r
225 \r
226             pTransmit->numSamples -= MAX_PDC_COUNTER;\r
227         }\r
228         else {\r
229 \r
230             pTransmit->numSamples = 0;\r
231         }\r
232 \r
233         // Transmit new buffers if necessary\r
234         if (pTransmit->numSamples > MAX_PDC_COUNTER) {\r
235 \r
236             // Fill next PDC\r
237             AT91C_BASE_AC97C->AC97C_TNPR = (unsigned int) pTransmit->pBuffer;\r
238             if (pTransmit->numSamples > 2 * MAX_PDC_COUNTER) {\r
239 \r
240                 AT91C_BASE_AC97C->AC97C_TNCR = MAX_PDC_COUNTER;\r
241                 pTransmit->pBuffer += MAX_PDC_COUNTER * GetSampleSize(AC97C_CHANNEL_A);\r
242             }\r
243             else {\r
244 \r
245                 AT91C_BASE_AC97C->AC97C_TNCR = pTransmit->numSamples - MAX_PDC_COUNTER;\r
246             }\r
247         }\r
248         // Only one buffer remaining\r
249         else {\r
250 \r
251             AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_ENDTX;\r
252             AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_TXBUFE;\r
253         }\r
254     }\r
255 \r
256     // Transmit completed\r
257     if ((status & AT91C_AC97C_TXBUFE) != 0) {\r
258 \r
259         pTransmit->numSamples = 0;\r
260         AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;\r
261         AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_TXBUFE;\r
262         if (pTransmit->callback) {\r
263 \r
264             pTransmit->callback(pTransmit->pArg, 0, 0);\r
265         }\r
266     }\r
267 \r
268     // A buffer has been received\r
269     if (status & AT91C_AC97C_ENDRX) {\r
270 \r
271         if (pReceive->numSamples > MAX_PDC_COUNTER) {\r
272         \r
273             pReceive->numSamples -= MAX_PDC_COUNTER;\r
274         }\r
275         else {\r
276 \r
277             pReceive->numSamples = 0;\r
278         }\r
279 \r
280         // Transfer remaining samples\r
281         if (pReceive->numSamples > MAX_PDC_COUNTER) {\r
282 \r
283             AT91C_BASE_AC97C->AC97C_RNPR = (unsigned int) pReceive->pBuffer;\r
284             if (pReceive->numSamples > 2 * MAX_PDC_COUNTER) {\r
285             \r
286                 AT91C_BASE_AC97C->AC97C_RNCR = MAX_PDC_COUNTER;\r
287                 pReceive->pBuffer += MAX_PDC_COUNTER * GetSampleSize(AC97C_CHANNEL_A);\r
288             }\r
289             else {\r
290 \r
291                 AT91C_BASE_AC97C->AC97C_RNCR = pReceive->numSamples - MAX_PDC_COUNTER;\r
292             }\r
293         }\r
294         // Only one buffer remaining\r
295         else {\r
296 \r
297             AT91C_BASE_AC97C->AC97C_CAMR &= ~(AT91C_AC97C_ENDRX);\r
298             AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_RXBUFF;\r
299         }\r
300     }\r
301 \r
302     // Receive complete\r
303     if ((status & AT91C_AC97C_RXBUFF) != 0) {\r
304 \r
305         pReceive->numSamples = 0;\r
306         AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;\r
307         AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_RXBUFF;\r
308         if (pReceive->callback) {\r
309 \r
310             pReceive->callback(pReceive->pArg, 0, 0);\r
311         }\r
312     }\r
313 }\r
314 \r
315 //------------------------------------------------------------------------------\r
316 //         Exported functions\r
317 //------------------------------------------------------------------------------\r
318 //------------------------------------------------------------------------------\r
319 /// This handler function must be called by the AC97C interrupt service routine.\r
320 /// Identifies which event was activated and calls the associated function.\r
321 //------------------------------------------------------------------------------ \r
322 void AC97C_Handler(void)\r
323 {\r
324     unsigned int status;\r
325 \r
326     // Get the real interrupt source\r
327     status = AT91C_BASE_AC97C->AC97C_SR;\r
328     status &= AT91C_BASE_AC97C->AC97C_IMR;\r
329     \r
330     // Check if an event on the codec channel is active\r
331     if ((status & AT91C_AC97C_COEVT) != 0) {\r
332 \r
333         CodecHandler();    \r
334     }\r
335     // Check if an event on channel A is active\r
336     if ((status & AT91C_AC97C_CAEVT) != 0) {\r
337 \r
338         ChannelAHandler();  \r
339     }\r
340 }\r
341 \r
342 //------------------------------------------------------------------------------\r
343 /// Starts a read or write transfer on the given channel\r
344 /// \param channel particular channel (AC97C_CHANNEL_A or AC97C_CHANNEL_B).\r
345 /// \param pBuffer buffer containing the slots to send.\r
346 /// \param numSamples total number of samples to send.  \r
347 /// \param callback optional callback function.\r
348 /// \param pArg optional argument to the callback function.\r
349 //------------------------------------------------------------------------------\r
350 unsigned char AC97C_Transfer(\r
351     unsigned char channel,\r
352     unsigned char *pBuffer,\r
353     unsigned int numSamples,\r
354     Ac97Callback callback,\r
355     void *pArg)\r
356 {\r
357     unsigned int size;\r
358     unsigned int data;\r
359     Ac97Transfer *pTransfer;\r
360 \r
361     SANITY_CHECK(channel <= 5);\r
362     SANITY_CHECK(pBuffer);\r
363     SANITY_CHECK(numSamples > 0);\r
364 \r
365     // Check that no transfer is pending on the channel\r
366     pTransfer = &(ac97c.transfers[channel]);\r
367     if (pTransfer->numSamples > 0) {\r
368 \r
369         trace_LOG(trace_WARNING, "-W- AC97C_Transfer: Channel %d is busy\n\r", channel);\r
370         return AC97C_ERROR_BUSY;\r
371     }\r
372 \r
373     // Fill transfer information\r
374     pTransfer->pBuffer = pBuffer;\r
375     pTransfer->numSamples = numSamples;\r
376     pTransfer->callback = callback;\r
377     pTransfer->pArg = pArg;\r
378 \r
379     // Transmit or receive over codec channel\r
380     if (channel == AC97C_CODEC_TRANSFER) {\r
381 \r
382         // Send command\r
383         data = *((unsigned int *) pTransfer->pBuffer); \r
384         AT91C_BASE_AC97C->AC97C_COTHR = data;\r
385 \r
386         // Check if transfer is read or write\r
387         if ((data & AT91C_AC97C_READ) != 0) {\r
388 \r
389             AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;\r
390         }\r
391         else {\r
392         \r
393             pTransfer->pBuffer += sizeof(unsigned int);\r
394             AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;\r
395         }\r
396 \r
397         // Enable interrupts\r
398         AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_COEVT;\r
399     }\r
400     // Transmit over channel A\r
401     else if (channel == AC97C_CHANNEL_A_TRANSMIT) {\r
402 \r
403         // Disable PDC\r
404         AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;\r
405 \r
406         // Fill PDC buffers\r
407         size = min(pTransfer->numSamples, MAX_PDC_COUNTER);\r
408         AT91C_BASE_AC97C->AC97C_TPR = (unsigned int) pTransfer->pBuffer;\r
409         AT91C_BASE_AC97C->AC97C_TCR = size;\r
410         pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);\r
411 \r
412         size = min(pTransfer->numSamples - size, MAX_PDC_COUNTER);\r
413         if (size > 0) {\r
414 \r
415             AT91C_BASE_AC97C->AC97C_TNPR = (unsigned int) pTransfer->pBuffer;\r
416             AT91C_BASE_AC97C->AC97C_TNCR = size;\r
417             pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);\r
418         }\r
419 \r
420         // Enable interrupts\r
421         AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_PDCEN | AT91C_AC97C_ENDTX;\r
422         AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_CAEVT;\r
423 \r
424         // Start transfer\r
425         AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTEN;\r
426     }\r
427     // Receive over channel A\r
428     else if (channel == AC97C_CHANNEL_A_RECEIVE) {\r
429 \r
430         // Disable PDC\r
431         AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;\r
432 \r
433         // Fill PDC buffers\r
434         size = min(pTransfer->numSamples, MAX_PDC_COUNTER);\r
435         AT91C_BASE_AC97C->AC97C_RPR = (unsigned int) pTransfer->pBuffer;\r
436         AT91C_BASE_AC97C->AC97C_RCR = size;\r
437         pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);\r
438 \r
439         size = min(pTransfer->numSamples - size, MAX_PDC_COUNTER);\r
440         if (size > 0) {\r
441 \r
442             AT91C_BASE_AC97C->AC97C_RNPR = (unsigned int) pTransfer->pBuffer;\r
443             AT91C_BASE_AC97C->AC97C_RNCR = size;\r
444             pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);\r
445         }\r
446 \r
447         // Enable interrupts\r
448         AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_PDCEN | AT91C_AC97C_ENDRX;\r
449         AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_CAEVT;\r
450 \r
451         // Start transfer\r
452         AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTEN;\r
453     }\r
454 \r
455     return 0;\r
456 }\r
457 \r
458 //------------------------------------------------------------------------------\r
459 /// Stop read or write transfer on the given channel.\r
460 /// \param channel  Channel number.\r
461 //------------------------------------------------------------------------------\r
462 void AC97C_CancelTransfer(unsigned char channel)\r
463 {    \r
464     unsigned int size = 0;\r
465     Ac97Transfer *pTransfer;\r
466 \r
467     SANITY_CHECK(channel <= AC97C_CHANNEL_B_TRANSMIT);\r
468 \r
469     // Save remaining size\r
470     pTransfer = &(ac97c.transfers[channel]);\r
471     size = pTransfer->numSamples;\r
472     pTransfer->numSamples = 0;\r
473 \r
474     // Stop PDC\r
475     if (channel == AC97C_CHANNEL_A_TRANSMIT) {\r
476 \r
477         AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;\r
478         size -= min(size, MAX_PDC_COUNTER) - AT91C_BASE_AC97C->AC97C_TCR;\r
479     }\r
480     if (channel == AC97C_CHANNEL_A_RECEIVE) {\r
481 \r
482         AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;\r
483         size -= min(size, MAX_PDC_COUNTER) - AT91C_BASE_AC97C->AC97C_RCR;\r
484     }\r
485 \r
486     // Invoke callback if provided\r
487     if (pTransfer->callback) {\r
488 \r
489         pTransfer->callback(pTransfer->pArg, AC97C_ERROR_STOPPED, size);\r
490     }\r
491 }\r
492 \r
493 //------------------------------------------------------------------------------\r
494 /// Initializes the AC97 controller.\r
495 //------------------------------------------------------------------------------\r
496 void AC97C_Configure(void)\r
497 {\r
498     unsigned char channel;\r
499 \r
500     // Enable the AC97 controller peripheral clock\r
501     AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_AC97C);   \r
502     \r
503     // Enable the peripheral and variable rate adjustment\r
504     AT91C_BASE_AC97C->AC97C_MR = AT91C_AC97C_ENA  | AT91C_AC97C_VRA;\r
505 \r
506     // Unassigns all input & output slots\r
507     AC97C_AssignInputSlots(0, 0xFFFF);\r
508     AC97C_AssignOutputSlots(0, 0xFFFF);\r
509 \r
510     // Install the AC97C interrupt handler\r
511     AT91C_BASE_AC97C->AC97C_IDR = 0xFFFFFFFF;\r
512     AIC_ConfigureIT(AT91C_ID_AC97C, 0, AC97C_Handler);\r
513     AIC_EnableIT(AT91C_ID_AC97C);  \r
514 \r
515     // Disable PDC transfers\r
516     AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;\r
517 \r
518     // Clear channel transfers\r
519     for (channel = 0; channel < AC97C_CHANNEL_B_TRANSMIT; channel++) {\r
520 \r
521         ac97c.transfers[channel].numSamples = 0;\r
522     }\r
523 }\r
524 \r
525 //------------------------------------------------------------------------------\r
526 /// Configures the desired channel with the given value.\r
527 /// \param channel  Channel number.\r
528 /// \param cfg  Configuration value.\r
529 //------------------------------------------------------------------------------\r
530 void AC97C_ConfigureChannel(unsigned char channel, unsigned int cfg)\r
531 {\r
532     SANITY_CHECK((channel == AC97C_CHANNEL_A) || (channel == AC97C_CHANNEL_B));\r
533 \r
534     if (channel == AC97C_CHANNEL_A) {\r
535 \r
536         AT91C_BASE_AC97C->AC97C_CAMR = cfg;\r
537     }\r
538     else {\r
539 \r
540         AT91C_BASE_AC97C->AC97C_CBMR = cfg;\r
541     }\r
542 }\r
543 \r
544 //------------------------------------------------------------------------------\r
545 /// Assigns the desired input slots to a particular channel.\r
546 /// \param channel  Channel number (or 0 to unassign slots).\r
547 /// \param slots  Bitfield value of slots to assign.\r
548 //------------------------------------------------------------------------------\r
549 void AC97C_AssignInputSlots(unsigned char channel, unsigned int slots)\r
550 {\r
551     unsigned int value;\r
552     unsigned int i;\r
553 \r
554     SANITY_CHECK(channel <= AC97C_CHANNEL_B);\r
555 \r
556     // Assign all slots\r
557     slots >>= 3;\r
558     for (i = 3; i < 15; i++) {\r
559 \r
560         // Check if slots is selected\r
561         if (slots & 1) {\r
562 \r
563             value = AT91C_BASE_AC97C->AC97C_ICA;\r
564             value &= ~(0x07 << ((i - 3) * 3));\r
565             value |= channel << ((i - 3) * 3);\r
566             AT91C_BASE_AC97C->AC97C_ICA = value;\r
567         }\r
568         slots >>= 1;\r
569     }\r
570 }\r
571 \r
572 //------------------------------------------------------------------------------\r
573 /// Assigns the desired output slots to a particular channel.\r
574 /// \param channel  Channel number (or 0 to unassign slots).\r
575 /// \param slots  Bitfield value of slots to assign.\r
576 //------------------------------------------------------------------------------\r
577 void AC97C_AssignOutputSlots(unsigned char channel, unsigned int slots)\r
578 {\r
579     unsigned int value;\r
580     unsigned int i;\r
581 \r
582     SANITY_CHECK(channel <= AC97C_CHANNEL_B);\r
583 \r
584     // Assign all slots\r
585     slots >>= 3;\r
586     for (i = 3; i < 15; i++) {\r
587 \r
588         // Check if slots is selected\r
589         if (slots & 1) {\r
590 \r
591             value = AT91C_BASE_AC97C->AC97C_OCA;\r
592             value &= ~(0x07 << ((i - 3) * 3));\r
593             value |= channel << ((i - 3) * 3);\r
594             AT91C_BASE_AC97C->AC97C_OCA = value;\r
595         }\r
596         slots >>= 1;\r
597     }\r
598 }\r
599 \r
600 //------------------------------------------------------------------------------\r
601 /// Returns 1 if no transfer is currently pending on the given channel;\r
602 /// otherwise, returns 0.\r
603 /// \param channel  Channel number.\r
604 //------------------------------------------------------------------------------\r
605 unsigned char AC97C_IsFinished(unsigned char channel)\r
606 {\r
607     SANITY_CHECK(channel <= AC97C_CHANNEL_B_TRANSMIT);\r
608 \r
609         if (ac97c.transfers[channel].numSamples > 0) {\r
610 \r
611                 return 0;\r
612         }\r
613         else {\r
614 \r
615                 return 1;\r
616         }\r
617 }\r
618 \r
619 //------------------------------------------------------------------------------\r
620 /// Convenience function for synchronously sending commands to the codec.\r
621 /// \param address  Register address.\r
622 /// \param data  Command data.\r
623 //------------------------------------------------------------------------------\r
624 void AC97C_WriteCodec(unsigned char address, unsigned short data)\r
625 {\r
626     unsigned int sample;\r
627 \r
628     sample = (address << 16) | data;\r
629     AC97C_Transfer(AC97C_CODEC_TRANSFER, (unsigned char *) &sample, 1, 0, 0);\r
630     while (!AC97C_IsFinished(AC97C_CODEC_TRANSFER));\r
631 }\r
632 \r
633 //------------------------------------------------------------------------------\r
634 /// Convenience function for receiving data from the AC97 codec.\r
635 /// \param address  Register address.\r
636 //------------------------------------------------------------------------------\r
637 unsigned short AC97C_ReadCodec(unsigned char address)\r
638 {\r
639     unsigned int sample;\r
640 \r
641     sample = AT91C_AC97C_READ | (address << 16);\r
642     AC97C_Transfer(AC97C_CODEC_TRANSFER, (unsigned char *) &sample, 1, 0, 0);\r
643         while (!AC97C_IsFinished(AC97C_CODEC_TRANSFER));\r
644 \r
645     return sample;\r
646 }\r
647             \r
648 //------------------------------------------------------------------------------\r
649 /// Sets the size in bits of one sample on the given channel.\r
650 /// \param channel  Channel number.\r
651 /// \param size  Size of one sample in bits (10, 16, 18 or 24).\r
652 //------------------------------------------------------------------------------        \r
653 void AC97C_SetChannelSize(unsigned char channel, unsigned char size)\r
654 {\r
655     unsigned int bits = 0;\r
656 \r
657     SANITY_CHECK((size == 10) || (size == 16) || (size == 18) || (size == 24));\r
658     SANITY_CHECK((channel == AC97C_CHANNEL_A) || (channel == AC97C_CHANNEL_B));\r
659 \r
660     switch (size) {\r
661 \r
662         case 10 : bits = AT91C_AC97C_SIZE_10_BITS; break;\r
663         case 16 : bits = AT91C_AC97C_SIZE_16_BITS; break;\r
664         case 18 : bits = AT91C_AC97C_SIZE_18_BITS; break;\r
665         case 20 : bits = AT91C_AC97C_SIZE_20_BITS; break;\r
666     }\r
667 \r
668     if (channel == AC97C_CHANNEL_A) {\r
669 \r
670         AT91C_BASE_AC97C->AC97C_CAMR &= ~(AT91C_AC97C_SIZE);\r
671         AT91C_BASE_AC97C->AC97C_CAMR |= bits;\r
672     }\r
673     else {\r
674 \r
675         AT91C_BASE_AC97C->AC97C_CBMR &= ~(AT91C_AC97C_SIZE);\r
676         AT91C_BASE_AC97C->AC97C_CBMR |= bits;\r
677     }\r
678 }\r
679 \r