/* Sync/Async Threshold */ #ifdef FULL_ASYNC_MODE #define SYNC_ASYNC_LENGTH_THRESH 0 /* Use Async for all transactions */ #else #define SYNC_ASYNC_LENGTH_THRESH 360 /* Use Async for transactions longer than this threshold (in bytes) */ #endif #define MAX_RETRIES 10 #define MAX_BUS_TXN_SIZE 8192 /* Max bus transaction size in bytes (for the DMA buffer allocation) */ int sdioAdapt_ConnectBus (void * fCbFunc, void * hCbArg, unsigned int uBlkSizeShift, unsigned int uSdioThreadPriority, unsigned char **pRxDmaBufAddr, unsigned int *pRxDmaBufLen, unsigned char **pTxDmaBufAddr, unsigned int *pTxDmaBufLen) { unsigned int uBlkSize = 1 << uBlkSizeShift; int iStatus; if (uBlkSize < SYNC_ASYNC_LENGTH_THRESH) { PERR1("%s(): Block-Size should be bigger than SYNC_ASYNC_LENGTH_THRESH!!\n", __FUNCTION__ ); } /* Allocate a DMA-able buffer and provide it to the upper layer to be used for all read and write transactions */ if (pDmaBufAddr == 0) /* allocate only once (in case this function is called multiple times) */ { pDmaBufAddr = kmalloc (MAX_BUS_TXN_SIZE, GFP_ATOMIC | GFP_DMA); if (pDmaBufAddr == 0) { return -1; } } *pRxDmaBufAddr = *pTxDmaBufAddr = pDmaBufAddr; *pRxDmaBufLen = *pTxDmaBufLen = MAX_BUS_TXN_SIZE; /* Init SDIO driver and HW */ iStatus = sdioDrv_ConnectBus (fCbFunc, hCbArg, uBlkSizeShift,uSdioThreadPriority); if (iStatus) { return iStatus; } sdioDrv_ClaimHost(SDIO_WLAN_FUNC); iStatus = sdioDrv_EnableFunction(TXN_FUNC_ID_WLAN); if (iStatus) { sdioDrv_ReleaseHost(SDIO_WLAN_FUNC); return iStatus; } #ifdef SDIO_IN_BAND_INTERRUPT iStatus = sdioDrv_EnableInterrupt(TXN_FUNC_ID_WLAN); if (iStatus) { return iStatus; } #endif iStatus = sdioDrv_SetBlockSize(TXN_FUNC_ID_WLAN, uBlkSize); if (iStatus) { sdioDrv_ReleaseHost(SDIO_WLAN_FUNC); return iStatus; } sdioDrv_ReleaseHost(SDIO_WLAN_FUNC); return iStatus; }
ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, unsigned int uHwAddr, void * pHostAddr, unsigned int uLength, unsigned int bDirection, unsigned int bMore) { int iStatus; if (bMore ==1) sdioDrv_ClaimHost(SDIO_WLAN_FUNC); /* Call read or write bytes Sync method */ if (bDirection) { iStatus = sdioDrv_ReadSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore); } else { iStatus = sdioDrv_WriteSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore); } if (bMore ==0) sdioDrv_ReleaseHost(SDIO_WLAN_FUNC); /* If failed return ERROR, if succeeded return COMPLETE */ if (iStatus) { return TXN_STATUS_ERROR; } return TXN_STATUS_COMPLETE; }
int sdioDrv_DisconnectBus (void) { printk("%s\n", __FUNCTION__); sdioDrv_ReleaseHost(SDIO_WLAN_FUNC); return 0; }
int sdioAdapt_DisconnectBus (void) { #ifndef PROPRIETARY_SDIO sdioDrv_ClaimHost(SDIO_WLAN_FUNC); sdioDrv_DisableFunction(TXN_FUNC_ID_WLAN); sdioDrv_ReleaseHost(SDIO_WLAN_FUNC); #endif if (pDmaBufAddr) { kfree (pDmaBufAddr); pDmaBufAddr = 0; } return sdioDrv_DisconnectBus (); }
int sdioAdapt_DisconnectBus (void) { #ifdef SDIO_IN_BAND_INTERRUPT sdioDrv_DisableInterrupt(TXN_FUNC_ID_WLAN); #endif sdioDrv_ClaimHost(SDIO_WLAN_FUNC); sdioDrv_DisableFunction(TXN_FUNC_ID_WLAN); sdioDrv_ReleaseHost(SDIO_WLAN_FUNC); if (pDmaBufAddr) { kfree (pDmaBufAddr); pDmaBufAddr = 0; } return sdioDrv_DisconnectBus (); }
int sdioAdapt_ConnectBus (void * fCbFunc, void * hCbArg, unsigned int uBlkSizeShift, unsigned int uSdioThreadPriority, unsigned char **pRxDmaBufAddr, unsigned int *pRxDmaBufLen, unsigned char **pTxDmaBufAddr, unsigned int *pTxDmaBufLen) { #ifdef PROPRIETARY_SDIO unsigned char uByte; unsigned long uLong; unsigned long uCount = 0; #endif unsigned int uBlkSize = 1 << uBlkSizeShift; int iStatus; if (uBlkSize < SYNC_ASYNC_LENGTH_THRESH) { PERR1("%s(): Block-Size should be bigger than SYNC_ASYNC_LENGTH_THRESH!!\n", __FUNCTION__ ); } #ifdef PROPRIETARY_SDIO /* Enabling clocks if thet are not enabled */ sdioDrv_clk_enable(); #endif /* Allocate a DMA-able buffer and provide it to the upper layer to be used for all read and write transactions */ if (pDmaBufAddr == 0) /* allocate only once (in case this function is called multiple times) */ { pDmaBufAddr = kmalloc (MAX_BUS_TXN_SIZE, GFP_KERNEL | GFP_DMA); if (pDmaBufAddr == 0) { return -1; } } *pRxDmaBufAddr = *pTxDmaBufAddr = pDmaBufAddr; *pRxDmaBufLen = *pTxDmaBufLen = MAX_BUS_TXN_SIZE; /* Init SDIO driver and HW */ iStatus = sdioDrv_ConnectBus (fCbFunc, hCbArg, uBlkSizeShift, uSdioThreadPriority); if (iStatus) { return iStatus; } #ifndef PROPRIETARY_SDIO sdioDrv_ClaimHost(SDIO_WLAN_FUNC); iStatus = sdioDrv_EnableFunction(TXN_FUNC_ID_WLAN); if (iStatus) { return iStatus; } iStatus = sdioDrv_SetBlockSize(TXN_FUNC_ID_WLAN, uBlkSize); if (iStatus) { return iStatus; } sdioDrv_ReleaseHost(SDIO_WLAN_FUNC); #endif #ifdef PROPRIETARY_SDIO /* Send commands sequence: 0, 5, 3, 7 */ iStatus = sdioDrv_ExecuteCmd (SD_IO_GO_IDLE_STATE, 0, MMC_RSP_NONE, &uByte, sizeof(uByte)); if (iStatus) { printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_GO_IDLE_STATE); return iStatus; } iStatus = sdioDrv_ExecuteCmd (SDIO_CMD5, VDD_VOLTAGE_WINDOW, MMC_RSP_R4, &uByte, sizeof(uByte)); if (iStatus) { printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SDIO_CMD5); return iStatus; } iStatus = sdioDrv_ExecuteCmd (SD_IO_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6, &uLong, sizeof(uLong)); if (iStatus) { printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SEND_RELATIVE_ADDR); return iStatus; } iStatus = sdioDrv_ExecuteCmd (SD_IO_SELECT_CARD, uLong, MMC_RSP_R6, &uByte, sizeof(uByte)); if (iStatus) { printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SELECT_CARD); return iStatus; } /* NOTE: * ===== * Each of the following loops is a workaround for a HW bug that will be solved in PG1.1 !! * Each write of CMD-52 to function-0 should use it as follows: * 1) Write the desired byte using CMD-52 * 2) Read back the byte using CMD-52 * 3) Write two dummy bytes to address 0xC8 using CMD-53 * 4) If the byte read in step 2 is different than the written byte repeat the sequence */ /* set device side bus width to 4 bit (for 1 bit write 0x80 instead of 0x82) */ do { uByte = SDIO_BITS_CODE; iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1); if (iStatus) { return iStatus; } iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1); if (iStatus) { return iStatus; } iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); if (iStatus) { return iStatus; } uCount++; } while ((uByte != SDIO_BITS_CODE) && (uCount < MAX_RETRIES)); uCount = 0; /* allow function 2 */ do { uByte = 4; iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1); if (iStatus) { return iStatus; } iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1); if (iStatus) { return iStatus; } iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); if (iStatus) { return iStatus; } uCount++; } while ((uByte != 4) && (uCount < MAX_RETRIES)); #ifdef SDIO_IN_BAND_INTERRUPT uCount = 0; do { uByte = 3; iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1); if (iStatus) { return iStatus; } iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1); if (iStatus) { return iStatus; } iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); if (iStatus) { return iStatus; } uCount++; } while ((uByte != 3) && (uCount < MAX_RETRIES)); #endif uCount = 0; /* set block size for SDIO block mode */ do { uLong = uBlkSize; iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1); if (iStatus) { return iStatus; } iStatus = sdioDrv_ReadSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1); if (iStatus) { return iStatus; } iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); if (iStatus) { return iStatus; } uCount++; } while (((uLong & FN0_FBR2_REG_108_BIT_MASK) != uBlkSize) && (uCount < MAX_RETRIES)); if (uCount >= MAX_RETRIES) { /* Failed to write CMD52_WRITE to function 0 */ return (int)uCount; } /* Disable the clocks for now */ sdioDrv_clk_disable(); #endif return iStatus; }