blob: d084134fb7e6457cd0c87018c6b3e7185aef4666 [file] [log] [blame]
/*
* Copyright (c) 2015-2017, Texas Instruments Incorporated
* 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 following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS 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.
*/
#include <stdint.h>
#include <string.h>
/*
* By default disable both asserts and log for this module.
* This must be done before DebugP.h is included.
*/
#ifndef DebugP_ASSERT_ENABLED
#define DebugP_ASSERT_ENABLED 0
#endif
#ifndef DebugP_LOG_ENABLED
#define DebugP_LOG_ENABLED 0
#endif
#include <ti/drivers/dpl/DebugP.h>
#include <ti/drivers/dpl/HwiP.h>
#include <ti/drivers/dpl/SemaphoreP.h>
#include <ti/drivers/utils/List.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC32XX.h>
#include <ti/drivers/dma/UDMACC32XX.h>
#include <ti/drivers/i2s/I2SCC32XXDMA.h>
/* driverlib header files */
#include <ti/devices/cc32xx/inc/hw_memmap.h>
#include <ti/devices/cc32xx/inc/hw_ocp_shared.h>
#include <ti/devices/cc32xx/inc/hw_ints.h>
#include <ti/devices/cc32xx/inc/hw_mcasp.h>
#include <ti/devices/cc32xx/inc/hw_types.h>
#include <ti/devices/cc32xx/driverlib/rom.h>
#include <ti/devices/cc32xx/driverlib/rom_map.h>
#include <ti/devices/cc32xx/driverlib/interrupt.h>
#include <ti/devices/cc32xx/driverlib/i2s.h>
#include <ti/devices/cc32xx/driverlib/prcm.h>
#include <ti/devices/cc32xx/driverlib/udma.h>
#define PinConfigPinMode(config) (((config) >> 8) & 0xF)
#define PinConfigPin(config) (((config) >> 0) & 0x3F)
#define PAD_CONFIG_BASE (OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_0)
#define PAD_RESET_STATE 0xC61
/* I2SCC32XXDMA functions */
void I2SCC32XXDMA_close(I2S_Handle handle);
int_fast16_t I2SCC32XXDMA_control(I2S_Handle handle, uint_fast16_t cmd,
void *arg);
void I2SCC32XXDMA_init(I2S_Handle handle);
I2S_Handle I2SCC32XXDMA_open(I2S_Handle handle, I2S_Params *params);
int_fast16_t I2SCC32XXDMA_readIssue(I2S_Handle handle, I2S_BufDesc *desc);
size_t I2SCC32XXDMA_readReclaim(I2S_Handle handle, I2S_BufDesc **desc);
int_fast16_t I2SCC32XXDMA_writeIssue(I2S_Handle handle, I2S_BufDesc *desc);
size_t I2SCC32XXDMA_writeReclaim(I2S_Handle handle, I2S_BufDesc **desc);
/* I2S function table for I2SCC32XXDMA implementation */
const I2S_FxnTable I2SCC32XXDMA_fxnTable = {
I2SCC32XXDMA_close,
I2SCC32XXDMA_control,
I2SCC32XXDMA_init,
I2SCC32XXDMA_open,
I2SCC32XXDMA_readIssue,
I2SCC32XXDMA_readReclaim,
I2SCC32XXDMA_writeIssue,
I2SCC32XXDMA_writeReclaim
};
/*
* This lookup table is used to configure the DMA channels for the appropriate
* (16bit or 32bit) transfer sizes.
* Table for an I2S DMA RX channel.
*/
static const uint32_t dmaRxConfig[] = {
UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_CHCTL_DSTINC_16 | UDMA_ARB_8,
UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_CHCTL_DSTINC_32 | UDMA_ARB_8
};
/*
* This lookup table is used to configure the DMA channels for the appropriate
* (16bit or 32bit) transfer sizes.
* Table for an I2 DMA TX channel
*/
static const uint32_t dmaTxConfig[] = {
UDMA_SIZE_16 | UDMA_CHCTL_SRCINC_16 | UDMA_DST_INC_NONE | UDMA_ARB_8,
UDMA_SIZE_32 | UDMA_CHCTL_SRCINC_32 | UDMA_DST_INC_NONE | UDMA_ARB_8
};
/*Zero buffer to write when there is no data from the application*/
uint8_t I2SCC32XXDMA_zeroBuffer[128];
static I2S_BufDesc I2SCC32XXDMA_zeroBufDesc;
/*Empty buffer to read into when there is no data requested
from the application*/
static uint8_t I2SCC32XXDMA_emptyBuffer[128];
static I2S_BufDesc I2SCC32XXDMA_emptyBufDesc;
/*
* ======== I2SCC32XXDMA_configDMA ========
*/
static void I2SCC32XXDMA_configDMA(I2S_Handle handle, I2S_BufDesc *desc,
bool isWrite)
{
I2SCC32XXDMA_Object *object = handle->object;
I2SCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
unsigned long channelControlOptions;
uint32_t divider = 1;
if (object->dmaSize == I2SCC32XXDMA_16bit) {
divider = 2;
}
else if (object->dmaSize == I2SCC32XXDMA_32bit) {
divider = 4;
}
Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
if (isWrite) {
channelControlOptions = dmaTxConfig[object->dmaSize];
/* Setup ping-pong transfer */
MAP_uDMAChannelControlSet(hwAttrs->txChannelIndex,
channelControlOptions);
MAP_uDMAChannelTransferSet(hwAttrs->txChannelIndex,
UDMA_MODE_PINGPONG, (void *)desc->bufPtr,
(void *)I2S_TX_DMA_PORT, ((desc->bufSize / 2) / divider));
/* Pong Buffer */
MAP_uDMAChannelControlSet(hwAttrs->txChannelIndex | UDMA_ALT_SELECT,
channelControlOptions);
MAP_uDMAChannelTransferSet(hwAttrs->txChannelIndex | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,
(void *)(((char *)desc->bufPtr) + (desc->bufSize / 2)),
(void *)I2S_TX_DMA_PORT,
((desc->bufSize / 2) / divider));
MAP_uDMAChannelAttributeEnable(hwAttrs->txChannelIndex, UDMA_ATTR_USEBURST);
MAP_uDMAChannelEnable(hwAttrs->txChannelIndex);
/* Configure TX FIFO */
MAP_I2STxFIFOEnable(hwAttrs->baseAddr,8,1);
}
else {
/*
* TX is always required so configure TX dma
* if 'read' is called first
*/
I2SCC32XXDMA_configDMA(handle, &I2SCC32XXDMA_zeroBufDesc, true);
channelControlOptions = dmaRxConfig[object->dmaSize];
/* Setup ping-pong transfer */
MAP_uDMAChannelControlSet(hwAttrs->rxChannelIndex,
channelControlOptions);
MAP_uDMAChannelTransferSet(hwAttrs->rxChannelIndex,
UDMA_MODE_PINGPONG, (void *)I2S_RX_DMA_PORT,
(void *)desc->bufPtr, ((desc->bufSize / 2) / divider));
/* Pong Buffer */
MAP_uDMAChannelControlSet(hwAttrs->rxChannelIndex | UDMA_ALT_SELECT,
channelControlOptions);
MAP_uDMAChannelTransferSet(hwAttrs->rxChannelIndex | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG, (void *)I2S_RX_DMA_PORT,
(void *)(((char *)desc->bufPtr) + (desc->bufSize / 2)),
((desc->bufSize / 2) / divider));
MAP_uDMAChannelAttributeEnable(hwAttrs->rxChannelIndex, UDMA_ATTR_USEBURST);
MAP_uDMAChannelEnable(hwAttrs->rxChannelIndex);
/* Configure RX FIFO */
MAP_I2SRxFIFOEnable(hwAttrs->baseAddr,8,1);
}
DebugP_log1("I2S:(%p) DMA transfer enabled", hwAttrs->baseAddr);
if (isWrite) {
DebugP_log3("I2S:(%p) DMA transmit, txBuf: %p; Count: %d",
hwAttrs->baseAddr, (uintptr_t)(desc->bufPtr), desc->bufSize);
}
else {
DebugP_log3("I2S:(%p) DMA receive, rxBuf: %p; Count: %d",
hwAttrs->baseAddr, (uintptr_t)(desc->bufPtr), desc->bufSize);
}
}
/*
* ======== I2SCC32XXDMA_hwiIntFxn ========
* Hwi function that processes I2S interrupts.
*
* @param(arg) The I2S_Handle for this Hwi.
*/
static void I2SCC32XXDMA_hwiIntFxn(uintptr_t arg)
{
I2SCC32XXDMA_Object *object = ((I2S_Handle)arg)->object;
I2SCC32XXDMA_HWAttrsV1 const *hwAttrs = ((I2S_Handle)arg)->hwAttrs;
uint32_t divider = 1;
uint32_t intStatus;
if (object->dmaSize == I2SCC32XXDMA_16bit) {
divider = 2;
}
else if (object->dmaSize == I2SCC32XXDMA_32bit) {
divider = 4;
}
/* Read the interrupt status */
intStatus = MAP_I2SIntStatus(hwAttrs->baseAddr);
/* Check for TX DMA done interrupt */
if (intStatus & I2S_STS_XDMA) {
/* Clear the interrupt */
MAP_I2SIntClear(hwAttrs->baseAddr,I2S_STS_XDMA);
/* Check if ping is over */
if (UDMA_MODE_STOP == MAP_uDMAChannelModeGet(hwAttrs->txChannelIndex)){
/* Get the next user buffer from the write queue*/
object->currentWriteBufDesc = (I2S_BufDesc *)List_get(&object->writeActiveQueue);
/* If no user write buffer use the zero buffer */
if(NULL == object->currentWriteBufDesc)
{
object->currentWriteBufDesc = &I2SCC32XXDMA_zeroBufDesc;
}
/* Setup the DMA control table entry */
MAP_uDMAChannelTransferSet(hwAttrs->txChannelIndex,
UDMA_MODE_PINGPONG,
(void *)object->currentWriteBufDesc->bufPtr,
(void *)I2S_TX_DMA_PORT,
((object->currentWriteBufDesc->bufSize / 2) / divider));
}
else {
/* If prevWriteBufDesc points to valid user buffer release it */
if( (NULL != object->prevWriteBufDesc) &&
(object->prevWriteBufDesc != &I2SCC32XXDMA_zeroBufDesc) ){
object->serialPinVars[object->writeIndex].readWriteCallback(
(I2S_Handle)arg, object->prevWriteBufDesc);
}
/* Setup the DMA control table alternate entry */
MAP_uDMAChannelTransferSet(
hwAttrs->txChannelIndex | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,
(void *)((char*)object->currentWriteBufDesc->bufPtr +
(object->currentWriteBufDesc->bufSize / 2)),
(void *)I2S_TX_DMA_PORT,
((object->currentWriteBufDesc->bufSize / 2) / divider));
/* Save pointer to issued buffer descriptor.*/
object->prevWriteBufDesc = object->currentWriteBufDesc;
}
DebugP_log2("I2S:(%p) Write finished, %d bytes written",
hwAttrs->baseAddr, object->currentWriteBufDesc->bufSize);
}
/* Check if Rx DMA done interrupt */
if (intStatus & I2S_STS_RDMA) {
/* Clear the read interrupt */
MAP_I2SIntClear(hwAttrs->baseAddr,I2S_STS_RDMA);
/* Check if ping is over */
if (UDMA_MODE_STOP == MAP_uDMAChannelModeGet(hwAttrs->rxChannelIndex)) {
/* Get the next user buffer from the read queue*/
object->currentReadBufDesc = (I2S_BufDesc *)List_get(&object->readActiveQueue);
/* If no user read buffer use the empty buffer */
if(NULL == object->currentReadBufDesc)
{
object->currentReadBufDesc = &I2SCC32XXDMA_emptyBufDesc;
}
MAP_uDMAChannelTransferSet(hwAttrs->rxChannelIndex,
UDMA_MODE_PINGPONG,
(void *)I2S_RX_DMA_PORT,
(void *)object->currentReadBufDesc->bufPtr,
((object->currentReadBufDesc->bufSize / 2) / divider));
}
else {
/* If prevReadBufDesc points to valid user buffer release it */
if( (NULL != object->prevReadBufDesc) &&
(object->prevReadBufDesc != &I2SCC32XXDMA_emptyBufDesc) ){
object->serialPinVars[object->readIndex].readWriteCallback(
(I2S_Handle)arg, object->prevReadBufDesc);
}
/* Setup the DMA control table alternate entry */
MAP_uDMAChannelTransferSet(
hwAttrs->rxChannelIndex | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG, (void *)I2S_RX_DMA_PORT,
(void *)((char*)object->currentReadBufDesc->bufPtr +
(object->currentReadBufDesc->bufSize / 2)),
((object->currentReadBufDesc->bufSize / 2) / divider));
/* Save pointer to issued buffer descriptor.*/
object->prevReadBufDesc = object->currentReadBufDesc;
}
DebugP_log2("I2S:(%p) Read finished, %d bytes read",
hwAttrs->baseAddr, object->currentReadBufDesc->bufSize);
}
}
/*
* ======== I2SCC32XX_Params_init ========
*/
void I2SCC32XXDMA_Params_init(I2SCC32XXDMA_SerialPinParams *params)
{
DebugP_assert(params != NULL);
params->serialPinConfig[0].pinNumber = 0;
params->serialPinConfig[0].pinMode = I2S_PINMODE_TX;
params->serialPinConfig[0].inActiveConfig =
I2S_SERCONFIG_INACT_LOW_LEVEL;
params->serialPinConfig[1].pinNumber = 1;
params->serialPinConfig[1].pinMode = I2S_PINMODE_RX;
params->serialPinConfig[1].inActiveConfig =
I2S_SERCONFIG_INACT_LOW_LEVEL;
}
/*
* ======== readIssueCallback ========
* Simple callback to post a semaphore for the issue-reclaim mode.
*/
static void readIssueCallback(I2S_Handle handle, I2S_BufDesc *desc)
{
I2SCC32XXDMA_Object *object = handle->object;
List_put(&object->readDoneQueue, &(desc->qElem));
SemaphoreP_post(object->readSem);
}
/*
* ======== writeIssueCallback ========
* Simple callback to post a semaphore for the issue-reclaim mode.
*/
static void writeIssueCallback(I2S_Handle handle, I2S_BufDesc *desc)
{
I2SCC32XXDMA_Object *object = handle->object;
List_put(&object->writeDoneQueue, &(desc->qElem));
SemaphoreP_post(object->writeSem);
}
/*
* ======== I2SCC32XXDMA_close ========
*/
void I2SCC32XXDMA_close(I2S_Handle handle)
{
I2SCC32XXDMA_Object *object = handle->object;
I2SCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
uint32_t padRegister;
/* Disable I2S and interrupts. */
MAP_I2SDisable(hwAttrs->baseAddr);
if (object->hwiHandle) {
HwiP_delete(object->hwiHandle);
}
if (object->writeSem != NULL) {
SemaphoreP_delete(object->writeSem);
}
if (object->readSem != NULL){
SemaphoreP_delete(object->readSem);
}
if (object->dmaHandle != NULL) {
UDMACC32XX_close(object->dmaHandle);
}
Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
Power_releaseDependency(PowerCC32XX_PERIPH_I2S);
/* Restore pin pads to their reset states */
padRegister = (PinToPadGet((hwAttrs->xr0Pin) & 0x3f)<<2) + PAD_CONFIG_BASE;
HWREG(padRegister) = PAD_RESET_STATE;
padRegister = (PinToPadGet((hwAttrs->xr1Pin) & 0x3f)<<2) + PAD_CONFIG_BASE;
HWREG(padRegister) = PAD_RESET_STATE;
padRegister = (PinToPadGet((hwAttrs->clkxPin) & 0x3f)<<2) + PAD_CONFIG_BASE;
HWREG(padRegister) = PAD_RESET_STATE;
padRegister = (PinToPadGet((hwAttrs->clkPin) & 0x3f)<<2) + PAD_CONFIG_BASE;
HWREG(padRegister) = PAD_RESET_STATE;
padRegister = (PinToPadGet((hwAttrs->fsxPin) & 0x3f)<<2) + PAD_CONFIG_BASE;
HWREG(padRegister) = PAD_RESET_STATE;
object->opened = false;
DebugP_log1("I2S:(%p) closed", hwAttrs->baseAddr);
}
/*
* ======== I2SCC32XXDMA_control ========
* @pre Function assumes that the handle is not NULL
*/
int_fast16_t I2SCC32XXDMA_control(I2S_Handle handle, uint_fast16_t cmd, void *arg)
{
I2SCC32XXDMA_Object *object = handle->object;
uint32_t newSize = *(uint32_t *)arg;
switch(cmd){
case I2SCC32XXDMA_CMD_SET_ZEROBUF_LEN:
if (newSize > 32){
return -1;
}
I2SCC32XXDMA_zeroBufDesc.bufSize = newSize;
object->zeroWriteBufLength = newSize;
return(I2SCC32XXDMA_CMD_SET_ZEROBUF_LEN);
case I2SCC32XXDMA_CMD_SET_EMPTYBUF_LEN:
if (newSize > 32){
return -1;
}
I2SCC32XXDMA_emptyBufDesc.bufSize = newSize;
object->emptyReadBufLength = newSize;
return(I2SCC32XXDMA_CMD_SET_EMPTYBUF_LEN);
default:
return (I2S_STATUS_UNDEFINEDCMD);
}
}
/*
* ======== I2SCC32XXDMA_init ========
*/
void I2SCC32XXDMA_init(I2S_Handle handle)
{
I2SCC32XXDMA_Object *object = handle->object;
object->opened = false;
UDMACC32XX_init();
}
/*
* ======== I2SCC32XXDMA_open ========
*/
I2S_Handle I2SCC32XXDMA_open(I2S_Handle handle, I2S_Params *params)
{
uintptr_t key;
unsigned int bitClock;
unsigned int slotConfig;
I2SCC32XXDMA_Object *object = handle->object;
I2SCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
I2SCC32XXDMA_SerialPinParams *cc3200CustomParams;
SemaphoreP_Params semParams;
HwiP_Params hwiParams;
int i;
uint32_t pin;
uint32_t mode;
unsigned long i2s_data_line[] = {
I2S_DATA_LINE_0, I2S_DATA_LINE_1
};
I2SCC32XXDMA_SerialPinParams defaultSerialPinParams;
cc3200CustomParams = (I2SCC32XXDMA_SerialPinParams *)params->customParams;
/* If customParams are NULL use defaults. */
if (!params->customParams) {
I2SCC32XXDMA_Params_init(&defaultSerialPinParams);
cc3200CustomParams = &defaultSerialPinParams;
}
/* Disable preemption while checking if the I2S is open. */
key = HwiP_disable();
/* Check if the I2S is open already with the base addr. */
if (object->opened == true) {
HwiP_restore(key);
DebugP_log1("I2S:(%p) already in use.", hwAttrs->baseAddr);
return (NULL);
}
object->opened = true;
HwiP_restore(key);
/* Set I2S variables to defaults. */
object->readSem = NULL;
object->writeSem = NULL;
object->writeIndex = I2SCC32XXDMA_INDEX_INVALID;
object->readIndex = I2SCC32XXDMA_INDEX_INVALID;
object->dmaHandle = NULL;
object->currentWriteBufDesc = NULL;
object->currentReadBufDesc = NULL;
object->emptyReadBufLength = sizeof(I2SCC32XXDMA_emptyBuffer);
object->zeroWriteBufLength = sizeof(I2SCC32XXDMA_zeroBuffer);
memset(&I2SCC32XXDMA_zeroBuffer,0,sizeof(I2SCC32XXDMA_zeroBuffer));
I2SCC32XXDMA_zeroBufDesc.bufPtr = &I2SCC32XXDMA_zeroBuffer;
I2SCC32XXDMA_zeroBufDesc.bufSize = object->zeroWriteBufLength;
I2SCC32XXDMA_emptyBufDesc.bufPtr = &I2SCC32XXDMA_emptyBuffer;
I2SCC32XXDMA_emptyBufDesc.bufSize = object->emptyReadBufLength;
object->operationMode = params->operationMode;
/*
* Register power dependency. Keeps the clock running in SLP
* and DSLP modes.
*/
Power_setDependency(PowerCC32XX_PERIPH_I2S);
MAP_PRCMPeripheralReset(PRCM_I2S);
pin = PinConfigPin(hwAttrs->xr0Pin);
mode = PinConfigPinMode(hwAttrs->xr0Pin);
MAP_PinTypeI2S((unsigned long)pin, (unsigned long)mode);
pin = PinConfigPin(hwAttrs->xr1Pin);
mode = PinConfigPinMode(hwAttrs->xr1Pin);
MAP_PinTypeI2S((unsigned long)pin, (unsigned long)mode);
pin = PinConfigPin(hwAttrs->clkxPin);
mode = PinConfigPinMode(hwAttrs->clkxPin);
MAP_PinTypeI2S((unsigned long)pin, (unsigned long)mode);
pin = PinConfigPin(hwAttrs->clkPin);
mode = PinConfigPinMode(hwAttrs->clkPin);
MAP_PinTypeI2S((unsigned long)pin, (unsigned long)mode);
pin = PinConfigPin(hwAttrs->fsxPin);
mode = PinConfigPinMode(hwAttrs->fsxPin);
MAP_PinTypeI2S((unsigned long)pin, (unsigned long)mode);
for (i = 0; i < 2; i++) {
if (cc3200CustomParams->serialPinConfig[i].pinMode !=
I2S_PINMODE_INACTIVE) {
if (cc3200CustomParams->serialPinConfig[i].pinMode ==
I2S_PINMODE_RX) {
object->readIndex = i;
object->serialPinVars[i].readWriteMode = params->readMode;
object->serialPinVars[i].readWriteCallback =
params->readCallback;
object->serialPinVars[i].readWriteTimeout = params->readTimeout;
MAP_I2SSerializerConfig(hwAttrs->baseAddr,i2s_data_line[i],
I2S_SER_MODE_RX, I2S_INACT_LOW_LEVEL);
}
else if (cc3200CustomParams->serialPinConfig[i].pinMode ==
I2S_PINMODE_TX) {
object->writeIndex = i;
object->serialPinVars[i].readWriteMode =
params->writeMode;
object->serialPinVars[i].readWriteCallback =
params->writeCallback;
object->serialPinVars[i].readWriteTimeout =
params->writeTimeout;
MAP_I2SSerializerConfig(hwAttrs->baseAddr,i2s_data_line[i],
I2S_SER_MODE_TX, I2S_INACT_LOW_LEVEL);
}
}
}
/* Disable the I2S interrupt. */
MAP_I2SIntDisable(hwAttrs->baseAddr,I2S_INT_XDMA | I2S_INT_RDMA);
HwiP_clearInterrupt(hwAttrs->intNum);
HwiP_Params_init(&hwiParams);
hwiParams.arg = (uintptr_t)handle;
hwiParams.priority = hwAttrs->intPriority;
object->hwiHandle = HwiP_create(hwAttrs->intNum,
I2SCC32XXDMA_hwiIntFxn,
&hwiParams);
if (object->hwiHandle == NULL) {
I2SCC32XXDMA_close(handle);
return (NULL);
}
object->dmaHandle = UDMACC32XX_open();
if (object->dmaHandle == NULL) {
I2SCC32XXDMA_close(handle);
return (NULL);
}
MAP_I2SIntEnable(hwAttrs->baseAddr,I2S_INT_XDMA | I2S_INT_RDMA);
if (params->operationMode == I2S_OPMODE_TX_ONLY) {
object->operationMode = I2S_MODE_TX_ONLY;
}
else if (params->operationMode == I2S_OPMODE_TX_RX_SYNC) {
object->operationMode = I2S_MODE_TX_RX_SYNC;
}
else {
I2SCC32XXDMA_close(handle);
return (NULL);
}
if (params->slotLength == 16) {
slotConfig = I2S_SLOT_SIZE_16;
object->dmaSize = I2SCC32XXDMA_16bit;
}
else if (params->slotLength == 24) {
slotConfig = I2S_SLOT_SIZE_24;
object->dmaSize = I2SCC32XXDMA_32bit;
}
else {
I2SCC32XXDMA_close(handle);
return (NULL);
}
SemaphoreP_Params_init(&semParams);
if (object->writeIndex != I2SCC32XXDMA_INDEX_INVALID) {
/* Initialize write Queue */
List_clearList(&object->writeActiveQueue);
if (object->serialPinVars[object->writeIndex].readWriteMode ==
I2S_MODE_ISSUERECLAIM) {
object->serialPinVars[object->writeIndex].readWriteCallback =
&writeIssueCallback;
semParams.mode = SemaphoreP_Mode_COUNTING;
object->writeSem = SemaphoreP_create(0, &semParams);
if (object->writeSem == NULL) {
DebugP_log1("I2S:(%p) Failed to create semaphore.",
hwAttrs->baseAddr);
I2SCC32XXDMA_close(handle);
return (NULL);
}
}
/* Initialize write Queue */
List_clearList(&object->writeDoneQueue);
}
if (object->readIndex != I2SCC32XXDMA_INDEX_INVALID) {
List_clearList(&object->readActiveQueue);
if (object->serialPinVars[object->readIndex].readWriteMode ==
I2S_MODE_ISSUERECLAIM) {
object->serialPinVars[object->readIndex].readWriteCallback =
&readIssueCallback;
semParams.mode = SemaphoreP_Mode_COUNTING;
object->readSem = SemaphoreP_create(0, &semParams);
if (object->readSem == NULL) {
if (object->writeSem) {
SemaphoreP_delete(object->writeSem);
DebugP_log1("I2S:(%p) Failed to create semaphore.",
hwAttrs->baseAddr);
I2SCC32XXDMA_close(handle);
return (NULL);
}
/* Initialize read Queues */
List_clearList(&object->readDoneQueue);
}
}
}
bitClock = (params->samplingFrequency *
params->slotLength * params->numChannels);
MAP_PRCMI2SClockFreqSet(bitClock);
MAP_I2SConfigSetExpClk(hwAttrs->baseAddr,bitClock,bitClock,slotConfig |
I2S_PORT_DMA);
MAP_uDMAChannelAssign(hwAttrs->rxChannelIndex);
MAP_uDMAChannelAttributeDisable(hwAttrs->rxChannelIndex,
UDMA_ATTR_ALTSELECT);
MAP_uDMAChannelAssign(hwAttrs->txChannelIndex);
MAP_uDMAChannelAttributeDisable(hwAttrs->txChannelIndex,
UDMA_ATTR_ALTSELECT);
/* Configure the DMA with zero/empty buffers */
if (params->operationMode == I2S_OPMODE_TX_ONLY){
I2SCC32XXDMA_configDMA(handle, &I2SCC32XXDMA_zeroBufDesc,true);
}
else{
I2SCC32XXDMA_configDMA(handle, &I2SCC32XXDMA_emptyBufDesc,false);
}
/* Enable the I2S */
MAP_I2SEnable(hwAttrs->baseAddr,object->operationMode);
DebugP_log1("I2S:(%p) opened", hwAttrs->baseAddr);
/* Return the handle */
return (handle);
}
/*
* ======== I2SCC32XXDMA_readIssue ========
*/
int_fast16_t I2SCC32XXDMA_readIssue(I2S_Handle handle, I2S_BufDesc *desc)
{
I2SCC32XXDMA_Object *object = handle->object;
if (object->readIndex == I2SCC32XXDMA_INDEX_INVALID) {
return (I2S_STATUS_UNDEFINEDCMD);
}
List_put(&object->readActiveQueue, &(desc->qElem));
return (0);
}
/*
* ======== I2SCC32XXDMA_readReclaim ========
*/
size_t I2SCC32XXDMA_readReclaim(I2S_Handle handle, I2S_BufDesc **desc)
{
I2SCC32XXDMA_Object *object = handle->object;
size_t size = 0;
*desc = NULL;
if (SemaphoreP_OK != SemaphoreP_pend(object->readSem,
object->serialPinVars[object->readIndex].readWriteTimeout)) {
DebugP_log1("I2S:(%p) Read timed out",
((I2SCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr);
}
else {
*desc = (I2S_BufDesc *)List_get(&object->readDoneQueue);
DebugP_assert(*desc != NULL);
size = (*desc)->bufSize;
}
return (size);
}
/*
* ======== I2SCC32XXDMA_writeIssue ========
*/
int_fast16_t I2SCC32XXDMA_writeIssue(I2S_Handle handle, I2S_BufDesc *desc)
{
I2SCC32XXDMA_Object *object = handle->object;
if (object->writeIndex == I2SCC32XXDMA_INDEX_INVALID) {
return (I2S_STATUS_UNDEFINEDCMD);
}
List_put(&object->writeActiveQueue, &(desc->qElem));
return (0);
}
/*
* ======== I2SCC32XXDMA_writeReclaim ========
*/
size_t I2SCC32XXDMA_writeReclaim(I2S_Handle handle, I2S_BufDesc **desc)
{
I2SCC32XXDMA_Object *object = handle->object;
size_t size = 0;
*desc = NULL;
if (SemaphoreP_OK != SemaphoreP_pend(object->writeSem,
object->serialPinVars[object->writeIndex].readWriteTimeout)) {
DebugP_log1("I2S:(%p) Write timed out",
((I2SCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr);
}
else {
*desc = (I2S_BufDesc *)List_get(&object->writeDoneQueue);
DebugP_assert(*desc != NULL);
size = (*desc)->bufSize;
}
return (size);
}