blob: 6b2a4505d3c8b1bbcd4b46c6656b22b71bc918ae [file] [log] [blame]
Henry Ptasinskicf2b4482010-09-20 22:33:12 -07001/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
Greg Kroah-Hartmana1c16ed2010-10-21 11:17:44 -070016#include <linux/types.h>
Brett Rudleyc6ac24e2010-10-26 11:55:23 -070017#include <linux/netdevice.h>
Franky Lin0df46042011-06-01 13:45:40 +020018#include <linux/mmc/sdio.h>
Greg Kroah-Hartmana1c16ed2010-10-21 11:17:44 -070019#include <bcmdefs.h>
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070020#include <bcmdevs.h>
Brett Rudley7f7c3db2010-10-26 15:23:09 -070021#include <bcmutils.h>
Franky Lin7c6100e2011-06-01 13:45:36 +020022#include <bcmwifi.h>
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070023#include <sdioh.h> /* SDIO Host Controller Specification */
24#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
25#include <sdiovar.h> /* ioctl/iovars */
26
27#include <linux/mmc/core.h>
28#include <linux/mmc/sdio_func.h>
29#include <linux/mmc/sdio_ids.h>
Sukesh Srikakulae6e8f892011-05-13 11:59:39 +020030#include <linux/suspend.h>
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070031
32#include <dngl_stats.h>
33#include <dhd.h>
34
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070035#include "bcmsdh_sdmmc.h"
36
37extern int sdio_function_init(void);
38extern void sdio_function_cleanup(void);
39
40#if !defined(OOB_INTR_ONLY)
41static void IRQHandler(struct sdio_func *func);
42static void IRQHandlerF2(struct sdio_func *func);
43#endif /* !defined(OOB_INTR_ONLY) */
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -070044static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, u32 regaddr);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070045extern int sdio_reset_comm(struct mmc_card *card);
46
47extern PBCMSDH_SDMMC_INSTANCE gInstance;
48
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070049uint sd_f2_blocksize = 512; /* Default blocksize */
50
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070051uint sd_msglevel = 0x01;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070052DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
53DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
54DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
55DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
56
57#define DMA_ALIGN_MASK 0x03
58
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -070059int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, u32 regaddr,
60 int regsize, u32 *data);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070061
Grant Grundler6b5a5a32011-03-18 15:56:57 -070062void sdioh_sdio_set_host_pm_flags(int flag)
63{
64 if (sdio_set_host_pm_flags(gInstance->func[1], flag))
65 printk(KERN_ERR "%s: Failed to set pm_flags 0x%08x\n",\
66 __func__, (unsigned int)flag);
67}
68
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070069static int sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
70{
71 int err_ret;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -070072 u32 fbraddr;
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -070073 u8 func;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070074
75 sd_trace(("%s\n", __func__));
76
77 /* Get the Card's common CIS address */
Franky Lin0df46042011-06-01 13:45:40 +020078 sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIO_CCCR_CIS);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070079 sd->func_cis_ptr[0] = sd->com_cis_ptr;
80 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__,
81 sd->com_cis_ptr));
82
83 /* Get the Card's function CIS (for each function) */
Franky Lin0df46042011-06-01 13:45:40 +020084 for (fbraddr = SDIO_FBR_BASE(1), func = 1;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070085 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
86 sd->func_cis_ptr[func] =
Franky Lin0df46042011-06-01 13:45:40 +020087 sdioh_sdmmc_get_cisaddr(sd, SDIO_FBR_CIS + fbraddr);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -070088 sd_info(("%s: Function %d CIS Ptr = 0x%x\n", __func__, func,
89 sd->func_cis_ptr[func]));
90 }
91
92 sd->func_cis_ptr[0] = sd->com_cis_ptr;
93 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__,
94 sd->com_cis_ptr));
95
96 /* Enable Function 1 */
97 sdio_claim_host(gInstance->func[1]);
98 err_ret = sdio_enable_func(gInstance->func[1]);
99 sdio_release_host(gInstance->func[1]);
100 if (err_ret) {
101 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x",
102 err_ret));
103 }
104
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700105 return false;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700106}
107
108/*
109 * Public entry points & extern's
110 */
Arend van Spriel3c9d4c32011-03-02 21:18:48 +0100111sdioh_info_t *sdioh_attach(void *bar0, uint irq)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700112{
113 sdioh_info_t *sd;
114 int err_ret;
115
116 sd_trace(("%s\n", __func__));
117
118 if (gInstance == NULL) {
119 sd_err(("%s: SDIO Device not present\n", __func__));
120 return NULL;
121 }
122
mike.rapoport@gmail.com5fcc1fc2010-10-13 00:09:10 +0200123 sd = kzalloc(sizeof(sdioh_info_t), GFP_ATOMIC);
Jason Coopera1b04b02010-09-30 15:15:37 -0400124 if (sd == NULL) {
mike.rapoport@gmail.com97e17d02010-10-13 00:09:09 +0200125 sd_err(("sdioh_attach: out of memory\n"));
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700126 return NULL;
127 }
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700128 if (sdioh_sdmmc_osinit(sd) != 0) {
129 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __func__));
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200130 kfree(sd);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700131 return NULL;
132 }
133
134 sd->num_funcs = 2;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700135 sd->use_client_ints = true;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700136 sd->client_block_size[0] = 64;
137
138 gInstance->sd = sd;
139
140 /* Claim host controller */
141 sdio_claim_host(gInstance->func[1]);
142
143 sd->client_block_size[1] = 64;
144 err_ret = sdio_set_block_size(gInstance->func[1], 64);
145 if (err_ret)
146 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
147
148 /* Release host controller F1 */
149 sdio_release_host(gInstance->func[1]);
150
151 if (gInstance->func[2]) {
152 /* Claim host controller F2 */
153 sdio_claim_host(gInstance->func[2]);
154
155 sd->client_block_size[2] = sd_f2_blocksize;
156 err_ret =
157 sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
158 if (err_ret)
159 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize "
160 "to %d\n", sd_f2_blocksize));
161
162 /* Release host controller F2 */
163 sdio_release_host(gInstance->func[2]);
164 }
165
166 sdioh_sdmmc_card_enablefuncs(sd);
167
168 sd_trace(("%s: Done\n", __func__));
169 return sd;
170}
171
Arend van Spriel8da4a3a2011-03-02 21:18:42 +0100172extern SDIOH_API_RC sdioh_detach(sdioh_info_t *sd)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700173{
174 sd_trace(("%s\n", __func__));
175
176 if (sd) {
177
178 /* Disable Function 2 */
179 sdio_claim_host(gInstance->func[2]);
180 sdio_disable_func(gInstance->func[2]);
181 sdio_release_host(gInstance->func[2]);
182
183 /* Disable Function 1 */
184 sdio_claim_host(gInstance->func[1]);
185 sdio_disable_func(gInstance->func[1]);
186 sdio_release_host(gInstance->func[1]);
187
188 /* deregister irq */
189 sdioh_sdmmc_osfree(sd);
190
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200191 kfree(sd);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700192 }
193 return SDIOH_API_RC_SUCCESS;
194}
195
196#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
197
198extern SDIOH_API_RC sdioh_enable_func_intr(void)
199{
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700200 u8 reg;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700201 int err;
202
203 if (gInstance->func[0]) {
204 sdio_claim_host(gInstance->func[0]);
205
206 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
207 if (err) {
208 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n",
209 __func__, err));
210 sdio_release_host(gInstance->func[0]);
211 return SDIOH_API_RC_FAIL;
212 }
213
214 /* Enable F1 and F2 interrupts, set master enable */
215 reg |=
216 (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN |
217 INTR_CTL_MASTER_EN);
218
219 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
220 sdio_release_host(gInstance->func[0]);
221
222 if (err) {
223 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n",
224 __func__, err));
225 return SDIOH_API_RC_FAIL;
226 }
227 }
228
229 return SDIOH_API_RC_SUCCESS;
230}
231
232extern SDIOH_API_RC sdioh_disable_func_intr(void)
233{
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700234 u8 reg;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700235 int err;
236
237 if (gInstance->func[0]) {
238 sdio_claim_host(gInstance->func[0]);
239 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
240 if (err) {
241 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n",
242 __func__, err));
243 sdio_release_host(gInstance->func[0]);
244 return SDIOH_API_RC_FAIL;
245 }
246
247 reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
248 /* Disable master interrupt with the last function interrupt */
249 if (!(reg & 0xFE))
250 reg = 0;
251 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
252
253 sdio_release_host(gInstance->func[0]);
254 if (err) {
255 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n",
256 __func__, err));
257 return SDIOH_API_RC_FAIL;
258 }
259 }
260 return SDIOH_API_RC_SUCCESS;
261}
262#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
263
Peter Hueweb3b97f52011-03-26 02:17:52 +0100264/* Configure callback to client when we receive client interrupt */
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700265extern SDIOH_API_RC
266sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
267{
268 sd_trace(("%s: Entering\n", __func__));
269 if (fn == NULL) {
270 sd_err(("%s: interrupt handler is NULL, not registering\n",
271 __func__));
272 return SDIOH_API_RC_FAIL;
273 }
274#if !defined(OOB_INTR_ONLY)
275 sd->intr_handler = fn;
276 sd->intr_handler_arg = argh;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700277 sd->intr_handler_valid = true;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700278
279 /* register and unmask irq */
280 if (gInstance->func[2]) {
281 sdio_claim_host(gInstance->func[2]);
282 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
283 sdio_release_host(gInstance->func[2]);
284 }
285
286 if (gInstance->func[1]) {
287 sdio_claim_host(gInstance->func[1]);
288 sdio_claim_irq(gInstance->func[1], IRQHandler);
289 sdio_release_host(gInstance->func[1]);
290 }
291#elif defined(HW_OOB)
292 sdioh_enable_func_intr();
293#endif /* defined(OOB_INTR_ONLY) */
294 return SDIOH_API_RC_SUCCESS;
295}
296
297extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *sd)
298{
299 sd_trace(("%s: Entering\n", __func__));
300
301#if !defined(OOB_INTR_ONLY)
302 if (gInstance->func[1]) {
303 /* register and unmask irq */
304 sdio_claim_host(gInstance->func[1]);
305 sdio_release_irq(gInstance->func[1]);
306 sdio_release_host(gInstance->func[1]);
307 }
308
309 if (gInstance->func[2]) {
310 /* Claim host controller F2 */
311 sdio_claim_host(gInstance->func[2]);
312 sdio_release_irq(gInstance->func[2]);
313 /* Release host controller F2 */
314 sdio_release_host(gInstance->func[2]);
315 }
316
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700317 sd->intr_handler_valid = false;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700318 sd->intr_handler = NULL;
319 sd->intr_handler_arg = NULL;
320#elif defined(HW_OOB)
321 sdioh_disable_func_intr();
322#endif /* !defined(OOB_INTR_ONLY) */
323 return SDIOH_API_RC_SUCCESS;
324}
325
326extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
327{
328 sd_trace(("%s: Entering\n", __func__));
329 *onoff = sd->client_intr_enabled;
330 return SDIOH_API_RC_SUCCESS;
331}
332
333#if defined(DHD_DEBUG)
334extern bool sdioh_interrupt_pending(sdioh_info_t *sd)
335{
336 return 0;
337}
338#endif
339
340uint sdioh_query_iofnum(sdioh_info_t *sd)
341{
342 return sd->num_funcs;
343}
344
345/* IOVar table */
346enum {
347 IOV_MSGLEVEL = 1,
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700348 IOV_BLOCKSIZE,
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700349 IOV_USEINTS,
350 IOV_NUMINTS,
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700351 IOV_DEVREG,
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700352 IOV_HCIREGS,
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700353 IOV_RXCHAIN
354};
355
356const bcm_iovar_t sdioh_iovars[] = {
357 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0},
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700358 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0},/* ((fn << 16) |
359 size) */
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700360 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0},
361 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0},
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700362 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t)}
363 ,
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700364 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0}
365 ,
366 {NULL, 0, 0, 0, 0}
367};
368
369int
370sdioh_iovar_op(sdioh_info_t *si, const char *name,
371 void *params, int plen, void *arg, int len, bool set)
372{
373 const bcm_iovar_t *vi = NULL;
374 int bcmerror = 0;
375 int val_size;
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -0700376 s32 int_val = 0;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700377 bool bool_val;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700378 u32 actionid;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700379
380 ASSERT(name);
381 ASSERT(len >= 0);
382
383 /* Get must have return space; Set does not take qualifiers */
384 ASSERT(set || (arg && len));
385 ASSERT(!set || (!params && !plen));
386
387 sd_trace(("%s: Enter (%s %s)\n", __func__, (set ? "set" : "get"),
388 name));
389
Jason Coopera1b04b02010-09-30 15:15:37 -0400390 vi = bcm_iovar_lookup(sdioh_iovars, name);
391 if (vi == NULL) {
Roland Vossene10d82d2011-05-03 11:35:19 +0200392 bcmerror = -ENOTSUPP;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700393 goto exit;
394 }
395
Jason Coopera1b04b02010-09-30 15:15:37 -0400396 bcmerror = bcm_iovar_lencheck(vi, arg, len, set);
397 if (bcmerror != 0)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700398 goto exit;
399
400 /* Set up params so get and set can share the convenience variables */
401 if (params == NULL) {
402 params = arg;
403 plen = len;
404 }
405
406 if (vi->type == IOVT_VOID)
407 val_size = 0;
408 else if (vi->type == IOVT_BUFFER)
409 val_size = len;
410 else
411 val_size = sizeof(int);
412
413 if (plen >= (int)sizeof(int_val))
Stanislav Fomichev02160692011-02-15 01:05:10 +0300414 memcpy(&int_val, params, sizeof(int_val));
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700415
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700416 bool_val = (int_val != 0) ? true : false;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700417
418 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
419 switch (actionid) {
420 case IOV_GVAL(IOV_MSGLEVEL):
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -0700421 int_val = (s32) sd_msglevel;
Stanislav Fomichev02160692011-02-15 01:05:10 +0300422 memcpy(arg, &int_val, val_size);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700423 break;
424
425 case IOV_SVAL(IOV_MSGLEVEL):
426 sd_msglevel = int_val;
427 break;
428
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700429 case IOV_GVAL(IOV_BLOCKSIZE):
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700430 if ((u32) int_val > si->num_funcs) {
Roland Vossene10d82d2011-05-03 11:35:19 +0200431 bcmerror = -EINVAL;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700432 break;
433 }
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -0700434 int_val = (s32) si->client_block_size[int_val];
Stanislav Fomichev02160692011-02-15 01:05:10 +0300435 memcpy(arg, &int_val, val_size);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700436 break;
437
438 case IOV_SVAL(IOV_BLOCKSIZE):
439 {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700440 uint func = ((u32) int_val >> 16);
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700441 uint blksize = (u16) int_val;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700442 uint maxsize;
443
444 if (func > si->num_funcs) {
Roland Vossene10d82d2011-05-03 11:35:19 +0200445 bcmerror = -EINVAL;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700446 break;
447 }
448
449 switch (func) {
450 case 0:
451 maxsize = 32;
452 break;
453 case 1:
454 maxsize = BLOCK_SIZE_4318;
455 break;
456 case 2:
457 maxsize = BLOCK_SIZE_4328;
458 break;
459 default:
460 maxsize = 0;
461 }
462 if (blksize > maxsize) {
Roland Vossene10d82d2011-05-03 11:35:19 +0200463 bcmerror = -EINVAL;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700464 break;
465 }
466 if (!blksize)
467 blksize = maxsize;
468
469 /* Now set it */
470 si->client_block_size[func] = blksize;
471
472 break;
473 }
474
475 case IOV_GVAL(IOV_RXCHAIN):
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700476 int_val = false;
Stanislav Fomichev02160692011-02-15 01:05:10 +0300477 memcpy(arg, &int_val, val_size);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700478 break;
479
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700480 case IOV_GVAL(IOV_USEINTS):
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -0700481 int_val = (s32) si->use_client_ints;
Stanislav Fomichev02160692011-02-15 01:05:10 +0300482 memcpy(arg, &int_val, val_size);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700483 break;
484
485 case IOV_SVAL(IOV_USEINTS):
486 si->use_client_ints = (bool) int_val;
487 if (si->use_client_ints)
488 si->intmask |= CLIENT_INTR;
489 else
490 si->intmask &= ~CLIENT_INTR;
491
492 break;
493
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700494 case IOV_GVAL(IOV_NUMINTS):
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -0700495 int_val = (s32) si->intrcount;
Stanislav Fomichev02160692011-02-15 01:05:10 +0300496 memcpy(arg, &int_val, val_size);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700497 break;
498
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700499 case IOV_GVAL(IOV_DEVREG):
500 {
501 sdreg_t *sd_ptr = (sdreg_t *) params;
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700502 u8 data = 0;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700503
504 if (sdioh_cfg_read
505 (si, sd_ptr->func, sd_ptr->offset, &data)) {
Roland Vossenb74ac122011-05-03 11:35:20 +0200506 bcmerror = -EIO;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700507 break;
508 }
509
510 int_val = (int)data;
Stanislav Fomichev02160692011-02-15 01:05:10 +0300511 memcpy(arg, &int_val, sizeof(int_val));
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700512 break;
513 }
514
515 case IOV_SVAL(IOV_DEVREG):
516 {
517 sdreg_t *sd_ptr = (sdreg_t *) params;
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700518 u8 data = (u8) sd_ptr->value;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700519
520 if (sdioh_cfg_write
521 (si, sd_ptr->func, sd_ptr->offset, &data)) {
Roland Vossenb74ac122011-05-03 11:35:20 +0200522 bcmerror = -EIO;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700523 break;
524 }
525 break;
526 }
527
528 default:
Roland Vossene10d82d2011-05-03 11:35:19 +0200529 bcmerror = -ENOTSUPP;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700530 break;
531 }
532exit:
533
534 return bcmerror;
535}
536
537#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
538
539SDIOH_API_RC sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
540{
541 SDIOH_API_RC status;
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700542 u8 data;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700543
544 if (enable)
545 data = 3; /* enable hw oob interrupt */
546 else
547 data = 4; /* disable hw oob interrupt */
548 data |= 4; /* Active HIGH */
549
550 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data);
551 return status;
552}
553#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
554
555extern SDIOH_API_RC
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700556sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, u32 addr, u8 *data)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700557{
558 SDIOH_API_RC status;
559 /* No lock needed since sdioh_request_byte does locking */
560 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
561 return status;
562}
563
564extern SDIOH_API_RC
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700565sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, u32 addr, u8 *data)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700566{
567 /* No lock needed since sdioh_request_byte does locking */
568 SDIOH_API_RC status;
569 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
570 return status;
571}
572
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700573static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, u32 regaddr)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700574{
575 /* read 24 bits and return valid 17 bit addr */
576 int i;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700577 u32 scratch, regdata;
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700578 u8 *ptr = (u8 *)&scratch;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700579 for (i = 0; i < 3; i++) {
580 if ((sdioh_sdmmc_card_regread(sd, 0, regaddr, 1, &regdata)) !=
581 SUCCESS)
582 sd_err(("%s: Can't read!\n", __func__));
583
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700584 *ptr++ = (u8) regdata;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700585 regaddr++;
586 }
587
588 /* Only the lower 17-bits are valid */
Stanislav Fomichev628f10b2011-02-20 21:43:32 +0300589 scratch = le32_to_cpu(scratch);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700590 scratch &= 0x0001FFFF;
591 return scratch;
592}
593
594extern SDIOH_API_RC
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700595sdioh_cis_read(sdioh_info_t *sd, uint func, u8 *cisd, u32 length)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700596{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700597 u32 count;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700598 int offset;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700599 u32 foo;
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700600 u8 *cis = cisd;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700601
602 sd_trace(("%s: Func = %d\n", __func__, func));
603
604 if (!sd->func_cis_ptr[func]) {
Brett Rudley9249ede2010-11-30 20:09:49 -0800605 memset(cis, 0, length);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700606 sd_err(("%s: no func_cis_ptr[%d]\n", __func__, func));
607 return SDIOH_API_RC_FAIL;
608 }
609
610 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __func__, func,
611 sd->func_cis_ptr[func]));
612
613 for (count = 0; count < length; count++) {
614 offset = sd->func_cis_ptr[func] + count;
615 if (sdioh_sdmmc_card_regread(sd, 0, offset, 1, &foo) < 0) {
616 sd_err(("%s: regread failed: Can't read CIS\n",
617 __func__));
618 return SDIOH_API_RC_FAIL;
619 }
620
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700621 *cis = (u8) (foo & 0xff);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700622 cis++;
623 }
624
625 return SDIOH_API_RC_SUCCESS;
626}
627
628extern SDIOH_API_RC
629sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr,
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700630 u8 *byte)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700631{
632 int err_ret;
633
634 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __func__, rw, func,
635 regaddr));
636
637 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
638 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
639 if (rw) { /* CMD52 Write */
640 if (func == 0) {
641 /* Can only directly write to some F0 registers.
642 * Handle F2 enable
643 * as a special case.
644 */
Franky Lin0df46042011-06-01 13:45:40 +0200645 if (regaddr == SDIO_CCCR_IOEx) {
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700646 if (gInstance->func[2]) {
647 sdio_claim_host(gInstance->func[2]);
648 if (*byte & SDIO_FUNC_ENABLE_2) {
649 /* Enable Function 2 */
650 err_ret =
651 sdio_enable_func
652 (gInstance->func[2]);
653 if (err_ret)
654 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
655 err_ret));
656 } else {
657 /* Disable Function 2 */
658 err_ret =
659 sdio_disable_func
660 (gInstance->func[2]);
661 if (err_ret)
662 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
663 err_ret));
664 }
665 sdio_release_host(gInstance->func[2]);
666 }
667 }
668#if defined(MMC_SDIO_ABORT)
669 /* to allow abort command through F1 */
Franky Lin0df46042011-06-01 13:45:40 +0200670 else if (regaddr == SDIO_CCCR_ABORT) {
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700671 sdio_claim_host(gInstance->func[func]);
672 /*
673 * this sdio_f0_writeb() can be replaced
674 * with another api
675 * depending upon MMC driver change.
676 * As of this time, this is temporaray one
677 */
678 sdio_writeb(gInstance->func[func], *byte,
679 regaddr, &err_ret);
680 sdio_release_host(gInstance->func[func]);
681 }
682#endif /* MMC_SDIO_ABORT */
683 else if (regaddr < 0xF0) {
684 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write "
685 "disallowed\n", regaddr));
686 } else {
687 /* Claim host controller, perform F0 write,
688 and release */
689 sdio_claim_host(gInstance->func[func]);
690 sdio_f0_writeb(gInstance->func[func], *byte,
691 regaddr, &err_ret);
692 sdio_release_host(gInstance->func[func]);
693 }
694 } else {
695 /* Claim host controller, perform Fn write,
696 and release */
697 sdio_claim_host(gInstance->func[func]);
698 sdio_writeb(gInstance->func[func], *byte, regaddr,
699 &err_ret);
700 sdio_release_host(gInstance->func[func]);
701 }
702 } else { /* CMD52 Read */
703 /* Claim host controller, perform Fn read, and release */
704 sdio_claim_host(gInstance->func[func]);
705
706 if (func == 0) {
707 *byte =
708 sdio_f0_readb(gInstance->func[func], regaddr,
709 &err_ret);
710 } else {
711 *byte =
712 sdio_readb(gInstance->func[func], regaddr,
713 &err_ret);
714 }
715
716 sdio_release_host(gInstance->func[func]);
717 }
718
719 if (err_ret)
720 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, "
721 "Err: %d\n", rw ? "Write" : "Read", func, regaddr,
722 *byte, err_ret));
723
724 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
725}
726
727extern SDIOH_API_RC
728sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func,
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700729 uint addr, u32 *word, uint nbytes)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700730{
731 int err_ret = SDIOH_API_RC_FAIL;
732
733 if (func == 0) {
734 sd_err(("%s: Only CMD52 allowed to F0.\n", __func__));
735 return SDIOH_API_RC_FAIL;
736 }
737
738 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
739 __func__, cmd_type, rw, func, addr, nbytes));
740
741 DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
742 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
743 /* Claim host controller */
744 sdio_claim_host(gInstance->func[func]);
745
746 if (rw) { /* CMD52 Write */
747 if (nbytes == 4) {
748 sdio_writel(gInstance->func[func], *word, addr,
749 &err_ret);
750 } else if (nbytes == 2) {
751 sdio_writew(gInstance->func[func], (*word & 0xFFFF),
752 addr, &err_ret);
753 } else {
754 sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes));
755 }
756 } else { /* CMD52 Read */
757 if (nbytes == 4) {
758 *word =
759 sdio_readl(gInstance->func[func], addr, &err_ret);
760 } else if (nbytes == 2) {
761 *word =
762 sdio_readw(gInstance->func[func], addr,
763 &err_ret) & 0xFFFF;
764 } else {
765 sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes));
766 }
767 }
768
769 /* Release host controller */
770 sdio_release_host(gInstance->func[func]);
771
772 if (err_ret) {
773 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
774 rw ? "Write" : "Read", err_ret));
775 }
776
777 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
778}
779
780static SDIOH_API_RC
781sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
Arend van Sprielc26b1372010-11-23 14:06:23 +0100782 uint addr, struct sk_buff *pkt)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700783{
784 bool fifo = (fix_inc == SDIOH_DATA_FIX);
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700785 u32 SGCount = 0;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700786 int err_ret = 0;
787
Arend van Sprielc26b1372010-11-23 14:06:23 +0100788 struct sk_buff *pnext;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700789
790 sd_trace(("%s: Enter\n", __func__));
791
792 ASSERT(pkt);
793 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
794 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
795
796 /* Claim host controller */
797 sdio_claim_host(gInstance->func[func]);
Arend van Spriel54991ad2010-11-23 14:06:24 +0100798 for (pnext = pkt; pnext; pnext = pnext->next) {
799 uint pkt_len = pnext->len;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700800 pkt_len += 3;
801 pkt_len &= 0xFFFFFFFC;
802
803#ifdef CONFIG_MMC_MSM7X00A
804 if ((pkt_len % 64) == 32) {
805 sd_trace(("%s: Rounding up TX packet +=32\n",
806 __func__));
807 pkt_len += 32;
808 }
809#endif /* CONFIG_MMC_MSM7X00A */
810 /* Make sure the packet is aligned properly.
811 * If it isn't, then this
812 * is the fault of sdioh_request_buffer() which
813 * is supposed to give
814 * us something we can work with.
815 */
Arend van Spriel54991ad2010-11-23 14:06:24 +0100816 ASSERT(((u32) (pkt->data) & DMA_ALIGN_MASK) == 0);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700817
818 if ((write) && (!fifo)) {
819 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
Arend van Spriel54991ad2010-11-23 14:06:24 +0100820 ((u8 *) (pnext->data)),
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700821 pkt_len);
822 } else if (write) {
823 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
Arend van Spriel54991ad2010-11-23 14:06:24 +0100824 ((u8 *) (pnext->data)),
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700825 pkt_len);
826 } else if (fifo) {
827 err_ret = sdio_readsb(gInstance->func[func],
Arend van Spriel54991ad2010-11-23 14:06:24 +0100828 ((u8 *) (pnext->data)),
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700829 addr, pkt_len);
830 } else {
831 err_ret = sdio_memcpy_fromio(gInstance->func[func],
Arend van Spriel54991ad2010-11-23 14:06:24 +0100832 ((u8 *) (pnext->data)),
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700833 addr, pkt_len);
834 }
835
836 if (err_ret) {
837 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d,"
Jason Coopere9887c92010-10-06 10:08:02 -0400838 "ERR=0x%08x\n", __func__,
839 (write) ? "TX" : "RX",
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700840 pnext, SGCount, addr, pkt_len, err_ret));
841 } else {
842 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
843 __func__,
844 (write) ? "TX" : "RX",
845 pnext, SGCount, addr, pkt_len));
846 }
847
848 if (!fifo)
849 addr += pkt_len;
850 SGCount++;
851
852 }
853
854 /* Release host controller */
855 sdio_release_host(gInstance->func[func]);
856
857 sd_trace(("%s: Exit\n", __func__));
858 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
859}
860
861/*
862 * This function takes a buffer or packet, and fixes everything up
Grant Grundler4b455e02011-05-04 09:59:47 -0700863 * so that in the end, a DMA-able packet is created.
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700864 *
865 * A buffer does not have an associated packet pointer,
866 * and may or may not be aligned.
867 * A packet may consist of a single packet, or a packet chain.
Grant Grundler4b455e02011-05-04 09:59:47 -0700868 * If it is a packet chain, then all the packets in the chain
869 * must be properly aligned.
870 *
871 * If the packet data is not aligned, then there may only be
872 * one packet, and in this case, it is copied to a new
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700873 * aligned packet.
874 *
875 */
876extern SDIOH_API_RC
877sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write,
878 uint func, uint addr, uint reg_width, uint buflen_u,
Arend van Sprielc26b1372010-11-23 14:06:23 +0100879 u8 *buffer, struct sk_buff *pkt)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700880{
881 SDIOH_API_RC Status;
Arend van Sprielc26b1372010-11-23 14:06:23 +0100882 struct sk_buff *mypkt = NULL;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700883
884 sd_trace(("%s: Enter\n", __func__));
885
886 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
887 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
888 /* Case 1: we don't have a packet. */
889 if (pkt == NULL) {
890 sd_data(("%s: Creating new %s Packet, len=%d\n",
891 __func__, write ? "TX" : "RX", buflen_u));
Henry Ptasinskib33f0e22011-05-10 22:25:29 +0200892 mypkt = bcm_pkt_buf_get_skb(buflen_u);
Jason Coopera1b04b02010-09-30 15:15:37 -0400893 if (!mypkt) {
Henry Ptasinskib33f0e22011-05-10 22:25:29 +0200894 sd_err(("%s: bcm_pkt_buf_get_skb failed: len %d\n",
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700895 __func__, buflen_u));
896 return SDIOH_API_RC_FAIL;
897 }
898
899 /* For a write, copy the buffer data into the packet. */
900 if (write)
Stanislav Fomichev02160692011-02-15 01:05:10 +0300901 memcpy(mypkt->data, buffer, buflen_u);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700902
903 Status =
904 sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
905
906 /* For a read, copy the packet data back to the buffer. */
907 if (!write)
Stanislav Fomichev02160692011-02-15 01:05:10 +0300908 memcpy(buffer, mypkt->data, buflen_u);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700909
Henry Ptasinskib33f0e22011-05-10 22:25:29 +0200910 bcm_pkt_buf_free_skb(mypkt);
Arend van Spriel54991ad2010-11-23 14:06:24 +0100911 } else if (((u32) (pkt->data) & DMA_ALIGN_MASK) != 0) {
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700912 /* Case 2: We have a packet, but it is unaligned. */
913
914 /* In this case, we cannot have a chain. */
Arend van Spriel54991ad2010-11-23 14:06:24 +0100915 ASSERT(pkt->next == NULL);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700916
917 sd_data(("%s: Creating aligned %s Packet, len=%d\n",
Arend van Spriel54991ad2010-11-23 14:06:24 +0100918 __func__, write ? "TX" : "RX", pkt->len));
Henry Ptasinskib33f0e22011-05-10 22:25:29 +0200919 mypkt = bcm_pkt_buf_get_skb(pkt->len);
Jason Coopera1b04b02010-09-30 15:15:37 -0400920 if (!mypkt) {
Henry Ptasinskib33f0e22011-05-10 22:25:29 +0200921 sd_err(("%s: bcm_pkt_buf_get_skb failed: len %d\n",
Arend van Spriel54991ad2010-11-23 14:06:24 +0100922 __func__, pkt->len));
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700923 return SDIOH_API_RC_FAIL;
924 }
925
926 /* For a write, copy the buffer data into the packet. */
927 if (write)
Stanislav Fomichev02160692011-02-15 01:05:10 +0300928 memcpy(mypkt->data, pkt->data, pkt->len);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700929
930 Status =
931 sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
932
933 /* For a read, copy the packet data back to the buffer. */
934 if (!write)
Stanislav Fomichev02160692011-02-15 01:05:10 +0300935 memcpy(pkt->data, mypkt->data, mypkt->len);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700936
Henry Ptasinskib33f0e22011-05-10 22:25:29 +0200937 bcm_pkt_buf_free_skb(mypkt);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700938 } else { /* case 3: We have a packet and
939 it is aligned. */
940 sd_data(("%s: Aligned %s Packet, direct DMA\n",
941 __func__, write ? "Tx" : "Rx"));
942 Status =
943 sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
944 }
945
946 return Status;
947}
948
949/* this function performs "abort" for both of host & device */
950extern int sdioh_abort(sdioh_info_t *sd, uint func)
951{
952#if defined(MMC_SDIO_ABORT)
953 char t_func = (char)func;
954#endif /* defined(MMC_SDIO_ABORT) */
955 sd_trace(("%s: Enter\n", __func__));
956
957#if defined(MMC_SDIO_ABORT)
Franky Lin0df46042011-06-01 13:45:40 +0200958 /* issue abort cmd52 command through F0 */
959 sdioh_request_byte(sd, SDIOH_WRITE, SDIO_FUNC_0, SDIO_CCCR_ABORT,
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700960 &t_func);
961#endif /* defined(MMC_SDIO_ABORT) */
962
963 sd_trace(("%s: Exit\n", __func__));
964 return SDIOH_API_RC_SUCCESS;
965}
966
967/* Reset and re-initialize the device */
968int sdioh_sdio_reset(sdioh_info_t *si)
969{
970 sd_trace(("%s: Enter\n", __func__));
971 sd_trace(("%s: Exit\n", __func__));
972 return SDIOH_API_RC_SUCCESS;
973}
974
975/* Disable device interrupt */
976void sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
977{
978 sd_trace(("%s: %d\n", __func__, sd->use_client_ints));
979 sd->intmask &= ~CLIENT_INTR;
980}
981
982/* Enable device interrupt */
983void sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
984{
985 sd_trace(("%s: %d\n", __func__, sd->use_client_ints));
986 sd->intmask |= CLIENT_INTR;
987}
988
989/* Read client card reg */
990int
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700991sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, u32 regaddr,
992 int regsize, u32 *data)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700993{
994
995 if ((func == 0) || (regsize == 1)) {
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -0700996 u8 temp = 0;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700997
998 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
999 *data = temp;
1000 *data &= 0xff;
1001 sd_data(("%s: byte read data=0x%02x\n", __func__, *data));
1002 } else {
1003 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data,
1004 regsize);
1005 if (regsize == 2)
1006 *data &= 0xffff;
1007
1008 sd_data(("%s: word read data=0x%08x\n", __func__, *data));
1009 }
1010
1011 return SUCCESS;
1012}
1013
1014#if !defined(OOB_INTR_ONLY)
1015/* bcmsdh_sdmmc interrupt handler */
1016static void IRQHandler(struct sdio_func *func)
1017{
1018 sdioh_info_t *sd;
1019
1020 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1021 sd = gInstance->sd;
1022
1023 ASSERT(sd != NULL);
1024 sdio_release_host(gInstance->func[0]);
1025
1026 if (sd->use_client_ints) {
1027 sd->intrcount++;
1028 ASSERT(sd->intr_handler);
1029 ASSERT(sd->intr_handler_arg);
1030 (sd->intr_handler) (sd->intr_handler_arg);
1031 } else {
1032 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1033
1034 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1035 __func__, sd->client_intr_enabled, sd->intr_handler));
1036 }
1037
1038 sdio_claim_host(gInstance->func[0]);
1039}
1040
1041/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1042static void IRQHandlerF2(struct sdio_func *func)
1043{
1044 sdioh_info_t *sd;
1045
1046 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1047
1048 sd = gInstance->sd;
1049
1050 ASSERT(sd != NULL);
1051}
1052#endif /* !defined(OOB_INTR_ONLY) */
1053
1054#ifdef NOTUSED
1055/* Write client card reg */
1056static int
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001057sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, u32 regaddr,
1058 int regsize, u32 data)
Henry Ptasinskicf2b4482010-09-20 22:33:12 -07001059{
1060
1061 if ((func == 0) || (regsize == 1)) {
Greg Kroah-Hartman3fd79f72010-10-05 10:11:12 -07001062 u8 temp;
Henry Ptasinskicf2b4482010-09-20 22:33:12 -07001063
1064 temp = data & 0xff;
1065 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1066 sd_data(("%s: byte write data=0x%02x\n", __func__, data));
1067 } else {
1068 if (regsize == 2)
1069 data &= 0xffff;
1070
1071 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data,
1072 regsize);
1073
1074 sd_data(("%s: word write data=0x%08x\n", __func__, data));
1075 }
1076
1077 return SUCCESS;
1078}
1079#endif /* NOTUSED */
1080
1081int sdioh_start(sdioh_info_t *si, int stage)
1082{
1083 return 0;
1084}
1085
1086int sdioh_stop(sdioh_info_t *si)
1087{
1088 return 0;
1089}