OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [drivers/] [Atmel/] [at91lib/] [peripherals/] [ac97c/] [ac97c.c] - Rev 608

Compare with Previous | Blame | View Log

/* ----------------------------------------------------------------------------
 *         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;
    }
}
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.