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