aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm4329/bcmsdspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm4329/bcmsdspi.c')
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdspi.c1596
1 files changed, 1596 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcm4329/bcmsdspi.c b/drivers/net/wireless/bcm4329/bcmsdspi.c
new file mode 100644
index 00000000000..636539be5ea
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdspi.c
@@ -0,0 +1,1596 @@
1/*
2 * Broadcom BCMSDH to SPI Protocol Conversion Layer
3 *
4 * Copyright (C) 1999-2010, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdspi.c,v 1.14.4.2.4.4.6.5 2010/03/10 03:09:48 Exp $
25 */
26
27#include <typedefs.h>
28
29#include <bcmdevs.h>
30#include <bcmendian.h>
31#include <bcmutils.h>
32#include <osl.h>
33#include <siutils.h>
34#include <sdio.h> /* SDIO Device and Protocol Specs */
35#include <sdioh.h> /* SDIO Host Controller Specification */
36#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
37#include <sdiovar.h> /* ioctl/iovars */
38
39#include <pcicfg.h>
40
41
42#include <bcmsdspi.h>
43#include <bcmspi.h>
44
45#include <proto/sdspi.h>
46
47#define SD_PAGE 4096
48
49/* Globals */
50
51uint sd_msglevel = SDH_ERROR_VAL;
52uint sd_hiok = FALSE; /* Use hi-speed mode if available? */
53uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */
54uint sd_f2_blocksize = 512; /* Default blocksize */
55
56uint sd_divisor = 2; /* Default 33MHz/2 = 16MHz for dongle */
57uint sd_power = 1; /* Default to SD Slot powered ON */
58uint sd_clock = 1; /* Default to SD Clock turned ON */
59uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */
60uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */
61
62uint sd_toctl = 7;
63
64/* Prototypes */
65static bool sdspi_start_power(sdioh_info_t *sd);
66static int sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode);
67static int sdspi_card_enablefuncs(sdioh_info_t *sd);
68static void sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count);
69static int sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg,
70 uint32 *data, uint32 datalen);
71static int sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
72 int regsize, uint32 *data);
73static int sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
74 int regsize, uint32 data);
75static int sdspi_driver_init(sdioh_info_t *sd);
76static bool sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset);
77static int sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
78 uint32 addr, int nbytes, uint32 *data);
79static int sdspi_abort(sdioh_info_t *sd, uint func);
80
81static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize);
82
83static uint8 sdspi_crc7(unsigned char* p, uint32 len);
84static uint16 sdspi_crc16(unsigned char* p, uint32 len);
85static int sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc);
86
87/*
88 * Public entry points & extern's
89 */
90extern sdioh_info_t *
91sdioh_attach(osl_t *osh, void *bar0, uint irq)
92{
93 sdioh_info_t *sd;
94
95 sd_trace(("%s\n", __FUNCTION__));
96 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
97 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
98 return NULL;
99 }
100 bzero((char *)sd, sizeof(sdioh_info_t));
101 sd->osh = osh;
102
103 if (spi_osinit(sd) != 0) {
104 sd_err(("%s: spi_osinit() failed\n", __FUNCTION__));
105 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
106 return NULL;
107 }
108
109 sd->bar0 = (uintptr)bar0;
110 sd->irq = irq;
111 sd->intr_handler = NULL;
112 sd->intr_handler_arg = NULL;
113 sd->intr_handler_valid = FALSE;
114
115 /* Set defaults */
116 sd->sd_blockmode = FALSE;
117 sd->use_client_ints = TRUE;
118 sd->sd_use_dma = FALSE; /* DMA Not supported */
119
120 /* Haven't figured out how to make bytemode work with dma */
121 if (!sd->sd_blockmode)
122 sd->sd_use_dma = 0;
123
124 if (!spi_hw_attach(sd)) {
125 sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__));
126 spi_osfree(sd);
127 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
128 return NULL;
129 }
130
131 if (sdspi_driver_init(sd) != SUCCESS) {
132 if (sdspi_driver_init(sd) != SUCCESS) {
133 sd_err(("%s:sdspi_driver_init() failed()\n", __FUNCTION__));
134 spi_hw_detach(sd);
135 spi_osfree(sd);
136 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
137 return (NULL);
138 }
139 }
140
141 if (spi_register_irq(sd, irq) != SUCCESS) {
142 sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
143 spi_hw_detach(sd);
144 spi_osfree(sd);
145 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
146 return (NULL);
147 }
148
149 sd_trace(("%s: Done\n", __FUNCTION__));
150 return sd;
151}
152
153extern SDIOH_API_RC
154sdioh_detach(osl_t *osh, sdioh_info_t *sd)
155{
156 sd_trace(("%s\n", __FUNCTION__));
157
158 if (sd) {
159 if (sd->card_init_done)
160 sdspi_reset(sd, 1, 1);
161
162 sd_info(("%s: detaching from hardware\n", __FUNCTION__));
163 spi_free_irq(sd->irq, sd);
164 spi_hw_detach(sd);
165 spi_osfree(sd);
166 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
167 }
168
169 return SDIOH_API_RC_SUCCESS;
170}
171
172/* Configure callback to client when we recieve client interrupt */
173extern SDIOH_API_RC
174sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
175{
176 sd_trace(("%s: Entering\n", __FUNCTION__));
177
178 sd->intr_handler = fn;
179 sd->intr_handler_arg = argh;
180 sd->intr_handler_valid = TRUE;
181
182 return SDIOH_API_RC_SUCCESS;
183}
184
185extern SDIOH_API_RC
186sdioh_interrupt_deregister(sdioh_info_t *sd)
187{
188 sd_trace(("%s: Entering\n", __FUNCTION__));
189
190 sd->intr_handler_valid = FALSE;
191 sd->intr_handler = NULL;
192 sd->intr_handler_arg = NULL;
193
194 return SDIOH_API_RC_SUCCESS;
195}
196
197extern SDIOH_API_RC
198sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
199{
200 sd_trace(("%s: Entering\n", __FUNCTION__));
201
202 *onoff = sd->client_intr_enabled;
203
204 return SDIOH_API_RC_SUCCESS;
205}
206
207#if defined(DHD_DEBUG)
208extern bool