blob: e5f25c5b9c3220c2237c18ce6ce56c6bc8edec21 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
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 */
16/* ****************** SDIO CARD Interface Functions **************************/
17
18#include <linux/types.h>
19#include <linux/netdevice.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020020#include <linux/pci.h>
21#include <linux/pci_ids.h>
22#include <linux/sched.h>
23#include <linux/completion.h>
Franky Lin354b75b2013-06-18 13:29:29 +020024#include <linux/scatterlist.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020025#include <linux/mmc/sdio.h>
Arend van Spriele2dc9ee2013-12-12 11:58:50 +010026#include <linux/mmc/core.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020027#include <linux/mmc/sdio_func.h>
Arend van Spriele2dc9ee2013-12-12 11:58:50 +010028#include <linux/mmc/sdio_ids.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020029#include <linux/mmc/card.h>
Arend van Spriele2dc9ee2013-12-12 11:58:50 +010030#include <linux/mmc/host.h>
31#include <linux/platform_device.h>
Hante Meuleman668761a2013-04-12 10:55:55 +020032#include <linux/platform_data/brcmfmac-sdio.h>
Arend van Spriele2dc9ee2013-12-12 11:58:50 +010033#include <linux/suspend.h>
34#include <linux/errno.h>
35#include <linux/module.h>
36#include <net/cfg80211.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020037
38#include <defs.h>
39#include <brcm_hw_ids.h>
40#include <brcmu_utils.h>
41#include <brcmu_wifi.h>
42#include <soc.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020043#include "dhd_bus.h"
44#include "dhd_dbg.h"
45#include "sdio_host.h"
Arend van Spriele2dc9ee2013-12-12 11:58:50 +010046#include "sdio_chip.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020047
48#define SDIOH_API_ACCESS_RETRY_LIMIT 2
49
Arend van Spriele49b06b2013-12-12 11:58:51 +010050#define SDIO_VENDOR_ID_BROADCOM 0x02d0
51
52#define DMA_ALIGN_MASK 0x03
53
54#define SDIO_FUNC1_BLOCKSIZE 64
55#define SDIO_FUNC2_BLOCKSIZE 512
Hante Meuleman668761a2013-04-12 10:55:55 +020056
57static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)
Franky Linba89bf12012-04-27 18:56:59 -070058{
Hante Meuleman5b3c1832012-11-14 18:46:20 -080059 struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
60 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Franky Linba89bf12012-04-27 18:56:59 -070061
Hante Meuleman668761a2013-04-12 10:55:55 +020062 brcmf_dbg(INTR, "OOB intr triggered\n");
Franky Linba89bf12012-04-27 18:56:59 -070063
Hante Meuleman668761a2013-04-12 10:55:55 +020064 /* out-of-band interrupt is level-triggered which won't
Franky Linba89bf12012-04-27 18:56:59 -070065 * be cleared until dpc
66 */
67 if (sdiodev->irq_en) {
68 disable_irq_nosync(irq);
69 sdiodev->irq_en = false;
70 }
71
72 brcmf_sdbrcm_isr(sdiodev->bus);
73
74 return IRQ_HANDLED;
75}
76
Hante Meuleman668761a2013-04-12 10:55:55 +020077static void brcmf_sdio_ib_irqhandler(struct sdio_func *func)
Arend van Spriel5b435de2011-10-05 13:19:03 +020078{
Hante Meuleman5b3c1832012-11-14 18:46:20 -080079 struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
80 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Arend van Spriel5b435de2011-10-05 13:19:03 +020081
Hante Meuleman668761a2013-04-12 10:55:55 +020082 brcmf_dbg(INTR, "IB intr triggered\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +020083
Arend van Spriel5b435de2011-10-05 13:19:03 +020084 brcmf_sdbrcm_isr(sdiodev->bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +020085}
86
Franky Linfbf59102011-12-16 18:36:53 -080087/* dummy handler for SDIO function 2 interrupt */
Franky Linba89bf12012-04-27 18:56:59 -070088static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
Franky Linfbf59102011-12-16 18:36:53 -080089{
90}
91
Arend van Spriele49b06b2013-12-12 11:58:51 +010092static bool brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
93{
94 bool is_err = false;
95#ifdef CONFIG_PM_SLEEP
96 is_err = atomic_read(&sdiodev->suspend);
97#endif
98 return is_err;
99}
100
101static void brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev,
102 wait_queue_head_t *wq)
103{
104#ifdef CONFIG_PM_SLEEP
105 int retry = 0;
106 while (atomic_read(&sdiodev->suspend) && retry++ != 30)
107 wait_event_timeout(*wq, false, HZ/100);
108#endif
109}
110
Franky Linba89bf12012-04-27 18:56:59 -0700111int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200112{
Hante Meuleman668761a2013-04-12 10:55:55 +0200113 int ret = 0;
114 u8 data;
115 unsigned long flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200116
Hante Meuleman668761a2013-04-12 10:55:55 +0200117 if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
118 brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
119 sdiodev->pdata->oob_irq_nr);
120 ret = request_irq(sdiodev->pdata->oob_irq_nr,
121 brcmf_sdio_oob_irqhandler,
122 sdiodev->pdata->oob_irq_flags,
123 "brcmf_oob_intr",
124 &sdiodev->func[1]->dev);
125 if (ret != 0) {
126 brcmf_err("request_irq failed %d\n", ret);
127 return ret;
128 }
129 sdiodev->oob_irq_requested = true;
130 spin_lock_init(&sdiodev->irq_en_lock);
131 spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
132 sdiodev->irq_en = true;
133 spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
134
135 ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr);
136 if (ret != 0) {
137 brcmf_err("enable_irq_wake failed %d\n", ret);
138 return ret;
139 }
140 sdiodev->irq_wake = true;
141
142 sdio_claim_host(sdiodev->func[1]);
143
144 /* must configure SDIO_CCCR_IENx to enable irq */
145 data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
146 data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
147 brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
148
149 /* redirect, configure and enable io for interrupt signal */
150 data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
151 if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
152 data |= SDIO_SEPINT_ACT_HI;
153 brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
154
155 sdio_release_host(sdiodev->func[1]);
156 } else {
157 brcmf_dbg(SDIO, "Entering\n");
158 sdio_claim_host(sdiodev->func[1]);
159 sdio_claim_irq(sdiodev->func[1], brcmf_sdio_ib_irqhandler);
160 sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
161 sdio_release_host(sdiodev->func[1]);
162 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200163
164 return 0;
165}
166
Franky Linba89bf12012-04-27 18:56:59 -0700167int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200168{
Arend van Sprielc3203372013-04-03 12:40:44 +0200169 brcmf_dbg(SDIO, "Entering\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200170
Hante Meuleman668761a2013-04-12 10:55:55 +0200171 if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
172 sdio_claim_host(sdiodev->func[1]);
173 brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
174 brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
175 sdio_release_host(sdiodev->func[1]);
176
177 if (sdiodev->oob_irq_requested) {
178 sdiodev->oob_irq_requested = false;
179 if (sdiodev->irq_wake) {
180 disable_irq_wake(sdiodev->pdata->oob_irq_nr);
181 sdiodev->irq_wake = false;
182 }
183 free_irq(sdiodev->pdata->oob_irq_nr,
184 &sdiodev->func[1]->dev);
185 sdiodev->irq_en = false;
186 }
187 } else {
188 sdio_claim_host(sdiodev->func[1]);
189 sdio_release_irq(sdiodev->func[2]);
190 sdio_release_irq(sdiodev->func[1]);
191 sdio_release_host(sdiodev->func[1]);
192 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200193
194 return 0;
195}
196
Arend van Spriele49b06b2013-12-12 11:58:51 +0100197static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
198 uint regaddr, u8 *byte)
199{
200 struct sdio_func *sdfunc = sdiodev->func[0];
201 int err_ret;
202
203 /*
204 * Can only directly write to some F0 registers.
205 * Handle F2 enable/disable and Abort command
206 * as a special case.
207 */
208 if (regaddr == SDIO_CCCR_IOEx) {
209 sdfunc = sdiodev->func[2];
210 if (sdfunc) {
211 if (*byte & SDIO_FUNC_ENABLE_2) {
212 /* Enable Function 2 */
213 err_ret = sdio_enable_func(sdfunc);
214 if (err_ret)
215 brcmf_err("enable F2 failed:%d\n",
216 err_ret);
217 } else {
218 /* Disable Function 2 */
219 err_ret = sdio_disable_func(sdfunc);
220 if (err_ret)
221 brcmf_err("Disable F2 failed:%d\n",
222 err_ret);
223 }
224 } else {
225 err_ret = -ENOENT;
226 }
227 } else if ((regaddr == SDIO_CCCR_ABORT) ||
228 (regaddr == SDIO_CCCR_IENx)) {
229 sdfunc = kmemdup(sdiodev->func[0], sizeof(struct sdio_func),
230 GFP_KERNEL);
231 if (!sdfunc)
232 return -ENOMEM;
233 sdfunc->num = 0;
234 sdio_writeb(sdfunc, *byte, regaddr, &err_ret);
235 kfree(sdfunc);
236 } else if (regaddr < 0xF0) {
237 brcmf_err("F0 Wr:0x%02x: write disallowed\n", regaddr);
238 err_ret = -EPERM;
239 } else {
240 sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret);
241 }
242
243 return err_ret;
244}
245
246static int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw,
247 uint func, uint regaddr, u8 *byte)
248{
249 int err_ret;
250
251 brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
252
253 brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
254 if (brcmf_pm_resume_error(sdiodev))
255 return -EIO;
256
257 if (rw && func == 0) {
258 /* handle F0 separately */
259 err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte);
260 } else {
261 if (rw) /* CMD52 Write */
262 sdio_writeb(sdiodev->func[func], *byte, regaddr,
263 &err_ret);
264 else if (func == 0) {
265 *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
266 &err_ret);
267 } else {
268 *byte = sdio_readb(sdiodev->func[func], regaddr,
269 &err_ret);
270 }
271 }
272
273 if (err_ret) {
274 /*
275 * SleepCSR register access can fail when
276 * waking up the device so reduce this noise
277 * in the logs.
278 */
279 if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
280 brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
281 rw ? "write" : "read", func, regaddr, *byte,
282 err_ret);
283 else
284 brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
285 rw ? "write" : "read", func, regaddr, *byte,
286 err_ret);
287 }
288 return err_ret;
289}
290
291static int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, uint rw,
292 uint func, uint addr, u32 *word,
293 uint nbytes)
294{
295 int err_ret = -EIO;
296
297 if (func == 0) {
298 brcmf_err("Only CMD52 allowed to F0\n");
299 return -EINVAL;
300 }
301
302 brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
303 rw, func, addr, nbytes);
304
305 brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
306 if (brcmf_pm_resume_error(sdiodev))
307 return -EIO;
308
309 if (rw) { /* CMD52 Write */
310 if (nbytes == 4)
311 sdio_writel(sdiodev->func[func], *word, addr,
312 &err_ret);
313 else if (nbytes == 2)
314 sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
315 addr, &err_ret);
316 else
317 brcmf_err("Invalid nbytes: %d\n", nbytes);
318 } else { /* CMD52 Read */
319 if (nbytes == 4)
320 *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
321 else if (nbytes == 2)
322 *word = sdio_readw(sdiodev->func[func], addr,
323 &err_ret) & 0xFFFF;
324 else
325 brcmf_err("Invalid nbytes: %d\n", nbytes);
326 }
327
328 if (err_ret)
329 brcmf_err("Failed to %s word, Err: 0x%08x\n",
330 rw ? "write" : "read", err_ret);
331
332 return err_ret;
333}
334
Franky Lin356bae62013-06-26 14:20:17 +0200335static int
Arend van Spriel5b435de2011-10-05 13:19:03 +0200336brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
337{
Franky Lin7d9cfc22012-05-04 18:27:30 -0700338 int err = 0, i;
339 u8 addr[3];
340 s32 retry;
341
342 addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
343 addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
344 addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
345
346 for (i = 0; i < 3; i++) {
347 retry = 0;
348 do {
349 if (retry)
350 usleep_range(1000, 2000);
351 err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
352 SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
353 &addr[i]);
354 } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
355
356 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100357 brcmf_err("failed at addr:0x%0x\n",
Franky Lin7d9cfc22012-05-04 18:27:30 -0700358 SBSDIO_FUNC1_SBADDRLOW + i);
359 break;
360 }
361 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200362
363 return err;
364}
365
Franky Lin356bae62013-06-26 14:20:17 +0200366static int
367brcmf_sdio_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
368{
369 uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
370 int err = 0;
371
372 if (bar0 != sdiodev->sbwad) {
373 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
374 if (err)
375 return err;
376
377 sdiodev->sbwad = bar0;
378 }
379
380 *addr &= SBSDIO_SB_OFT_ADDR_MASK;
381
382 if (width == 4)
383 *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
384
385 return 0;
386}
387
Franky Lin45316032012-09-13 21:12:03 +0200388int
Franky Line9b8d912012-05-04 18:27:31 -0700389brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
390 void *data, bool write)
391{
392 u8 func_num, reg_size;
Franky Line9b8d912012-05-04 18:27:31 -0700393 s32 retry = 0;
394 int ret;
395
396 /*
397 * figure out how to read the register based on address range
Franky Lind8b3fc52012-05-04 18:27:38 -0700398 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
Franky Line9b8d912012-05-04 18:27:31 -0700399 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
400 * The rest: function 1 silicon backplane core registers
401 */
Franky Lind8b3fc52012-05-04 18:27:38 -0700402 if ((addr & ~REG_F0_REG_MASK) == 0) {
Franky Line9b8d912012-05-04 18:27:31 -0700403 func_num = SDIO_FUNC_0;
404 reg_size = 1;
405 } else if ((addr & ~REG_F1_MISC_MASK) == 0) {
406 func_num = SDIO_FUNC_1;
407 reg_size = 1;
408 } else {
409 func_num = SDIO_FUNC_1;
410 reg_size = 4;
411
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200412 ret = brcmf_sdio_addrprep(sdiodev, reg_size, &addr);
413 if (ret)
414 goto done;
Franky Line9b8d912012-05-04 18:27:31 -0700415 }
416
417 do {
418 if (!write)
419 memset(data, 0, reg_size);
420 if (retry) /* wait for 1 ms till bus get settled down */
421 usleep_range(1000, 2000);
422 if (reg_size == 1)
423 ret = brcmf_sdioh_request_byte(sdiodev, write,
424 func_num, addr, data);
425 else
426 ret = brcmf_sdioh_request_word(sdiodev, write,
427 func_num, addr, data, 4);
428 } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
429
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200430done:
Franky Lin5c15c232012-05-04 18:27:37 -0700431 if (ret != 0)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100432 brcmf_err("failed with %d\n", ret);
Franky Line9b8d912012-05-04 18:27:31 -0700433
434 return ret;
435}
436
437u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
438{
439 u8 data;
440 int retval;
441
Arend van Sprielc3203372013-04-03 12:40:44 +0200442 brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
Franky Line9b8d912012-05-04 18:27:31 -0700443 retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
Arend van Sprielc3203372013-04-03 12:40:44 +0200444 brcmf_dbg(SDIO, "data:0x%02x\n", data);
Franky Line9b8d912012-05-04 18:27:31 -0700445
446 if (ret)
447 *ret = retval;
448
449 return data;
450}
451
452u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
453{
454 u32 data;
455 int retval;
456
Arend van Sprielc3203372013-04-03 12:40:44 +0200457 brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
Franky Line9b8d912012-05-04 18:27:31 -0700458 retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
Arend van Sprielc3203372013-04-03 12:40:44 +0200459 brcmf_dbg(SDIO, "data:0x%08x\n", data);
Franky Line9b8d912012-05-04 18:27:31 -0700460
461 if (ret)
462 *ret = retval;
463
464 return data;
465}
466
467void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
468 u8 data, int *ret)
469{
470 int retval;
471
Arend van Sprielc3203372013-04-03 12:40:44 +0200472 brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
Franky Line9b8d912012-05-04 18:27:31 -0700473 retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
474
475 if (ret)
476 *ret = retval;
477}
478
479void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
480 u32 data, int *ret)
481{
482 int retval;
483
Arend van Sprielc3203372013-04-03 12:40:44 +0200484 brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
Franky Line9b8d912012-05-04 18:27:31 -0700485 retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
486
487 if (ret)
488 *ret = retval;
489}
490
Arend van Spriel4aef2672013-10-15 15:44:52 +0200491static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
492 bool write, u32 addr, struct sk_buff *pkt)
493{
494 unsigned int req_sz;
495
496 brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
497 if (brcmf_pm_resume_error(sdiodev))
498 return -EIO;
499
500 /* Single skb use the standard mmc interface */
501 req_sz = pkt->len + 3;
502 req_sz &= (uint)~3;
503
504 if (write)
505 return sdio_memcpy_toio(sdiodev->func[fn], addr,
506 ((u8 *)(pkt->data)),
507 req_sz);
508 else if (fn == 1)
509 return sdio_memcpy_fromio(sdiodev->func[fn],
510 ((u8 *)(pkt->data)),
511 addr, req_sz);
512 else
513 /* function 2 read is FIFO operation */
514 return sdio_readsb(sdiodev->func[fn],
515 ((u8 *)(pkt->data)), addr,
516 req_sz);
517}
518
Franky Lin78b3f1c2013-06-18 13:29:28 +0200519/**
Arend van Spriel0d7d9822013-10-15 15:44:51 +0200520 * brcmf_sdio_sglist_rw - SDIO interface function for block data access
Franky Lin78b3f1c2013-06-18 13:29:28 +0200521 * @sdiodev: brcmfmac sdio device
522 * @fn: SDIO function number
523 * @write: direction flag
524 * @addr: dongle memory address as source/destination
525 * @pkt: skb pointer
526 *
527 * This function takes the respbonsibility as the interface function to MMC
528 * stack for block data access. It assumes that the skb passed down by the
529 * caller has already been padded and aligned.
530 */
Arend van Spriel0d7d9822013-10-15 15:44:51 +0200531static int brcmf_sdio_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
532 bool write, u32 addr,
533 struct sk_buff_head *pktlist)
Franky Lin78b3f1c2013-06-18 13:29:28 +0200534{
Franky Lin354b75b2013-06-18 13:29:29 +0200535 unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset;
Arend van Spriel71201492013-10-15 15:44:49 +0200536 unsigned int max_req_sz, orig_offset, dst_offset;
Arend van Spriel3f782742013-10-15 15:44:48 +0200537 unsigned short max_seg_cnt, seg_sz;
Franky Lin3b81a682013-06-26 14:20:18 +0200538 unsigned char *pkt_data, *orig_data, *dst_data;
539 struct sk_buff *pkt_next = NULL, *local_pkt_next;
540 struct sk_buff_head local_list, *target_list;
Franky Lin354b75b2013-06-18 13:29:29 +0200541 struct mmc_request mmc_req;
542 struct mmc_command mmc_cmd;
543 struct mmc_data mmc_dat;
544 struct sg_table st;
545 struct scatterlist *sgl;
Franky Lin354b75b2013-06-18 13:29:29 +0200546 int ret = 0;
547
548 if (!pktlist->qlen)
549 return -EINVAL;
Franky Lin78b3f1c2013-06-18 13:29:28 +0200550
551 brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
552 if (brcmf_pm_resume_error(sdiodev))
553 return -EIO;
554
Franky Lin3b81a682013-06-26 14:20:18 +0200555 target_list = pktlist;
556 /* for host with broken sg support, prepare a page aligned list */
557 __skb_queue_head_init(&local_list);
558 if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
559 req_sz = 0;
560 skb_queue_walk(pktlist, pkt_next)
561 req_sz += pkt_next->len;
562 req_sz = ALIGN(req_sz, sdiodev->func[fn]->cur_blksize);
563 while (req_sz > PAGE_SIZE) {
564 pkt_next = brcmu_pkt_buf_get_skb(PAGE_SIZE);
565 if (pkt_next == NULL) {
566 ret = -ENOMEM;
567 goto exit;
568 }
569 __skb_queue_tail(&local_list, pkt_next);
570 req_sz -= PAGE_SIZE;
571 }
572 pkt_next = brcmu_pkt_buf_get_skb(req_sz);
573 if (pkt_next == NULL) {
574 ret = -ENOMEM;
575 goto exit;
576 }
577 __skb_queue_tail(&local_list, pkt_next);
578 target_list = &local_list;
579 }
580
Franky Lin354b75b2013-06-18 13:29:29 +0200581 func_blk_sz = sdiodev->func[fn]->cur_blksize;
Arend van Spriel71201492013-10-15 15:44:49 +0200582 max_req_sz = sdiodev->max_request_size;
583 max_seg_cnt = min_t(unsigned short, sdiodev->max_segment_count,
584 target_list->qlen);
Franky Lin3b81a682013-06-26 14:20:18 +0200585 seg_sz = target_list->qlen;
Franky Lin354b75b2013-06-18 13:29:29 +0200586 pkt_offset = 0;
Franky Lin3b81a682013-06-26 14:20:18 +0200587 pkt_next = target_list->next;
Franky Lin354b75b2013-06-18 13:29:29 +0200588
Arend van Spriel3f782742013-10-15 15:44:48 +0200589 if (sg_alloc_table(&st, max_seg_cnt, GFP_KERNEL)) {
Franky Lin3b81a682013-06-26 14:20:18 +0200590 ret = -ENOMEM;
591 goto exit;
592 }
Franky Lin354b75b2013-06-18 13:29:29 +0200593
Arend van Spriel7f9a8dc2013-10-15 15:44:50 +0200594 memset(&mmc_req, 0, sizeof(struct mmc_request));
595 memset(&mmc_cmd, 0, sizeof(struct mmc_command));
596 memset(&mmc_dat, 0, sizeof(struct mmc_data));
597
598 mmc_dat.sg = st.sgl;
599 mmc_dat.blksz = func_blk_sz;
600 mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
601 mmc_cmd.opcode = SD_IO_RW_EXTENDED;
602 mmc_cmd.arg = write ? 1<<31 : 0; /* write flag */
603 mmc_cmd.arg |= (fn & 0x7) << 28; /* SDIO func num */
604 mmc_cmd.arg |= 1<<27; /* block mode */
605 /* for function 1 the addr will be incremented */
606 mmc_cmd.arg |= (fn == 1) ? 1<<26 : 0;
607 mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
608 mmc_req.cmd = &mmc_cmd;
609 mmc_req.data = &mmc_dat;
610
Franky Lin354b75b2013-06-18 13:29:29 +0200611 while (seg_sz) {
612 req_sz = 0;
613 sg_cnt = 0;
Franky Lin354b75b2013-06-18 13:29:29 +0200614 sgl = st.sgl;
615 /* prep sg table */
Franky Lin3b81a682013-06-26 14:20:18 +0200616 while (pkt_next != (struct sk_buff *)target_list) {
Franky Lin354b75b2013-06-18 13:29:29 +0200617 pkt_data = pkt_next->data + pkt_offset;
618 sg_data_sz = pkt_next->len - pkt_offset;
Arend van Spriel71201492013-10-15 15:44:49 +0200619 if (sg_data_sz > sdiodev->max_segment_size)
620 sg_data_sz = sdiodev->max_segment_size;
Franky Lin354b75b2013-06-18 13:29:29 +0200621 if (sg_data_sz > max_req_sz - req_sz)
622 sg_data_sz = max_req_sz - req_sz;
623
624 sg_set_buf(sgl, pkt_data, sg_data_sz);
625
626 sg_cnt++;
627 sgl = sg_next(sgl);
628 req_sz += sg_data_sz;
629 pkt_offset += sg_data_sz;
630 if (pkt_offset == pkt_next->len) {
631 pkt_offset = 0;
632 pkt_next = pkt_next->next;
633 }
634
Arend van Spriel3f782742013-10-15 15:44:48 +0200635 if (req_sz >= max_req_sz || sg_cnt >= max_seg_cnt)
Franky Lin354b75b2013-06-18 13:29:29 +0200636 break;
637 }
638 seg_sz -= sg_cnt;
639
640 if (req_sz % func_blk_sz != 0) {
641 brcmf_err("sg request length %u is not %u aligned\n",
642 req_sz, func_blk_sz);
Franky Lin3b81a682013-06-26 14:20:18 +0200643 ret = -ENOTBLK;
644 goto exit;
Franky Lin354b75b2013-06-18 13:29:29 +0200645 }
Arend van Spriel7f9a8dc2013-10-15 15:44:50 +0200646
Franky Lin354b75b2013-06-18 13:29:29 +0200647 mmc_dat.sg_len = sg_cnt;
Franky Lin354b75b2013-06-18 13:29:29 +0200648 mmc_dat.blocks = req_sz / func_blk_sz;
Franky Lin354b75b2013-06-18 13:29:29 +0200649 mmc_cmd.arg |= (addr & 0x1FFFF) << 9; /* address */
650 mmc_cmd.arg |= mmc_dat.blocks & 0x1FF; /* block count */
Arend van Spriel7f9a8dc2013-10-15 15:44:50 +0200651 /* incrementing addr for function 1 */
Franky Lin354b75b2013-06-18 13:29:29 +0200652 if (fn == 1)
653 addr += req_sz;
654
655 mmc_set_data_timeout(&mmc_dat, sdiodev->func[fn]->card);
Arend van Spriel71201492013-10-15 15:44:49 +0200656 mmc_wait_for_req(sdiodev->func[fn]->card->host, &mmc_req);
Franky Lin354b75b2013-06-18 13:29:29 +0200657
658 ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
659 if (ret != 0) {
660 brcmf_err("CMD53 sg block %s failed %d\n",
661 write ? "write" : "read", ret);
662 ret = -EIO;
663 break;
664 }
665 }
666
Franky Lin3b81a682013-06-26 14:20:18 +0200667 if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
668 local_pkt_next = local_list.next;
669 orig_offset = 0;
670 skb_queue_walk(pktlist, pkt_next) {
671 dst_offset = 0;
672 do {
673 req_sz = local_pkt_next->len - orig_offset;
674 req_sz = min_t(uint, pkt_next->len - dst_offset,
675 req_sz);
676 orig_data = local_pkt_next->data + orig_offset;
677 dst_data = pkt_next->data + dst_offset;
678 memcpy(dst_data, orig_data, req_sz);
679 orig_offset += req_sz;
680 dst_offset += req_sz;
681 if (orig_offset == local_pkt_next->len) {
682 orig_offset = 0;
683 local_pkt_next = local_pkt_next->next;
684 }
685 if (dst_offset == pkt_next->len)
686 break;
687 } while (!skb_queue_empty(&local_list));
688 }
689 }
690
691exit:
Franky Lin354b75b2013-06-18 13:29:29 +0200692 sg_free_table(&st);
Franky Lin3b81a682013-06-26 14:20:18 +0200693 while ((pkt_next = __skb_dequeue(&local_list)) != NULL)
694 brcmu_pkt_buf_free_skb(pkt_next);
Franky Lin354b75b2013-06-18 13:29:29 +0200695
696 return ret;
Franky Lin78b3f1c2013-06-18 13:29:28 +0200697}
698
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800699int
700brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
701 uint flags, u8 *buf, uint nbytes)
702{
703 struct sk_buff *mypkt;
704 int err;
705
706 mypkt = brcmu_pkt_buf_get_skb(nbytes);
707 if (!mypkt) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100708 brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800709 nbytes);
710 return -EIO;
711 }
712
713 err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
714 if (!err)
715 memcpy(buf, mypkt->data, nbytes);
716
717 brcmu_pkt_buf_free_skb(mypkt);
718 return err;
719}
720
721int
722brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
723 uint flags, struct sk_buff *pkt)
724{
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800725 uint width;
726 int err = 0;
727
Arend van Sprielc3203372013-04-03 12:40:44 +0200728 brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800729 fn, addr, pkt->len);
730
731 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
Franky Lin356bae62013-06-26 14:20:17 +0200732 err = brcmf_sdio_addrprep(sdiodev, width, &addr);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800733 if (err)
Franky Lin7057fd02012-09-13 21:12:02 +0200734 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200735
Arend van Spriel4aef2672013-10-15 15:44:52 +0200736 err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pkt);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800737
Franky Lin7057fd02012-09-13 21:12:02 +0200738done:
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800739 return err;
740}
741
742int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
Arend van Spriela413e392013-10-15 15:44:57 +0200743 uint flags, struct sk_buff_head *pktq, uint totlen)
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800744{
Arend van Spriela413e392013-10-15 15:44:57 +0200745 struct sk_buff *glom_skb;
746 struct sk_buff *skb;
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800747 uint width;
748 int err = 0;
749
Arend van Sprielc3203372013-04-03 12:40:44 +0200750 brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800751 fn, addr, pktq->qlen);
752
Arend van Spriel5b435de2011-10-05 13:19:03 +0200753 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
Franky Lin356bae62013-06-26 14:20:17 +0200754 err = brcmf_sdio_addrprep(sdiodev, width, &addr);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800755 if (err)
Franky Lin7057fd02012-09-13 21:12:02 +0200756 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200757
Arend van Spriela413e392013-10-15 15:44:57 +0200758 if (pktq->qlen == 1)
759 err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pktq->next);
760 else if (!sdiodev->sg_support) {
761 glom_skb = brcmu_pkt_buf_get_skb(totlen);
762 if (!glom_skb)
763 return -ENOMEM;
764 err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, glom_skb);
765 if (err)
766 goto done;
767
768 skb_queue_walk(pktq, skb) {
769 memcpy(skb->data, glom_skb->data, skb->len);
770 skb_pull(glom_skb, skb->len);
771 }
772 } else
773 err = brcmf_sdio_sglist_rw(sdiodev, fn, false, addr, pktq);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200774
Franky Lin7057fd02012-09-13 21:12:02 +0200775done:
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800776 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200777}
778
779int
780brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800781 uint flags, u8 *buf, uint nbytes)
782{
783 struct sk_buff *mypkt;
Arend van Spriel4aef2672013-10-15 15:44:52 +0200784 uint width;
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800785 int err;
786
787 mypkt = brcmu_pkt_buf_get_skb(nbytes);
788 if (!mypkt) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100789 brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800790 nbytes);
791 return -EIO;
792 }
793
794 memcpy(mypkt->data, buf, nbytes);
Arend van Spriel4aef2672013-10-15 15:44:52 +0200795
796 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200797 err = brcmf_sdio_addrprep(sdiodev, width, &addr);
Arend van Spriel4aef2672013-10-15 15:44:52 +0200798
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200799 if (!err)
800 err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, mypkt);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800801
802 brcmu_pkt_buf_free_skb(mypkt);
803 return err;
804
805}
806
807int
808brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
Franky Linb05e9252013-08-10 12:27:26 +0200809 uint flags, struct sk_buff_head *pktq)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200810{
Arend van Sprielc8cce1f2013-10-15 15:44:55 +0200811 struct sk_buff *skb;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200812 uint width;
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200813 int err;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200814
Arend van Sprielc3203372013-04-03 12:40:44 +0200815 brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
Franky Linb05e9252013-08-10 12:27:26 +0200816 fn, addr, pktq->qlen);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200817
Arend van Spriel5b435de2011-10-05 13:19:03 +0200818 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200819 err = brcmf_sdio_addrprep(sdiodev, width, &addr);
820 if (err)
821 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200822
Arend van Sprielc8cce1f2013-10-15 15:44:55 +0200823 if (pktq->qlen == 1 || !sdiodev->sg_support)
824 skb_queue_walk(pktq, skb) {
825 err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, skb);
826 if (err)
827 break;
828 }
829 else
830 err = brcmf_sdio_sglist_rw(sdiodev, fn, true, addr, pktq);
831
832 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200833}
834
Franky Linba540b02013-04-11 13:28:47 +0200835int
836brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
837 u8 *data, uint size)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200838{
Franky Linba540b02013-04-11 13:28:47 +0200839 int bcmerror = 0;
840 struct sk_buff *pkt;
841 u32 sdaddr;
842 uint dsize;
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800843
Franky Linba540b02013-04-11 13:28:47 +0200844 dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
845 pkt = dev_alloc_skb(dsize);
846 if (!pkt) {
847 brcmf_err("dev_alloc_skb failed: len %d\n", dsize);
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800848 return -EIO;
849 }
Franky Linba540b02013-04-11 13:28:47 +0200850 pkt->priority = 0;
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800851
Franky Linba540b02013-04-11 13:28:47 +0200852 /* Determine initial transfer parameters */
853 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
854 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
855 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
856 else
857 dsize = size;
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800858
Franky Linba540b02013-04-11 13:28:47 +0200859 sdio_claim_host(sdiodev->func[1]);
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800860
Franky Linba540b02013-04-11 13:28:47 +0200861 /* Do the transfer(s) */
862 while (size) {
863 /* Set the backplane window to include the start address */
864 bcmerror = brcmf_sdcard_set_sbaddr_window(sdiodev, address);
865 if (bcmerror)
866 break;
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800867
Franky Linba540b02013-04-11 13:28:47 +0200868 brcmf_dbg(SDIO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
869 write ? "write" : "read", dsize,
870 sdaddr, address & SBSDIO_SBWINDOW_MASK);
871
872 sdaddr &= SBSDIO_SB_OFT_ADDR_MASK;
873 sdaddr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
874
875 skb_put(pkt, dsize);
876 if (write)
877 memcpy(pkt->data, data, dsize);
Arend van Spriel4aef2672013-10-15 15:44:52 +0200878 bcmerror = brcmf_sdio_buffrw(sdiodev, SDIO_FUNC_1, write,
879 sdaddr, pkt);
Franky Linba540b02013-04-11 13:28:47 +0200880 if (bcmerror) {
881 brcmf_err("membytes transfer failed\n");
882 break;
883 }
884 if (!write)
885 memcpy(data, pkt->data, dsize);
886 skb_trim(pkt, dsize);
887
888 /* Adjust for next transfer (if any) */
889 size -= dsize;
890 if (size) {
891 data += dsize;
892 address += dsize;
893 sdaddr = 0;
894 dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
895 }
896 }
897
898 dev_kfree_skb(pkt);
899
900 /* Return the window to backplane enumeration space for core access */
901 if (brcmf_sdcard_set_sbaddr_window(sdiodev, sdiodev->sbwad))
902 brcmf_err("FAILED to set window back to 0x%x\n",
903 sdiodev->sbwad);
904
905 sdio_release_host(sdiodev->func[1]);
906
907 return bcmerror;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200908}
909
910int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
911{
912 char t_func = (char)fn;
Arend van Sprielc3203372013-04-03 12:40:44 +0200913 brcmf_dbg(SDIO, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200914
915 /* issue abort cmd52 command through F0 */
916 brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
917 SDIO_CCCR_ABORT, &t_func);
918
Arend van Sprielc3203372013-04-03 12:40:44 +0200919 brcmf_dbg(SDIO, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200920 return 0;
921}
922
Arend van Spriele49b06b2013-12-12 11:58:51 +0100923static int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100924{
925 int err_ret = 0;
926 struct mmc_host *host;
927 struct sdio_func *func;
928 uint max_blocks;
929
930 brcmf_dbg(SDIO, "\n");
931
932 sdiodev->num_funcs = 2;
933
934 sdio_claim_host(sdiodev->func[1]);
935
936 err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
937 if (err_ret) {
938 brcmf_err("Failed to set F1 blocksize\n");
939 goto out;
940 }
941
942 err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
943 if (err_ret) {
944 brcmf_err("Failed to set F2 blocksize\n");
945 goto out;
946 }
947
Arend van Spriel463c30b2013-12-12 11:58:52 +0100948 /* Enable Function 1 */
949 err_ret = sdio_enable_func(sdiodev->func[1]);
950 if (err_ret) {
951 brcmf_err("Failed to enable F1 Err: 0x%08x\n", err_ret);
952 goto out;
953 }
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100954
955 /*
956 * determine host related variables after brcmf_sdio_probe()
957 * as func->cur_blksize is properly set and F2 init has been
958 * completed successfully.
959 */
960 func = sdiodev->func[2];
961 host = func->card->host;
962 sdiodev->sg_support = host->max_segs > 1;
963 max_blocks = min_t(uint, host->max_blk_count, 511u);
964 sdiodev->max_request_size = min_t(uint, host->max_req_size,
965 max_blocks * func->cur_blksize);
966 sdiodev->max_segment_count = min_t(uint, host->max_segs,
967 SG_MAX_SINGLE_ALLOC);
968 sdiodev->max_segment_size = host->max_seg_size;
969out:
970 sdio_release_host(sdiodev->func[1]);
971 brcmf_dbg(SDIO, "Done\n");
972 return err_ret;
973}
974
Arend van Spriele49b06b2013-12-12 11:58:51 +0100975static void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100976{
977 brcmf_dbg(SDIO, "\n");
978
979 /* Disable Function 2 */
980 sdio_claim_host(sdiodev->func[2]);
981 sdio_disable_func(sdiodev->func[2]);
982 sdio_release_host(sdiodev->func[2]);
983
984 /* Disable Function 1 */
985 sdio_claim_host(sdiodev->func[1]);
986 sdio_disable_func(sdiodev->func[1]);
987 sdio_release_host(sdiodev->func[1]);
988
989}
990
Arend van Spriele49b06b2013-12-12 11:58:51 +0100991static int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
992{
993 sdiodev->bus_if->state = BRCMF_BUS_DOWN;
994
995 if (sdiodev->bus) {
996 brcmf_sdbrcm_disconnect(sdiodev->bus);
997 sdiodev->bus = NULL;
998 }
999
1000 brcmf_sdioh_detach(sdiodev);
1001
1002 sdiodev->sbwad = 0;
1003
1004 return 0;
1005}
1006
1007static int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
1008{
1009 u32 regs = 0;
1010 int ret = 0;
1011
1012 ret = brcmf_sdioh_attach(sdiodev);
1013 if (ret)
1014 goto out;
1015
1016 regs = SI_ENUM_BASE;
1017
1018 /* try to attach to the target device */
1019 sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
1020 if (!sdiodev->bus) {
1021 brcmf_err("device attach failed\n");
1022 ret = -ENODEV;
1023 goto out;
1024 }
1025
1026out:
1027 if (ret)
1028 brcmf_sdio_remove(sdiodev);
1029
1030 return ret;
1031}
1032
1033/* devices we support, null terminated */
1034static const struct sdio_device_id brcmf_sdmmc_ids[] = {
1035 {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)},
1036 {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
1037 {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
1038 {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
1039 {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
1040 {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
1041 SDIO_DEVICE_ID_BROADCOM_4335_4339)},
1042 { /* end: all zeroes */ },
1043};
1044MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
1045
1046static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
1047
1048
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001049static int brcmf_ops_sdio_probe(struct sdio_func *func,
1050 const struct sdio_device_id *id)
1051{
1052 int err;
1053 struct brcmf_sdio_dev *sdiodev;
1054 struct brcmf_bus *bus_if;
1055
1056 brcmf_dbg(SDIO, "Enter\n");
1057 brcmf_dbg(SDIO, "Class=%x\n", func->class);
1058 brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
1059 brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
1060 brcmf_dbg(SDIO, "Function#: %d\n", func->num);
1061
1062 /* Consume func num 1 but dont do anything with it. */
1063 if (func->num == 1)
1064 return 0;
1065
1066 /* Ignore anything but func 2 */
1067 if (func->num != 2)
1068 return -ENODEV;
1069
1070 bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
1071 if (!bus_if)
1072 return -ENOMEM;
1073 sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
1074 if (!sdiodev) {
1075 kfree(bus_if);
1076 return -ENOMEM;
1077 }
1078
1079 sdiodev->func[0] = func->card->sdio_func[0];
1080 sdiodev->func[1] = func->card->sdio_func[0];
1081 sdiodev->func[2] = func;
1082
1083 sdiodev->bus_if = bus_if;
1084 bus_if->bus_priv.sdio = sdiodev;
1085 dev_set_drvdata(&func->dev, bus_if);
1086 dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
1087 sdiodev->dev = &sdiodev->func[1]->dev;
1088 sdiodev->pdata = brcmfmac_sdio_pdata;
1089
1090 atomic_set(&sdiodev->suspend, false);
1091 init_waitqueue_head(&sdiodev->request_byte_wait);
1092 init_waitqueue_head(&sdiodev->request_word_wait);
1093 init_waitqueue_head(&sdiodev->request_buffer_wait);
1094
1095 brcmf_dbg(SDIO, "F2 found, calling brcmf_sdio_probe...\n");
1096 err = brcmf_sdio_probe(sdiodev);
1097 if (err) {
1098 brcmf_err("F2 error, probe failed %d...\n", err);
1099 goto fail;
1100 }
1101
1102 brcmf_dbg(SDIO, "F2 init completed...\n");
1103 return 0;
1104
1105fail:
1106 dev_set_drvdata(&func->dev, NULL);
1107 dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
1108 kfree(sdiodev);
1109 kfree(bus_if);
1110 return err;
1111}
1112
1113static void brcmf_ops_sdio_remove(struct sdio_func *func)
1114{
1115 struct brcmf_bus *bus_if;
1116 struct brcmf_sdio_dev *sdiodev;
1117
1118 brcmf_dbg(SDIO, "Enter\n");
1119 brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
1120 brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
1121 brcmf_dbg(SDIO, "Function: %d\n", func->num);
1122
1123 if (func->num != 1 && func->num != 2)
1124 return;
1125
1126 bus_if = dev_get_drvdata(&func->dev);
1127 if (bus_if) {
1128 sdiodev = bus_if->bus_priv.sdio;
1129 brcmf_sdio_remove(sdiodev);
1130
1131 dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
1132 dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
1133
1134 kfree(bus_if);
1135 kfree(sdiodev);
1136 }
1137
1138 brcmf_dbg(SDIO, "Exit\n");
1139}
1140
1141#ifdef CONFIG_PM_SLEEP
Arend van Spriele49b06b2013-12-12 11:58:51 +01001142static void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
1143{
1144 if (enable)
1145 brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
1146 else
1147 brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
1148}
1149
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001150static int brcmf_sdio_suspend(struct device *dev)
1151{
1152 mmc_pm_flag_t sdio_flags;
1153 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1154 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
1155 int ret = 0;
1156
1157 brcmf_dbg(SDIO, "\n");
1158
1159 atomic_set(&sdiodev->suspend, true);
1160
1161 sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
1162 if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
1163 brcmf_err("Host can't keep power while suspended\n");
1164 return -EINVAL;
1165 }
1166
1167 ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
1168 if (ret) {
1169 brcmf_err("Failed to set pm_flags\n");
1170 return ret;
1171 }
1172
1173 brcmf_sdio_wdtmr_enable(sdiodev, false);
1174
1175 return ret;
1176}
1177
1178static int brcmf_sdio_resume(struct device *dev)
1179{
1180 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1181 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
1182
1183 brcmf_sdio_wdtmr_enable(sdiodev, true);
1184 atomic_set(&sdiodev->suspend, false);
1185 return 0;
1186}
1187
1188static const struct dev_pm_ops brcmf_sdio_pm_ops = {
1189 .suspend = brcmf_sdio_suspend,
1190 .resume = brcmf_sdio_resume,
1191};
1192#endif /* CONFIG_PM_SLEEP */
1193
1194static struct sdio_driver brcmf_sdmmc_driver = {
1195 .probe = brcmf_ops_sdio_probe,
1196 .remove = brcmf_ops_sdio_remove,
1197 .name = BRCMFMAC_SDIO_PDATA_NAME,
1198 .id_table = brcmf_sdmmc_ids,
1199#ifdef CONFIG_PM_SLEEP
1200 .drv = {
1201 .pm = &brcmf_sdio_pm_ops,
1202 },
1203#endif /* CONFIG_PM_SLEEP */
1204};
1205
1206static int brcmf_sdio_pd_probe(struct platform_device *pdev)
1207{
1208 brcmf_dbg(SDIO, "Enter\n");
1209
1210 brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
1211
1212 if (brcmfmac_sdio_pdata->power_on)
1213 brcmfmac_sdio_pdata->power_on();
1214
1215 return 0;
1216}
1217
1218static int brcmf_sdio_pd_remove(struct platform_device *pdev)
1219{
1220 brcmf_dbg(SDIO, "Enter\n");
1221
1222 if (brcmfmac_sdio_pdata->power_off)
1223 brcmfmac_sdio_pdata->power_off();
1224
1225 sdio_unregister_driver(&brcmf_sdmmc_driver);
1226
1227 return 0;
1228}
1229
1230static struct platform_driver brcmf_sdio_pd = {
1231 .remove = brcmf_sdio_pd_remove,
1232 .driver = {
1233 .name = BRCMFMAC_SDIO_PDATA_NAME,
1234 .owner = THIS_MODULE,
1235 }
1236};
1237
1238void brcmf_sdio_register(void)
1239{
1240 int ret;
1241
1242 ret = sdio_register_driver(&brcmf_sdmmc_driver);
1243 if (ret)
1244 brcmf_err("sdio_register_driver failed: %d\n", ret);
1245}
1246
1247void brcmf_sdio_exit(void)
1248{
1249 brcmf_dbg(SDIO, "Enter\n");
1250
1251 if (brcmfmac_sdio_pdata)
1252 platform_driver_unregister(&brcmf_sdio_pd);
1253 else
1254 sdio_unregister_driver(&brcmf_sdmmc_driver);
1255}
1256
1257void __init brcmf_sdio_init(void)
1258{
1259 int ret;
1260
1261 brcmf_dbg(SDIO, "Enter\n");
1262
1263 ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
1264 if (ret == -ENODEV)
1265 brcmf_dbg(SDIO, "No platform data available.\n");
1266}