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_KERNEL | 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#include <linux/slab.h>
259
260#ifdef SDIO_1_BIT /* see also in SdioDrv.c */
261#define SDIO_BITS_CODE   0x80 /* 1 bits */
262#else
263#define SDIO_BITS_CODE   0x82 /* 4 bits */
264#endif
265
266static unsigned char *pDmaBufAddr = 0;
267
268/************************************************************************
269 * Defines
270 ************************************************************************/
271/* Sync/Async Threshold */
272#ifdef FULL_ASYNC_MODE
273#define SYNC_ASYNC_LENGTH_THRESH	0     /* Use Async for all transactions */
274#else
275#define SYNC_ASYNC_LENGTH_THRESH	360   /* Use Async for transactions longer than this threshold (in bytes) */
276#endif
277
278#define MAX_RETRIES                 10
279
280#define MAX_BUS_TXN_SIZE            8192  /* Max bus transaction size in bytes (for the DMA buffer allocation) */
281
282/* For block mode configuration */
283#define FN0_FBR2_REG_108                    0x210
284#define FN0_FBR2_REG_108_BIT_MASK           0xFFF
285
286int sdioAdapt_ConnectBus (void *        fCbFunc,
287                          void *        hCbArg,
288                          unsigned int  uBlkSizeShift,
289                          unsigned int  uSdioThreadPriority,
290                          unsigned char **pRxDmaBufAddr,
291                          unsigned int  *pRxDmaBufLen,
292                          unsigned char **pTxDmaBufAddr,
293                          unsigned int  *pTxDmaBufLen)
294{
295	unsigned char  uByte;
296	unsigned long  uLong;
297	unsigned long  uCount = 0;
298	unsigned int   uBlkSize = 1 << uBlkSizeShift;
299	int            iStatus;
300
301	if (uBlkSize < SYNC_ASYNC_LENGTH_THRESH)
302	{
303		PERR1("%s(): Block-Size should be bigger than SYNC_ASYNC_LENGTH_THRESH!!\n", __FUNCTION__ );
304	}
305
306	/* Enabling clocks if thet are not enabled */
307	sdioDrv_clk_enable();
308
309	/* Allocate a DMA-able buffer and provide it to the upper layer to be used for all read and write transactions */
310	if (pDmaBufAddr == 0) /* allocate only once (in case this function is called multiple times) */
311	{
312		pDmaBufAddr = kmalloc(MAX_BUS_TXN_SIZE, GFP_KERNEL | GFP_DMA);
313		if (pDmaBufAddr == 0)
314		{
315			iStatus = -1;
316			goto fail;
317		}
318	}
319	*pRxDmaBufAddr = *pTxDmaBufAddr = pDmaBufAddr;
320	*pRxDmaBufLen  = *pTxDmaBufLen  = MAX_BUS_TXN_SIZE;
321
322	/* Init SDIO driver and HW */
323	iStatus = sdioDrv_ConnectBus (fCbFunc, hCbArg, uBlkSizeShift, uSdioThreadPriority);
324	if (iStatus) { goto fail; }
325
326	/* Send commands sequence: 0, 5, 3, 7 */
327	iStatus = sdioDrv_ExecuteCmd (SD_IO_GO_IDLE_STATE, 0, MMC_RSP_NONE, &uByte, sizeof(uByte));
328	if (iStatus)
329	{
330		printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_GO_IDLE_STATE);
331		goto fail;
332	}
333
334	iStatus = sdioDrv_ExecuteCmd (SDIO_CMD5, VDD_VOLTAGE_WINDOW, MMC_RSP_R4, &uByte, sizeof(uByte));
335	if (iStatus) {
336		printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SDIO_CMD5);
337		goto fail;
338	}
339
340	iStatus = sdioDrv_ExecuteCmd (SD_IO_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6, &uLong, sizeof(uLong));
341	if (iStatus) {
342		printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SEND_RELATIVE_ADDR);
343		goto fail;
344	}
345
346	iStatus = sdioDrv_ExecuteCmd (SD_IO_SELECT_CARD, uLong, MMC_RSP_R6, &uByte, sizeof(uByte));
347	if (iStatus) {
348		printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SELECT_CARD);
349		goto fail;
350	}
351
352    /* NOTE:
353     * =====
354     * Each of the following loops is a workaround for a HW bug that will be solved in PG1.1 !!
355     * Each write of CMD-52 to function-0 should use it as follows:
356     * 1) Write the desired byte using CMD-52
357     * 2) Read back the byte using CMD-52
358     * 3) Write two dummy bytes to address 0xC8 using CMD-53
359     * 4) If the byte read in step 2 is different than the written byte repeat the sequence
360     */
361
362	/* set device side bus width to 4 bit (for 1 bit write 0x80 instead of 0x82) */
363	do
364	{
365		uByte = SDIO_BITS_CODE;
366		iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1);
367		if (iStatus) { goto fail; }
368
369		iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1);
370		if (iStatus) { goto fail; }
371
372		iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1);
373		if (iStatus) { goto fail; }
374
375		uCount++;
376
377	} while ((uByte != SDIO_BITS_CODE) && (uCount < MAX_RETRIES));
378
379	uCount = 0;
380
381	/* allow function 2 */
382	do
383	{
384		uByte = 4;
385		iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1);
386		if (iStatus) { goto fail; }
387
388		iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1);
389		if (iStatus) { goto fail; }
390
391		iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1);
392		if (iStatus) { goto fail; }
393
394		uCount++;
395
396	} while ((uByte != 4) && (uCount < MAX_RETRIES));
397
398
399#ifdef SDIO_IN_BAND_INTERRUPT
400
401	uCount = 0;
402
403	do
404	{
405		uByte = 3;
406		iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1);
407		if (iStatus) { goto fail; }
408
409		iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1);
410		if (iStatus) { goto fail; }
411
412		iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1);
413		if (iStatus) { goto fail; }
414
415		uCount++;
416
417	} while ((uByte != 3) && (uCount < MAX_RETRIES));
418
419
420#endif
421
422	uCount = 0;
423
424	/* set block size for SDIO block mode */
425	do
426	{
427		uLong = uBlkSize;
428		iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1);
429		if (iStatus) { goto fail; }
430
431		iStatus = sdioDrv_ReadSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1);
432		if (iStatus) { goto fail; }
433
434		iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1);
435		if (iStatus) { goto fail; }
436
437		uCount++;
438
439	} while (((uLong & FN0_FBR2_REG_108_BIT_MASK) != uBlkSize) && (uCount < MAX_RETRIES));
440
441	if (uCount >= MAX_RETRIES)
442	{
443		/* Failed to write CMD52_WRITE to function 0 */
444		iStatus = (int)uCount;
445	}
446
447fail:
448	/* Disable the clocks for now */
449	sdioDrv_clk_disable();
450
451	return iStatus;
452}
453
454
455int sdioAdapt_DisconnectBus (void)
456{
457	if (pDmaBufAddr)
458	{
459		kfree (pDmaBufAddr);
460		pDmaBufAddr = 0;
461	}
462
463	return sdioDrv_DisconnectBus ();
464}
465
466ETxnStatus sdioAdapt_Transact (unsigned int  uFuncId,
467                               unsigned int  uHwAddr,
468                               void *        pHostAddr,
469                               unsigned int  uLength,
470                               unsigned int  bDirection,
471                               unsigned int  bBlkMode,
472                               unsigned int  bFixedAddr,
473                               unsigned int  bMore)
474{
475	int iStatus;
476
477	/* If transction length is below threshold, use Sync methods */
478	if (uLength < SYNC_ASYNC_LENGTH_THRESH)
479	{
480		/* Call read or write Sync method */
481		if (bDirection)
482		{
483			CL_TRACE_START_L2();
484			iStatus = sdioDrv_ReadSync (uFuncId, uHwAddr, pHostAddr, uLength, bFixedAddr, bMore);
485			CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".ReadSync");
486		}
487		else
488		{
489			CL_TRACE_START_L2();
490			iStatus = sdioDrv_WriteSync (uFuncId, uHwAddr, pHostAddr, uLength, bFixedAddr, bMore);
491			CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".WriteSync");
492		}
493
494		/* If failed return ERROR, if succeeded return COMPLETE */
495		if (iStatus)
496		{
497			return TXN_STATUS_ERROR;
498		}
499		return TXN_STATUS_COMPLETE;
500	}
501
502	/* If transction length is above threshold, use Async methods */
503	else
504	{
505		/* Call read or write Async method */
506		if (bDirection)
507		{
508			CL_TRACE_START_L2();
509			iStatus = sdioDrv_ReadAsync (uFuncId, uHwAddr, pHostAddr, uLength, bBlkMode, bFixedAddr, bMore);
510			CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".ReadAsync");
511		}
512		else
513		{
514			CL_TRACE_START_L2();
515			iStatus = sdioDrv_WriteAsync (uFuncId, uHwAddr, pHostAddr, uLength, bBlkMode, bFixedAddr, bMore);
516			CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".WriteAsync");
517		}
518
519		/* If failed return ERROR, if succeeded return PENDING */
520		if (iStatus)
521		{
522			return TXN_STATUS_ERROR;
523		}
524		return TXN_STATUS_PENDING;
525	}
526}
527
528ETxnStatus sdioAdapt_TransactBytes (unsigned int  uFuncId,
529                                    unsigned int  uHwAddr,
530                                    void *        pHostAddr,
531                                    unsigned int  uLength,
532                                    unsigned int  bDirection,
533                                    unsigned int  bMore)
534{
535	static unsigned int lastMore = 0;
536	int iStatus;
537
538	if ((bMore == 1) || (lastMore == bMore))
539	{
540		sdioDrv_cancel_inact_timer();
541		sdioDrv_clk_enable();
542	}
543
544	/* Call read or write bytes Sync method */
545	if (bDirection)
546	{
547		iStatus = sdioDrv_ReadSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore);
548	}
549	else
550	{
551		iStatus = sdioDrv_WriteSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore);
552	}
553
554	if (bMore == 0)
555	{
556		sdioDrv_start_inact_timer();
557	}
558	lastMore = bMore;
559
560	/* If failed return ERROR, if succeeded return COMPLETE */
561	if (iStatus)
562	{
563		return TXN_STATUS_ERROR;
564	}
565	return TXN_STATUS_COMPLETE;
566}
567#endif
568