mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-08-19 09:38:32 -04:00
Atmel provided hardware specifics.
This commit is contained in:
parent
5e6d50864c
commit
efc8243397
73 changed files with 24720 additions and 0 deletions
679
Demo/Common/drivers/Atmel/at91lib/peripherals/ac97c/ac97c.c
Normal file
679
Demo/Common/drivers/Atmel/at91lib/peripherals/ac97c/ac97c.c
Normal file
|
@ -0,0 +1,679 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "ac97c.h"
|
||||
#include <board.h>
|
||||
#include <aic/aic.h>
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
#include <utility/math.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Maximum size of one PDC buffer (in bytes).
|
||||
#define MAX_PDC_COUNTER 65535
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// AC97 transfer descriptor. Tracks the status and parameters of a transfer
|
||||
/// on the AC97 bus.
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct _Ac97Transfer {
|
||||
|
||||
/// Buffer containing the slots to send.
|
||||
unsigned char *pBuffer;
|
||||
/// Total number of samples to send.
|
||||
volatile unsigned int numSamples;
|
||||
/// Optional callback function.
|
||||
Ac97Callback callback;
|
||||
/// Optional argument to the callback function.
|
||||
void *pArg;
|
||||
|
||||
} Ac97Transfer;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// AC97 controller driver structure. Monitors the status of transfers on all
|
||||
/// AC97 channels.
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct _Ac97c {
|
||||
|
||||
/// List of transfers occuring on each channel.
|
||||
Ac97Transfer transfers[5];
|
||||
} Ac97c;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Global AC97 controller instance.
|
||||
static Ac97c ac97c;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the size of one sample (in bytes) on the given channel.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char GetSampleSize(unsigned char channel)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
|
||||
SANITY_CHECK((channel == AC97C_CHANNEL_A)
|
||||
|| (channel == AC97C_CHANNEL_B)
|
||||
|| (channel == AC97C_CHANNEL_CODEC));
|
||||
|
||||
// Check selected channel
|
||||
switch (channel) {
|
||||
case AC97C_CHANNEL_CODEC: return 2;
|
||||
case AC97C_CHANNEL_A: size = (AT91C_BASE_AC97C->AC97C_CAMR & AT91C_AC97C_SIZE) >> 16; break;
|
||||
case AC97C_CHANNEL_B: size = (AT91C_BASE_AC97C->AC97C_CBMR & AT91C_AC97C_SIZE) >> 16; break;
|
||||
}
|
||||
|
||||
// Compute size in bytes given SIZE field
|
||||
if ((size & 2) != 0) {
|
||||
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Interrupt service routine for Codec, is invoked by AC97C_Handler.
|
||||
//------------------------------------------------------------------------------
|
||||
static void CodecHandler(void)
|
||||
{
|
||||
unsigned int status;
|
||||
unsigned int data;
|
||||
Ac97Transfer *pTransfer = &(ac97c.transfers[AC97C_CODEC_TRANSFER]);
|
||||
|
||||
// Read CODEC status register
|
||||
status = AT91C_BASE_AC97C->AC97C_COSR;
|
||||
status &= AT91C_BASE_AC97C->AC97C_COMR;
|
||||
|
||||
// A sample has been transmitted
|
||||
if (status & AT91C_AC97C_TXRDY) {
|
||||
|
||||
pTransfer->numSamples--;
|
||||
|
||||
// If there are remaining samples, transmit one
|
||||
if (pTransfer->numSamples > 0) {
|
||||
|
||||
data = *((unsigned int *) pTransfer->pBuffer);
|
||||
AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_TXRDY);
|
||||
AT91C_BASE_AC97C->AC97C_COTHR = data;
|
||||
|
||||
// Check if transfer is read or write
|
||||
if ((data & AT91C_AC97C_READ) != 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
|
||||
}
|
||||
else {
|
||||
|
||||
pTransfer->pBuffer += sizeof(unsigned int);
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
|
||||
}
|
||||
}
|
||||
// Transfer finished
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_IDR = AT91C_AC97C_COEVT;
|
||||
AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_TXRDY);
|
||||
if (pTransfer->callback) {
|
||||
|
||||
pTransfer->callback(pTransfer->pArg, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A sample has been received
|
||||
if (status & AT91C_AC97C_RXRDY) {
|
||||
|
||||
// Store sample
|
||||
data = AT91C_BASE_AC97C->AC97C_CORHR;
|
||||
*((unsigned int *) pTransfer->pBuffer) = data;
|
||||
|
||||
pTransfer->pBuffer += sizeof(unsigned int);
|
||||
pTransfer->numSamples--;
|
||||
|
||||
// Transfer finished
|
||||
if (pTransfer->numSamples > 0) {
|
||||
|
||||
data = *((unsigned int *) pTransfer->pBuffer);
|
||||
AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_RXRDY);
|
||||
AT91C_BASE_AC97C->AC97C_COTHR = data;
|
||||
|
||||
// Check if transfer is read or write
|
||||
if ((data & AT91C_AC97C_READ) != 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
|
||||
}
|
||||
else {
|
||||
|
||||
pTransfer->pBuffer += sizeof(unsigned int);
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_IDR = AT91C_AC97C_COEVT;
|
||||
AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_RXRDY);
|
||||
if (pTransfer->callback) {
|
||||
|
||||
pTransfer->callback(pTransfer->pArg, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Interrupt service routine for channel A, is invoked by AC97C_Handler.
|
||||
//------------------------------------------------------------------------------
|
||||
static void ChannelAHandler(void)
|
||||
{
|
||||
unsigned int status;
|
||||
Ac97Transfer *pTransmit = &(ac97c.transfers[AC97C_CHANNEL_A_TRANSMIT]);
|
||||
Ac97Transfer *pReceive = &(ac97c.transfers[AC97C_CHANNEL_A_RECEIVE]);
|
||||
|
||||
// Read channel A status register
|
||||
status = AT91C_BASE_AC97C->AC97C_CASR;
|
||||
|
||||
// A buffer has been transmitted
|
||||
if ((status & AT91C_AC97C_ENDTX) != 0) {
|
||||
|
||||
// Update transfer information
|
||||
if (pTransmit->numSamples > MAX_PDC_COUNTER) {
|
||||
|
||||
pTransmit->numSamples -= MAX_PDC_COUNTER;
|
||||
}
|
||||
else {
|
||||
|
||||
pTransmit->numSamples = 0;
|
||||
}
|
||||
|
||||
// Transmit new buffers if necessary
|
||||
if (pTransmit->numSamples > MAX_PDC_COUNTER) {
|
||||
|
||||
// Fill next PDC
|
||||
AT91C_BASE_AC97C->AC97C_TNPR = (unsigned int) pTransmit->pBuffer;
|
||||
if (pTransmit->numSamples > 2 * MAX_PDC_COUNTER) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_TNCR = MAX_PDC_COUNTER;
|
||||
pTransmit->pBuffer += MAX_PDC_COUNTER * GetSampleSize(AC97C_CHANNEL_A);
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_TNCR = pTransmit->numSamples - MAX_PDC_COUNTER;
|
||||
}
|
||||
}
|
||||
// Only one buffer remaining
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_ENDTX;
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_TXBUFE;
|
||||
}
|
||||
}
|
||||
|
||||
// Transmit completed
|
||||
if ((status & AT91C_AC97C_TXBUFE) != 0) {
|
||||
|
||||
pTransmit->numSamples = 0;
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_TXBUFE;
|
||||
if (pTransmit->callback) {
|
||||
|
||||
pTransmit->callback(pTransmit->pArg, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// A buffer has been received
|
||||
if (status & AT91C_AC97C_ENDRX) {
|
||||
|
||||
if (pReceive->numSamples > MAX_PDC_COUNTER) {
|
||||
|
||||
pReceive->numSamples -= MAX_PDC_COUNTER;
|
||||
}
|
||||
else {
|
||||
|
||||
pReceive->numSamples = 0;
|
||||
}
|
||||
|
||||
// Transfer remaining samples
|
||||
if (pReceive->numSamples > MAX_PDC_COUNTER) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_RNPR = (unsigned int) pReceive->pBuffer;
|
||||
if (pReceive->numSamples > 2 * MAX_PDC_COUNTER) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_RNCR = MAX_PDC_COUNTER;
|
||||
pReceive->pBuffer += MAX_PDC_COUNTER * GetSampleSize(AC97C_CHANNEL_A);
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_RNCR = pReceive->numSamples - MAX_PDC_COUNTER;
|
||||
}
|
||||
}
|
||||
// Only one buffer remaining
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~(AT91C_AC97C_ENDRX);
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_RXBUFF;
|
||||
}
|
||||
}
|
||||
|
||||
// Receive complete
|
||||
if ((status & AT91C_AC97C_RXBUFF) != 0) {
|
||||
|
||||
pReceive->numSamples = 0;
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_RXBUFF;
|
||||
if (pReceive->callback) {
|
||||
|
||||
pReceive->callback(pReceive->pArg, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// This handler function must be called by the AC97C interrupt service routine.
|
||||
/// Identifies which event was activated and calls the associated function.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_Handler(void)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
// Get the real interrupt source
|
||||
status = AT91C_BASE_AC97C->AC97C_SR;
|
||||
status &= AT91C_BASE_AC97C->AC97C_IMR;
|
||||
|
||||
// Check if an event on the codec channel is active
|
||||
if ((status & AT91C_AC97C_COEVT) != 0) {
|
||||
|
||||
CodecHandler();
|
||||
}
|
||||
// Check if an event on channel A is active
|
||||
if ((status & AT91C_AC97C_CAEVT) != 0) {
|
||||
|
||||
ChannelAHandler();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts a read or write transfer on the given channel
|
||||
/// \param channel particular channel (AC97C_CHANNEL_A or AC97C_CHANNEL_B).
|
||||
/// \param pBuffer buffer containing the slots to send.
|
||||
/// \param numSamples total number of samples to send.
|
||||
/// \param callback optional callback function.
|
||||
/// \param pArg optional argument to the callback function.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char AC97C_Transfer(
|
||||
unsigned char channel,
|
||||
unsigned char *pBuffer,
|
||||
unsigned int numSamples,
|
||||
Ac97Callback callback,
|
||||
void *pArg)
|
||||
{
|
||||
unsigned int size;
|
||||
unsigned int data;
|
||||
Ac97Transfer *pTransfer;
|
||||
|
||||
SANITY_CHECK(channel <= 5);
|
||||
SANITY_CHECK(pBuffer);
|
||||
SANITY_CHECK(numSamples > 0);
|
||||
|
||||
// Check that no transfer is pending on the channel
|
||||
pTransfer = &(ac97c.transfers[channel]);
|
||||
if (pTransfer->numSamples > 0) {
|
||||
|
||||
trace_LOG(trace_WARNING, "-W- AC97C_Transfer: Channel %d is busy\n\r", channel);
|
||||
return AC97C_ERROR_BUSY;
|
||||
}
|
||||
|
||||
// Fill transfer information
|
||||
pTransfer->pBuffer = pBuffer;
|
||||
pTransfer->numSamples = numSamples;
|
||||
pTransfer->callback = callback;
|
||||
pTransfer->pArg = pArg;
|
||||
|
||||
// Transmit or receive over codec channel
|
||||
if (channel == AC97C_CODEC_TRANSFER) {
|
||||
|
||||
// Send command
|
||||
data = *((unsigned int *) pTransfer->pBuffer);
|
||||
AT91C_BASE_AC97C->AC97C_COTHR = data;
|
||||
|
||||
// Check if transfer is read or write
|
||||
if ((data & AT91C_AC97C_READ) != 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
|
||||
}
|
||||
else {
|
||||
|
||||
pTransfer->pBuffer += sizeof(unsigned int);
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
|
||||
}
|
||||
|
||||
// Enable interrupts
|
||||
AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_COEVT;
|
||||
}
|
||||
// Transmit over channel A
|
||||
else if (channel == AC97C_CHANNEL_A_TRANSMIT) {
|
||||
|
||||
// Disable PDC
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
|
||||
|
||||
// Fill PDC buffers
|
||||
size = min(pTransfer->numSamples, MAX_PDC_COUNTER);
|
||||
AT91C_BASE_AC97C->AC97C_TPR = (unsigned int) pTransfer->pBuffer;
|
||||
AT91C_BASE_AC97C->AC97C_TCR = size;
|
||||
pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
|
||||
|
||||
size = min(pTransfer->numSamples - size, MAX_PDC_COUNTER);
|
||||
if (size > 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_TNPR = (unsigned int) pTransfer->pBuffer;
|
||||
AT91C_BASE_AC97C->AC97C_TNCR = size;
|
||||
pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
|
||||
}
|
||||
|
||||
// Enable interrupts
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_PDCEN | AT91C_AC97C_ENDTX;
|
||||
AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_CAEVT;
|
||||
|
||||
// Start transfer
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTEN;
|
||||
}
|
||||
// Receive over channel A
|
||||
else if (channel == AC97C_CHANNEL_A_RECEIVE) {
|
||||
|
||||
// Disable PDC
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
|
||||
|
||||
// Fill PDC buffers
|
||||
size = min(pTransfer->numSamples, MAX_PDC_COUNTER);
|
||||
AT91C_BASE_AC97C->AC97C_RPR = (unsigned int) pTransfer->pBuffer;
|
||||
AT91C_BASE_AC97C->AC97C_RCR = size;
|
||||
pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
|
||||
|
||||
size = min(pTransfer->numSamples - size, MAX_PDC_COUNTER);
|
||||
if (size > 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_RNPR = (unsigned int) pTransfer->pBuffer;
|
||||
AT91C_BASE_AC97C->AC97C_RNCR = size;
|
||||
pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
|
||||
}
|
||||
|
||||
// Enable interrupts
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_PDCEN | AT91C_AC97C_ENDRX;
|
||||
AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_CAEVT;
|
||||
|
||||
// Start transfer
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Stop read or write transfer on the given channel.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_CancelTransfer(unsigned char channel)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
Ac97Transfer *pTransfer;
|
||||
|
||||
SANITY_CHECK(channel <= AC97C_CHANNEL_B_TRANSMIT);
|
||||
|
||||
// Save remaining size
|
||||
pTransfer = &(ac97c.transfers[channel]);
|
||||
size = pTransfer->numSamples;
|
||||
pTransfer->numSamples = 0;
|
||||
|
||||
// Stop PDC
|
||||
if (channel == AC97C_CHANNEL_A_TRANSMIT) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
|
||||
size -= min(size, MAX_PDC_COUNTER) - AT91C_BASE_AC97C->AC97C_TCR;
|
||||
}
|
||||
if (channel == AC97C_CHANNEL_A_RECEIVE) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
|
||||
size -= min(size, MAX_PDC_COUNTER) - AT91C_BASE_AC97C->AC97C_RCR;
|
||||
}
|
||||
|
||||
// Invoke callback if provided
|
||||
if (pTransfer->callback) {
|
||||
|
||||
pTransfer->callback(pTransfer->pArg, AC97C_ERROR_STOPPED, size);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes the AC97 controller.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_Configure(void)
|
||||
{
|
||||
unsigned char channel;
|
||||
|
||||
// Enable the AC97 controller peripheral clock
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_AC97C);
|
||||
|
||||
// Enable the peripheral and variable rate adjustment
|
||||
AT91C_BASE_AC97C->AC97C_MR = AT91C_AC97C_ENA | AT91C_AC97C_VRA;
|
||||
|
||||
// Unassigns all input & output slots
|
||||
AC97C_AssignInputSlots(0, 0xFFFF);
|
||||
AC97C_AssignOutputSlots(0, 0xFFFF);
|
||||
|
||||
// Install the AC97C interrupt handler
|
||||
AT91C_BASE_AC97C->AC97C_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_AC97C, 0, AC97C_Handler);
|
||||
AIC_EnableIT(AT91C_ID_AC97C);
|
||||
|
||||
// Disable PDC transfers
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
|
||||
|
||||
// Clear channel transfers
|
||||
for (channel = 0; channel < AC97C_CHANNEL_B_TRANSMIT; channel++) {
|
||||
|
||||
ac97c.transfers[channel].numSamples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the desired channel with the given value.
|
||||
/// \param channel Channel number.
|
||||
/// \param cfg Configuration value.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_ConfigureChannel(unsigned char channel, unsigned int cfg)
|
||||
{
|
||||
SANITY_CHECK((channel == AC97C_CHANNEL_A) || (channel == AC97C_CHANNEL_B));
|
||||
|
||||
if (channel == AC97C_CHANNEL_A) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CAMR = cfg;
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CBMR = cfg;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Assigns the desired input slots to a particular channel.
|
||||
/// \param channel Channel number (or 0 to unassign slots).
|
||||
/// \param slots Bitfield value of slots to assign.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_AssignInputSlots(unsigned char channel, unsigned int slots)
|
||||
{
|
||||
unsigned int value;
|
||||
unsigned int i;
|
||||
|
||||
SANITY_CHECK(channel <= AC97C_CHANNEL_B);
|
||||
|
||||
// Assign all slots
|
||||
slots >>= 3;
|
||||
for (i = 3; i < 15; i++) {
|
||||
|
||||
// Check if slots is selected
|
||||
if (slots & 1) {
|
||||
|
||||
value = AT91C_BASE_AC97C->AC97C_ICA;
|
||||
value &= ~(0x07 << ((i - 3) * 3));
|
||||
value |= channel << ((i - 3) * 3);
|
||||
AT91C_BASE_AC97C->AC97C_ICA = value;
|
||||
}
|
||||
slots >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Assigns the desired output slots to a particular channel.
|
||||
/// \param channel Channel number (or 0 to unassign slots).
|
||||
/// \param slots Bitfield value of slots to assign.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_AssignOutputSlots(unsigned char channel, unsigned int slots)
|
||||
{
|
||||
unsigned int value;
|
||||
unsigned int i;
|
||||
|
||||
SANITY_CHECK(channel <= AC97C_CHANNEL_B);
|
||||
|
||||
// Assign all slots
|
||||
slots >>= 3;
|
||||
for (i = 3; i < 15; i++) {
|
||||
|
||||
// Check if slots is selected
|
||||
if (slots & 1) {
|
||||
|
||||
value = AT91C_BASE_AC97C->AC97C_OCA;
|
||||
value &= ~(0x07 << ((i - 3) * 3));
|
||||
value |= channel << ((i - 3) * 3);
|
||||
AT91C_BASE_AC97C->AC97C_OCA = value;
|
||||
}
|
||||
slots >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns 1 if no transfer is currently pending on the given channel;
|
||||
/// otherwise, returns 0.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char AC97C_IsFinished(unsigned char channel)
|
||||
{
|
||||
SANITY_CHECK(channel <= AC97C_CHANNEL_B_TRANSMIT);
|
||||
|
||||
if (ac97c.transfers[channel].numSamples > 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Convenience function for synchronously sending commands to the codec.
|
||||
/// \param address Register address.
|
||||
/// \param data Command data.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_WriteCodec(unsigned char address, unsigned short data)
|
||||
{
|
||||
unsigned int sample;
|
||||
|
||||
sample = (address << 16) | data;
|
||||
AC97C_Transfer(AC97C_CODEC_TRANSFER, (unsigned char *) &sample, 1, 0, 0);
|
||||
while (!AC97C_IsFinished(AC97C_CODEC_TRANSFER));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Convenience function for receiving data from the AC97 codec.
|
||||
/// \param address Register address.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned short AC97C_ReadCodec(unsigned char address)
|
||||
{
|
||||
unsigned int sample;
|
||||
|
||||
sample = AT91C_AC97C_READ | (address << 16);
|
||||
AC97C_Transfer(AC97C_CODEC_TRANSFER, (unsigned char *) &sample, 1, 0, 0);
|
||||
while (!AC97C_IsFinished(AC97C_CODEC_TRANSFER));
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the size in bits of one sample on the given channel.
|
||||
/// \param channel Channel number.
|
||||
/// \param size Size of one sample in bits (10, 16, 18 or 24).
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_SetChannelSize(unsigned char channel, unsigned char size)
|
||||
{
|
||||
unsigned int bits = 0;
|
||||
|
||||
SANITY_CHECK((size == 10) || (size == 16) || (size == 18) || (size == 24));
|
||||
SANITY_CHECK((channel == AC97C_CHANNEL_A) || (channel == AC97C_CHANNEL_B));
|
||||
|
||||
switch (size) {
|
||||
|
||||
case 10 : bits = AT91C_AC97C_SIZE_10_BITS; break;
|
||||
case 16 : bits = AT91C_AC97C_SIZE_16_BITS; break;
|
||||
case 18 : bits = AT91C_AC97C_SIZE_18_BITS; break;
|
||||
case 20 : bits = AT91C_AC97C_SIZE_20_BITS; break;
|
||||
}
|
||||
|
||||
if (channel == AC97C_CHANNEL_A) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~(AT91C_AC97C_SIZE);
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= bits;
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CBMR &= ~(AT91C_AC97C_SIZE);
|
||||
AT91C_BASE_AC97C->AC97C_CBMR |= bits;
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue