Home | History | Annotate | Download | only in src
      1 /* tnetw_sdio.c
      2  *
      3  * This program is free software; you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License version 2 as
      5  * published by the Free Software Foundation.
      6  *
      7  * Copyright  Texas Instruments Incorporated (Oct 2005)
      8  * THIS CODE/PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
      9  * EITHER EXPRESS OR IMPLIED, INCLUDED BUT NOT LIMITED TO , THE IMPLIED
     10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     11  * This program has been modified from its original operation by Texas
     12  * Instruments Incorporated. These changes are covered under version 2
     13  * of the GNU General Public License, dated June 1991.
     14  *
     15  * Copyright  Google Inc (Feb 2008)
     16  */
     17 /*-------------------------------------------------------------------*/
     18 #ifdef TIWLAN_MSM7000
     19 #include <linux/mm.h>
     20 #include <linux/vmalloc.h>
     21 #include <linux/pagemap.h>
     22 #include <asm/pgtable.h>
     23 #include <asm/cacheflush.h>
     24 
     25 #include <linux/delay.h>
     26 #include <linux/mmc/core.h>
     27 #include <linux/mmc/card.h>
     28 #include <linux/mmc/host.h>
     29 #include <linux/mmc/sdio_func.h>
     30 #include <linux/mmc/sdio_ids.h>
     31 #include "esta_drv.h"
     32 #include "mmc_omap_api.h"
     33 #include "osApi.h"
     34 
     35 /*-------------------------------------------------------------------*/
     36 extern int tiwlan_sdio_init(struct sdio_func *func);
     37 extern int sdio_reset_comm(struct mmc_card *card);
     38 
     39 /*-------------------------------------------------------------------*/
     40 static struct sdio_func *tiwlan_func = NULL;
     41 static int sdio_reset_flag = 0;
     42 
     43 #define DMA_THRESHOLD_SIZE  64
     44 static void *sdio_dma_ptr = NULL;
     45 #define USE_SKETCHY_WRITES 0
     46 
     47 /*-------------------------------------------------------------------*/
     48 void SDIO_SetFunc( struct sdio_func *func )
     49 {
     50 	tiwlan_func = func;
     51 }
     52 
     53 struct sdio_func *SDIO_GetFunc( void )
     54 {
     55 	return tiwlan_func;
     56 }
     57 
     58 SDIO_Status SDIO_Init(SDIO_ConfigParams *ConfigParams, SDIO_Handle *Handle)
     59 {
     60 	if (Handle == NULL) {
     61 		printk(KERN_ERR "Error: SDIO_Init() called with NULL!\n");
     62 		return SDIO_FAILURE;
     63 	}
     64 
     65 	*Handle = (SDIO_Handle)SDIO_GetFunc();
     66 	if ((*Handle) == NULL) {
     67 		printk(KERN_ERR "SDIO_Init() called before init!\n");
     68 		return SDIO_FAILURE;
     69 	}
     70 
     71 	if (!sdio_dma_ptr) {
     72 		if (!(sdio_dma_ptr = kmalloc(PAGE_SIZE, GFP_KERNEL))) {
     73 			printk(KERN_ERR "Failed to alloc DMA bounce buffer\n");
     74 			return SDIO_FAILURE;
     75 		}
     76 	}
     77 	return SDIO_SUCCESS;
     78 }
     79 
     80 SDIO_Status SDIO_Shutdown(SDIO_Handle Handle)
     81 {
     82 	if (sdio_dma_ptr) {
     83 		kfree(sdio_dma_ptr);
     84 		sdio_dma_ptr = NULL;
     85 	}
     86 	return SDIO_SUCCESS;
     87 }
     88 
     89 SDIO_Status SDIO_Start(SDIO_Handle Handle)
     90 {
     91 	struct sdio_func *func = (struct sdio_func *)Handle;
     92 
     93 	if (func) {
     94 		if (sdio_reset_flag) {
     95 			sdio_reset_flag = 0;
     96 			if (tiwlan_sdio_init(func)) {
     97 				printk("TI: tiwlan_sdio_init Error!\n");
     98 				return SDIO_FAILURE;
     99 			}
    100 
    101 		}
    102 	}
    103 	return SDIO_SUCCESS;
    104 }
    105 
    106 SDIO_Status SDIO_Reset(SDIO_Handle Handle)
    107 {
    108 	struct sdio_func *func = (struct sdio_func *)Handle;
    109 
    110 	if (func && func->card) {
    111 		sdio_release_host(func);
    112 		sdio_reset_comm(func->card);
    113 		sdio_claim_host(func);
    114 	}
    115 	return SDIO_SUCCESS;
    116 }
    117 
    118 SDIO_Status SDIO_Stop(SDIO_Handle Handle, unsigned long Wait_Window)
    119 {
    120 	sdio_reset_flag = 1;
    121 	return SDIO_Reset(Handle);
    122 }
    123 
    124 static inline int spans_page(void *s, int len)
    125 {
    126 	if (((unsigned long) s + len) <= ((((unsigned long) s) & ~(PAGE_SIZE-1)) + PAGE_SIZE))
    127 		return 0;
    128 	return 1;
    129 }
    130 
    131 static void *vmalloc_to_unity(void *a)
    132 {
    133 	struct page *pg;
    134 	unsigned long virt = (unsigned long) a;
    135 
    136 	pg = vmalloc_to_page(a);
    137 	virt = (unsigned long)page_address(pg) | (virt & (PAGE_SIZE -1));
    138 	return (void *)virt;
    139 }
    140 
    141 SDIO_Status SDIO_SyncRead(SDIO_Handle Handle, SDIO_Request_t *Req)
    142 {
    143 	struct sdio_func *func = (struct sdio_func *)Handle;
    144 	int rc;
    145 	void *tgt = Req->buffer;
    146 
    147 	if (Req->buffer_len >= DMA_THRESHOLD_SIZE) {
    148 		if (is_vmalloc_addr(tgt)) {
    149 			if (!spans_page(tgt, Req->buffer_len)) {
    150 				tgt = vmalloc_to_unity(tgt);
    151 				dmac_flush_range(Req->buffer,
    152 						 Req->buffer + Req->buffer_len);
    153 			} else
    154 				tgt = sdio_dma_ptr;
    155 		}
    156 	}
    157 
    158 	if ((rc = sdio_memcpy_fromio(func, tgt, Req->peripheral_addr,
    159 				     Req->buffer_len))) {
    160 		printk(KERN_ERR "%s: failed (%d)\n", __func__, rc);
    161 		return SDIO_FAILURE;
    162 	}
    163 
    164 	if (tgt == sdio_dma_ptr)
    165 		memcpy(Req->buffer, sdio_dma_ptr, Req->buffer_len);
    166 
    167 	return SDIO_SUCCESS;
    168 }
    169 
    170 SDIO_Status SDIO_SyncWrite(SDIO_Handle Handle, SDIO_Request_t *Req)
    171 {
    172 	struct sdio_func *func = (struct sdio_func *)Handle;
    173 	int rc;
    174 	void *src = Req->buffer;
    175 
    176 	if (Req->buffer_len >= DMA_THRESHOLD_SIZE) {
    177 #if USE_SKETCHY_WRITES
    178 		if (is_vmalloc_addr(src)) {
    179 			if (!spans_page(src, Req->buffer_len)) {
    180 				src = vmalloc_to_unity(src);
    181 				dmac_clean_range(Req->buffer,
    182 						 Req->buffer + Req->buffer_len);
    183 			} else {
    184 #endif
    185 				src = sdio_dma_ptr;
    186 				memcpy(src, Req->buffer, Req->buffer_len);
    187 #if USE_SKETCHY_WRITES
    188 			}
    189 		}
    190 #endif
    191 	}
    192 
    193 	rc = sdio_memcpy_toio(func, Req->peripheral_addr, src,
    194 			      Req->buffer_len);
    195 
    196 	if (!rc)
    197 		return SDIO_SUCCESS;
    198 
    199 	printk(KERN_ERR "%s: failed (%d)\n", __func__, rc);
    200 	return SDIO_FAILURE;
    201 }
    202 #endif
    203