1/* 2 * SdioAdapter.c 3 * 4 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved. 5 * Copyright(c) 2008 - 2009 Google, Inc. All rights reserved. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name Texas Instruments nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35/** \file SdioAdapter.c 36 * \brief The SDIO driver adapter. Platform dependent. 37 * 38 * An adaptation layer between the lower SDIO driver (in BSP) and the upper Sdio 39 * Used for issuing all SDIO transaction types towards the lower SDIO-driver. 40 * Makes the decision whether to use Sync or Async transaction, and reflects it 41 * by the return value and calling its callback in case of Async. 42 * 43 * \see SdioAdapter.h, SdioDrv.c & h 44 */ 45 46#ifdef CONFIG_MMC_EMBEDDED_SDIO 47#include <linux/kernel.h> 48#include <linux/mutex.h> 49#include <linux/mmc/core.h> 50#include <linux/mmc/card.h> 51#include <linux/mmc/sdio_func.h> 52#include <linux/mmc/sdio_ids.h> 53#include "TxnDefs.h" 54 55#define TI_SDIO_DEBUG 56 57#define TIWLAN_MMC_MAX_DMA 8192 58 59int wifi_set_carddetect( int on ); 60 61static struct sdio_func *tiwlan_func = NULL; 62static struct completion sdio_wait; 63 64ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, 65 unsigned int uHwAddr, 66 void * pHostAddr, 67 unsigned int uLength, 68 unsigned int bDirection, 69 unsigned int bMore); 70 71static int sdio_wifi_probe(struct sdio_func *func, 72 const struct sdio_device_id *id) 73{ 74 int rc; 75 76 printk("%s: %d\n", __FUNCTION__, func->class); 77 78 if (func->class != SDIO_CLASS_WLAN) 79 return -EINVAL; 80 81 sdio_claim_host(func); 82 83 rc = sdio_enable_func(func); 84 if (rc) 85 goto err1; 86 rc = sdio_set_block_size(func, 512); 87 88 if (rc) { 89 printk("%s: Unable to set blocksize\n", __FUNCTION__); 90 goto err2; 91 } 92 93 tiwlan_func = func; 94 complete(&sdio_wait); 95 return 0; 96err2: 97 sdio_disable_func(func); 98err1: 99 sdio_release_host(func); 100 complete(&sdio_wait); 101 return rc; 102} 103 104static void sdio_wifi_remove(struct sdio_func *func) 105{ 106} 107 108static const struct sdio_device_id sdio_wifi_ids[] = { 109 { SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN) }, 110 { }, 111}; 112 113MODULE_DEVICE_TABLE(sdio, sdio_wifi_ids); 114 115static struct sdio_driver sdio_wifi_driver = { 116 .probe = sdio_wifi_probe, 117 .remove = sdio_wifi_remove, 118 .name = "sdio_wifi", 119 .id_table = sdio_wifi_ids, 120}; 121 122ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, 123 unsigned int uHwAddr, 124 void * pHostAddr, 125 unsigned int uLength, 126 unsigned int bDirection, 127 unsigned int bMore); 128 129int sdioAdapt_ConnectBus (void * fCbFunc, 130 void * hCbArg, 131 unsigned int uBlkSizeShift, 132 unsigned int uSdioThreadPriority, 133 unsigned char **pTxDmaSrcAddr) 134{ 135 int rc; 136 137 init_completion(&sdio_wait); 138 wifi_set_carddetect( 1 ); 139 rc = sdio_register_driver(&sdio_wifi_driver); 140 if (rc < 0) { 141 printk(KERN_ERR "%s: Fail to register sdio_wifi_driver\n", __func__); 142 return rc; 143 } 144 if (!wait_for_completion_timeout(&sdio_wait, msecs_to_jiffies(10000))) { 145 printk(KERN_ERR "%s: Timed out waiting for device detect\n", __func__); 146 sdio_unregister_driver(&sdio_wifi_driver); 147 return -ENODEV; 148 } 149 /* Provide the DMA buffer address to the upper layer so it will use it as the transactions host buffer. */ 150 if (pTxDmaSrcAddr) { /* Dm: check what to do with it */ 151 *pTxDmaSrcAddr = kmalloc(TIWLAN_MMC_MAX_DMA, GFP_ATOMIC | GFP_DMA); 152 } 153 return 0; 154} 155 156int sdioAdapt_DisconnectBus (void) 157{ 158 if (tiwlan_func) { 159 sdio_disable_func( tiwlan_func ); 160 sdio_release_host( tiwlan_func ); 161 } 162 wifi_set_carddetect( 0 ); 163 sdio_unregister_driver(&sdio_wifi_driver); 164 return 0; 165} 166 167ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, 168 unsigned int uHwAddr, 169 void * pHostAddr, 170 unsigned int uLength, 171 unsigned int bDirection, 172 unsigned int bMore) 173{ 174 unsigned char *pData = pHostAddr; 175 unsigned int i; 176 int rc = 0, final_rc = 0; 177 178 for (i = 0; i < uLength; i++) { 179 if( bDirection ) { 180 if (uFuncId == 0) 181 *pData = (unsigned char)sdio_f0_readb(tiwlan_func, uHwAddr, &rc); 182 else 183 *pData = (unsigned char)sdio_readb(tiwlan_func, uHwAddr, &rc); 184 } 185 else { 186 if (uFuncId == 0) 187 sdio_f0_writeb(tiwlan_func, *pData, uHwAddr, &rc); 188 else 189 sdio_writeb(tiwlan_func, *pData, uHwAddr, &rc); 190 } 191 if( rc ) { 192 final_rc = rc; 193 } 194#ifdef TI_SDIO_DEBUG 195 printk(KERN_INFO "%c52: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)*pData); 196#endif 197 uHwAddr++; 198 pData++; 199 } 200 /* If failed return ERROR, if succeeded return COMPLETE */ 201 if (final_rc) { 202 return TXN_STATUS_ERROR; 203 } 204 return TXN_STATUS_COMPLETE; 205} 206 207ETxnStatus sdioAdapt_Transact (unsigned int uFuncId, 208 unsigned int uHwAddr, 209 void * pHostAddr, 210 unsigned int uLength, 211 unsigned int bDirection, 212 unsigned int bBlkMode, 213 unsigned int bFixedAddr, 214 unsigned int bMore) 215{ 216 int rc; 217 218 if (uFuncId == 0) 219 return sdioAdapt_TransactBytes (uFuncId, uHwAddr, pHostAddr, 220 uLength, bDirection, bMore); 221 if (bDirection) { 222 if (bFixedAddr) 223 rc = sdio_memcpy_fromio(tiwlan_func, pHostAddr, uHwAddr, uLength); 224 else 225 rc = sdio_readsb(tiwlan_func, pHostAddr, uHwAddr, uLength); 226 227 } 228 else { 229 if (bFixedAddr) 230 rc = sdio_memcpy_toio(tiwlan_func, uHwAddr, pHostAddr, uLength); 231 else 232 rc = sdio_writesb(tiwlan_func, uHwAddr, pHostAddr, uLength); 233 } 234#ifdef TI_SDIO_DEBUG 235 if (uLength == 1) 236 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(char *)pHostAddr)); 237 else if (uLength == 2) 238 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(short *)pHostAddr)); 239 else if (uLength == 4) 240 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(long *)pHostAddr)); 241 else 242 printk(KERN_INFO "%c53: [0x%x](%u) F[%d] B[%d] I[%d] = %d\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, uFuncId, bBlkMode, bFixedAddr, rc); 243#endif 244 /* If failed return ERROR, if succeeded return COMPLETE */ 245 if (rc) { 246 return TXN_STATUS_ERROR; 247 } 248 return TXN_STATUS_COMPLETE; 249} 250 251#else 252 253#include "SdioDrvDbg.h" 254#include "TxnDefs.h" 255#include "SdioAdapter.h" 256#include "SdioDrv.h" 257#include "bmtrace_api.h" 258 259#ifdef SDIO_1_BIT /* see also in SdioDrv.c */ 260#define SDIO_BITS_CODE 0x80 /* 1 bits */ 261#else 262#define SDIO_BITS_CODE 0x82 /* 4 bits */ 263#endif 264 265/************************************************************************ 266 * Defines 267 ************************************************************************/ 268/* Sync/Async Threshold */ 269#ifdef FULL_ASYNC_MODE 270#define SYNC_ASYNC_LENGTH_THRESH 0 /* Use Async for all transactions */ 271#else 272#define SYNC_ASYNC_LENGTH_THRESH 360 /* Use Async for transactions longer than this threshold (in bytes) */ 273#endif 274 275#define MAX_RETRIES 10 276 277/* For block mode configuration */ 278#define FN0_FBR2_REG_108 0x210 279#define FN0_FBR2_REG_108_BIT_MASK 0xFFF 280 281int sdioDrv_clk_enable(void); 282void sdioDrv_clk_disable(void); 283 284int sdioAdapt_ConnectBus (void * fCbFunc, 285 void * hCbArg, 286 unsigned int uBlkSizeShift, 287 unsigned int uSdioThreadPriority, 288 unsigned char **pTxDmaSrcAddr) 289{ 290 unsigned char uByte; 291 unsigned long uLong; 292 unsigned long uCount = 0; 293 unsigned int uBlkSize = 1 << uBlkSizeShift; 294 int iStatus; 295 296 if (uBlkSize < SYNC_ASYNC_LENGTH_THRESH) 297 { 298 PERR1("%s(): Block-Size should be bigger than SYNC_ASYNC_LENGTH_THRESH!!\n", __FUNCTION__ ); 299 } 300 301 /* Init SDIO driver and HW */ 302 iStatus = sdioDrv_ConnectBus (fCbFunc, hCbArg, uBlkSizeShift,uSdioThreadPriority, pTxDmaSrcAddr); 303 if (iStatus) { return iStatus; } 304 305 /* Send commands sequence: 0, 5, 3, 7 */ 306 iStatus = sdioDrv_ExecuteCmd (SD_IO_GO_IDLE_STATE, 0, MMC_RSP_NONE, &uByte, sizeof(uByte)); 307 if (iStatus) 308 { 309 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_GO_IDLE_STATE); 310 return iStatus; 311 } 312 iStatus = sdioDrv_ExecuteCmd (SDIO_CMD5, VDD_VOLTAGE_WINDOW, MMC_RSP_R4, &uByte, sizeof(uByte)); 313 if (iStatus) { 314 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SDIO_CMD5); 315 return iStatus; 316 } 317 318 iStatus = sdioDrv_ExecuteCmd (SD_IO_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6, &uLong, sizeof(uLong)); 319 if (iStatus) { 320 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SEND_RELATIVE_ADDR); 321 return iStatus; 322 } 323 iStatus = sdioDrv_ExecuteCmd (SD_IO_SELECT_CARD, uLong, MMC_RSP_R6, &uByte, sizeof(uByte)); 324 if (iStatus) { 325 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SELECT_CARD); 326 return iStatus; 327 } 328 329 /* NOTE: 330 * ===== 331 * Each of the following loops is a workaround for a HW bug that will be solved in PG1.1 !! 332 * Each write of CMD-52 to function-0 should use it as follows: 333 * 1) Write the desired byte using CMD-52 334 * 2) Read back the byte using CMD-52 335 * 3) Write two dummy bytes to address 0xC8 using CMD-53 336 * 4) If the byte read in step 2 is different than the written byte repeat the sequence 337 */ 338 339 /* set device side bus width to 4 bit (for 1 bit write 0x80 instead of 0x82) */ 340 do 341 { 342 uByte = SDIO_BITS_CODE; 343 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1); 344 if (iStatus) { return iStatus; } 345 346 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1); 347 if (iStatus) { return iStatus; } 348 349 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); 350 if (iStatus) { return iStatus; } 351 352 uCount++; 353 354 } while ((uByte != SDIO_BITS_CODE) && (uCount < MAX_RETRIES)); 355 356 357 uCount = 0; 358 359 /* allow function 2 */ 360 do 361 { 362 uByte = 4; 363 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1); 364 if (iStatus) { return iStatus; } 365 366 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1); 367 if (iStatus) { return iStatus; } 368 369 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); 370 if (iStatus) { return iStatus; } 371 372 uCount++; 373 374 } while ((uByte != 4) && (uCount < MAX_RETRIES)); 375 376 377#ifdef SDIO_IN_BAND_INTERRUPT 378 379 uCount = 0; 380 381 do 382 { 383 uByte = 3; 384 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1); 385 if (iStatus) { return iStatus; } 386 387 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1); 388 if (iStatus) { return iStatus; } 389 390 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); 391 if (iStatus) { return iStatus; } 392 393 uCount++; 394 395 } while ((uByte != 3) && (uCount < MAX_RETRIES)); 396 397 398#endif 399 400 uCount = 0; 401 402 /* set block size for SDIO block mode */ 403 do 404 { 405 uLong = uBlkSize; 406 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1); 407 if (iStatus) { return iStatus; } 408 409 iStatus = sdioDrv_ReadSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1); 410 if (iStatus) { return iStatus; } 411 412 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); 413 if (iStatus) { return iStatus; } 414 415 uCount++; 416 417 } while (((uLong & FN0_FBR2_REG_108_BIT_MASK) != uBlkSize) && (uCount < MAX_RETRIES)); 418 419 420 if (uCount >= MAX_RETRIES) 421 { 422 /* Failed to write CMD52_WRITE to function 0 */ 423 return (int)uCount; 424 } 425 426 return iStatus; 427} 428 429 430int sdioAdapt_DisconnectBus (void) 431{ 432 return sdioDrv_DisconnectBus (); 433} 434 435ETxnStatus sdioAdapt_Transact (unsigned int uFuncId, 436 unsigned int uHwAddr, 437 void * pHostAddr, 438 unsigned int uLength, 439 unsigned int bDirection, 440 unsigned int bBlkMode, 441 unsigned int bFixedAddr, 442 unsigned int bMore) 443{ 444 int iStatus; 445 446 /* If transction length is below threshold, use Sync methods */ 447 if (uLength < SYNC_ASYNC_LENGTH_THRESH) 448 { 449 /* Call read or write Sync method */ 450 if (bDirection) 451 { 452 CL_TRACE_START_L2(); 453 iStatus = sdioDrv_ReadSync (uFuncId, uHwAddr, pHostAddr, uLength, bFixedAddr, bMore); 454 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".ReadSync"); 455 } 456 else 457 { 458 CL_TRACE_START_L2(); 459 iStatus = sdioDrv_WriteSync (uFuncId, uHwAddr, pHostAddr, uLength, bFixedAddr, bMore); 460 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".WriteSync"); 461 } 462 463 /* If failed return ERROR, if succeeded return COMPLETE */ 464 if (iStatus) 465 { 466 return TXN_STATUS_ERROR; 467 } 468 return TXN_STATUS_COMPLETE; 469 } 470 471 /* If transction length is above threshold, use Async methods */ 472 else 473 { 474 /* Call read or write Async method */ 475 if (bDirection) 476 { 477 CL_TRACE_START_L2(); 478 iStatus = sdioDrv_ReadAsync (uFuncId, uHwAddr, pHostAddr, uLength, bBlkMode, bFixedAddr, bMore); 479 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".ReadAsync"); 480 } 481 else 482 { 483 CL_TRACE_START_L2(); 484 iStatus = sdioDrv_WriteAsync (uFuncId, uHwAddr, pHostAddr, uLength, bBlkMode, bFixedAddr, bMore); 485 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".WriteAsync"); 486 } 487 488 /* If failed return ERROR, if succeeded return PENDING */ 489 if (iStatus) 490 { 491 return TXN_STATUS_ERROR; 492 } 493 return TXN_STATUS_PENDING; 494 } 495} 496 497ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, 498 unsigned int uHwAddr, 499 void * pHostAddr, 500 unsigned int uLength, 501 unsigned int bDirection, 502 unsigned int bMore) 503{ 504 static unsigned int lastMore = 0; 505 int iStatus; 506 507 if ((bMore == 1) || (lastMore == bMore)) 508 { 509 sdioDrv_clk_enable(); 510 } 511 512 /* Call read or write bytes Sync method */ 513 if (bDirection) 514 { 515 iStatus = sdioDrv_ReadSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore); 516 } 517 else 518 { 519 iStatus = sdioDrv_WriteSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore); 520 } 521 522 if (bMore == 0) 523 { 524 sdioDrv_clk_disable(); 525 } 526 lastMore = bMore; 527 528 /* If failed return ERROR, if succeeded return COMPLETE */ 529 if (iStatus) 530 { 531 return TXN_STATUS_ERROR; 532 } 533 return TXN_STATUS_COMPLETE; 534} 535#endif 536