/*
* WspiBusDrv.c
*
* Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
* 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 Texas Instruments 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.
*/
/** \file WspiBusDrv.c
* \brief The WSPI bus driver upper layer. Platform independent.
* Uses the SpiAdapter API.
* Introduces a generic bus-independent API upwards.
*
* \see BusDrv.h, SpiAdapter.h, SpiAdapter.c
*/
#include "tidef.h"
#include "report.h"
#include "osApi.h"
#include "wspi.h"
#include "BusDrv.h"
#include "TxnDefs.h"
#define __FILE_ID__ FILE_ID_124
/************************************************************************
* Defines
************************************************************************/
#define WSPI_FIXED_BUSY_LEN 1
#define WSPI_INIT_CMD_MASK 0
/************************************************************************
* Types
************************************************************************/
/* The busDrv module Object */
typedef struct _TBusDrvObj
{
TI_HANDLE hOs;
TI_HANDLE hReport;
TI_HANDLE hDriver;
TI_HANDLE hWspi;
TTxnDoneCb fTxnDoneCb; /* The callback to call upon full transaction completion. */
TI_HANDLE hCbHandle; /* The callback handle */
TTxnStruct * pCurrTxn; /* The transaction currently being processed */
TI_STATUS eCurrTxnStatus; /* COMPLETE, PENDING or ERROR */
TI_UINT32 uCurrTxnBufsCount;
TI_BOOL bPendingByte;
TTxnDoneCb fTxnConnectDoneCb; /* The callback to call upon full transaction completion. */
} TBusDrvObj;
/************************************************************************
* Internal functions prototypes
************************************************************************/
static void asyncEnded_CB(TI_HANDLE hBusTxn, int status);
static void ConnectDone_CB(TI_HANDLE hBusDrv, int status);
/************************************************************************
*
* Module functions implementation
*
************************************************************************/
/**
* \fn busDrv_Create
* \brief Create the module
*
* Allocate and clear the module's object.
*
* \note
* \param hOs - Handle to Os Abstraction Layer
* \return Handle of the allocated object, NULL if allocation failed
* \sa busDrv_Destroy
*/
TI_HANDLE busDrv_Create (TI_HANDLE hOs)
{
TI_HANDLE hBusDrv;
TBusDrvObj *pBusDrv;
hBusDrv = os_memoryAlloc(hOs, sizeof(TBusDrvObj));
if (hBusDrv == NULL)
return NULL;
pBusDrv = (TBusDrvObj *)hBusDrv;
os_memoryZero(hOs, hBusDrv, sizeof(TBusDrvObj));
pBusDrv->hOs = hOs;
// addapt to WSPI
pBusDrv->hWspi= WSPI_Open(hOs);
return pBusDrv;
}
/**
* \fn busDrv_Destroy
* \brief Destroy the module.
*
* Close SPI lower bus driver and free the module's object.
*
* \note
* \param The module's object
* \return TI_OK on success or TI_NOK on failure
* \sa busDrv_Create
*/
TI_STATUS busDrv_Destroy (TI_HANDLE hBusDrv)
{
TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
if (pBusDrv)
{
// addapt to WSPI
WSPI_Close(pBusDrv->hWspi);
os_memoryFree (pBusDrv->hOs, pBusDrv, sizeof(TBusDrvObj));
}
return TI_OK;
}
/****************************************************************************
* busDrv_Init
****************************************************************************
* DESCRIPTION: config the module.
*
* INPUTS: hBusDrv - handle to the module context
* hReport - handle to report module context that is used when we output debug messages
* CBFunc - The callback to call upon transaction complete (calls the tasklet).
* CBArg - The handle for the CBFunc.
*
* OUTPUT: none.
*
* RETURNS: one of the error codes (0 => TI_OK)
****************************************************************************/
void busDrv_Init (TI_HANDLE hBusDrv,
TI_HANDLE hReport)
{
TBusDrvObj *pBusDrv = (TBusDrvObj*) hBusDrv;
pBusDrv->hReport = hReport;
}
/**
* \fn busDrv_ConnectBus
* \brief Configure bus driver
*
* Called by TxnQ.
* Configure the bus driver with its connection configuration (such as baud-rate, bus width etc)
* and establish the physical connection.
* Done once upon init (and not per functional driver startup).
*
* \note
* \param hBusDrv - The module's object
* \param pBusDrvCfg - A union used for per-bus specific configuration.
* \param fCbFunc - CB function for Async transaction completion (after all txn parts are completed).
* \param hCbArg - The CB function handle
* \return TI_OK / TI_NOK
* \sa
*/
TI_STATUS busDrv_ConnectBus (TI_HANDLE hBusDrv,
TBusDrvCfg *pBusDrvCfg,
TBusDrvTxnDoneCb fCbFunc,
TI_HANDLE hCbArg,
TBusDrvTxnDoneCb fConnectCbFunc
)
{
TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
int iStatus;
WSPIConfig_t wspi_config;
WSPI_CB_T cb;
/* Save the parameters (TxnQ callback for TxnDone events) */
pBusDrv->fTxnDoneCb = fCbFunc;
pBusDrv->hCbHandle = hCbArg;
pBusDrv->fTxnConnectDoneCb = fConnectCbFunc;
/* Configure the WSPI driver parameters */
wspi_config.isFixedAddress = TI_FALSE;
wspi_config.fixedBusyLength = WSPI_FIXED_BUSY_LEN;
wspi_config.mask = WSPI_INIT_CMD_MASK;
cb.CBFunc = ConnectDone_CB;/* The BusTxn callback called upon Async transaction end. */
cb.CBArg = hBusDrv; /* The handle for the BusDrv. */
/* Configure the WSPI module */
iStatus = WSPI_Configure(pBusDrv->hWspi, pBusDrv->hReport, &wspi_config, &cb);
if ((iStatus == 0) || (iStatus == 1))
{
TRACE1 (pBusDrv->hReport, REPORT_SEVERITY_INIT, "busDrv_ConnectBus: called Status %d\n",iStatus);
TRACE2 (pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_ConnectBus: Successful Status %d\n",iStatus);
return TI_OK;
}
else
{
TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_ConnectBus: Status = %d,\n", iStatus);
return TI_NOK;
}
}
/**
* \fn busDrv_DisconnectBus
* \brief Disconnect SDIO driver
*
* Called by TxnQ. Disconnect the SDIO driver.
*
* \note
* \param hBusDrv - The module's object
* \return TI_OK / TI_NOK
* \sa
*/
TI_STATUS busDrv_DisconnectBus (TI_HANDLE hBusDrv)
{
return TI_OK;
}
/**
* \fn busDrv_Transact
* \brief Process transaction
*
* Called by the TxnQ module to initiate a new transaction.
* Call either write or read functions according to Txn direction field.
*
* \note It's assumed that this function is called only when idle (i.e. previous Txn is done).
* \param hBusDrv - The module's object
* \param pTxn - The transaction object
* \return COMPLETE if Txn completed in this context, PENDING if not, ERROR if failed
* \sa busDrv_PrepareTxnParts, busDrv_SendTxnParts
*/
ETxnStatus busDrv_Transact (TI_HANDLE hBusDrv, TTxnStruct *pTxn)
{
TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
WSPI_CB_T cb;
TI_UINT8 * tempReadBuff;
TI_UINT8 * tempWriteBuff;
pBusDrv->pCurrTxn = pTxn;
pBusDrv->eCurrTxnStatus = TXN_STATUS_COMPLETE; /* The Txn is Sync as long as it continues in this context */
cb.CBFunc = asyncEnded_CB; /* The BusTxn callback called upon Async transaction end. */
cb.CBArg = hBusDrv; /* The handle for the BusTxnCB. */
/* If write command */
if (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_WRITE)
{
//WLAN_REPORT_INIT(pBusDrv->hReport, TNETW_DRV_MODULE_LOG,
// ("busDrv_Transact: Write to pTxn->uHwAddr %x\n", pTxn->uHwAddr ));
/*WLAN_REPORT_ERROR(pBusDrv->hReport, BUS_DRV_MODULE_LOG,
("busDrv_Transact: Buff= %x, Len=%d\n", pTxn->aBuf[0], pTxn->aLen[0]));*/
/*1.write memory*/
/* Decrease the data pointer to the beginning of the WSPI padding */
tempWriteBuff = pTxn->aBuf[0];
tempWriteBuff -= WSPI_PAD_LEN_WRITE;
/* Write the data to the WSPI in Aync mode (not completed in the current context). */
pBusDrv->eCurrTxnStatus = WSPI_WriteAsync(pBusDrv->hWspi, pTxn->uHwAddr,tempWriteBuff,pTxn->aLen[0], &cb, TI_TRUE, TI_TRUE,TXN_PARAM_GET_FIXED_ADDR(pTxn));
}
/* If read command */
else
{
//WLAN_REPORT_INIT(pBusDrv->hReport, TNETW_DRV_MODULE_LOG,
// ("busDrv_Transact: Read from pTxn->uHwAddr %x pTxn %x \n", pTxn->uHwAddr,pTxn));
/*1. Read mem */
/* Decrease the tempReadBuff pointer to the beginning of the WSPI padding */
tempReadBuff = pTxn->aBuf[0];
tempReadBuff -= WSPI_PAD_LEN_READ;
/* Read the required data from the WSPI in Aync mode (not completed in the current context). */
pBusDrv->eCurrTxnStatus = WSPI_ReadAsync(pBusDrv->hWspi, pTxn->uHwAddr,tempReadBuff,pTxn->aLen[0], &cb, TI_TRUE, TI_TRUE,TXN_PARAM_GET_FIXED_ADDR(pTxn));
}
/* return transaction status - COMPLETE, PENDING or ERROR */
return (pBusDrv->eCurrTxnStatus == WSPI_TXN_COMPLETE ? TXN_STATUS_COMPLETE :
(pBusDrv->eCurrTxnStatus == WSPI_TXN_PENDING ? TXN_STATUS_PENDING : TXN_STATUS_ERROR));
}
/****************************************************************************
* asyncEnded_CB()
****************************************************************************
* DESCRIPTION:
* Called back by the WSPI driver from Async transaction end interrupt (ISR context).
* Calls the upper layers callback.
*
* INPUTS: status -
*
* OUTPUT: None
*
* RETURNS: None
****************************************************************************/
static void asyncEnded_CB(TI_HANDLE hBusDrv, int status)
{
TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
/* If the last transaction failed, call failure CB and exit. */
if (status != 0)
{
TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "asyncEnded_CB : Status = %d, fTxnDoneCb = 0x%x\n", status,pBusDrv->fTxnDoneCb);
TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR);
}
else
{
TRACE2(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION,"asyncEnded_CB: Successful async cb done pBusDrv->pCurrTxn %x\n", pBusDrv->pCurrTxn);
}
/* Call the upper layer CB */
pBusDrv->fTxnDoneCb(pBusDrv->hCbHandle,pBusDrv->pCurrTxn);
}
/****************************************************************************
* ConnectDone_CB()
****************************************************************************
* DESCRIPTION:
* Called back by the WSPI driver from Async transaction end interrupt (ISR context).
* Calls the upper layers callback.
*
* INPUTS: status -
*
* OUTPUT: None
*
* RETURNS: None
****************************************************************************/
static void ConnectDone_CB(TI_HANDLE hBusDrv, int status)
{
TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
/* If the last transaction failed, call failure CB and exit. */
if (status != 0)
{
TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "ConnectDone_CB : Status = %d, fTxnConnectDoneCb = 0x%x\n", status,pBusDrv->fTxnConnectDoneCb);
TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR);
}
else
{
TRACE1 (pBusDrv->hReport, REPORT_SEVERITY_INIT, "ConnectDone_CB: Successful Connect Async cb done \n");
}
/* Call the upper layer CB */
pBusDrv->fTxnConnectDoneCb(pBusDrv->hCbHandle,pBusDrv->pCurrTxn);
}