blob: 1f7e2f245e9ef1a0995d9788d7194ce9112c18de [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>
28#include <linux/mmc/card.h>
Arend van Spriele2dc9ee2013-12-12 11:58:50 +010029#include <linux/mmc/host.h>
30#include <linux/platform_device.h>
Hante Meuleman668761a2013-04-12 10:55:55 +020031#include <linux/platform_data/brcmfmac-sdio.h>
Arend van Spriele2dc9ee2013-12-12 11:58:50 +010032#include <linux/suspend.h>
33#include <linux/errno.h>
34#include <linux/module.h>
35#include <net/cfg80211.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020036
37#include <defs.h>
38#include <brcm_hw_ids.h>
39#include <brcmu_utils.h>
40#include <brcmu_wifi.h>
Hans de Goede568ba382014-07-29 14:23:23 +020041#include <chipcommon.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020042#include <soc.h>
Hans de Goede568ba382014-07-29 14:23:23 +020043#include "chip.h"
Hante Meulemand14f78b2014-10-28 14:56:14 +010044#include "bus.h"
Hante Meulemana8e8ed32014-10-28 14:56:13 +010045#include "debug.h"
Hante Meuleman888bf76e2014-10-28 14:56:17 +010046#include "sdio.h"
Chen-Yu Tsai61f663d2014-06-29 16:16:59 +020047#include "of.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020048
49#define SDIOH_API_ACCESS_RETRY_LIMIT 2
50
Arend van Spriele49b06b2013-12-12 11:58:51 +010051#define DMA_ALIGN_MASK 0x03
52
53#define SDIO_FUNC1_BLOCKSIZE 64
54#define SDIO_FUNC2_BLOCKSIZE 512
Arend van Spriel71370eb2013-12-12 11:58:53 +010055/* Maximum milliseconds to wait for F2 to come up */
56#define SDIO_WAIT_F2RDY 3000
57
Arend van Sprielaf1fa212014-02-27 19:25:00 +010058#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
59#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */
60
61static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
62module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
63MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
Hante Meuleman668761a2013-04-12 10:55:55 +020064
Arend van Spriela39be272013-12-12 11:58:58 +010065static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
Franky Linba89bf12012-04-27 18:56:59 -070066{
Hante Meuleman5b3c1832012-11-14 18:46:20 -080067 struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
68 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Franky Linba89bf12012-04-27 18:56:59 -070069
Hante Meuleman668761a2013-04-12 10:55:55 +020070 brcmf_dbg(INTR, "OOB intr triggered\n");
Franky Linba89bf12012-04-27 18:56:59 -070071
Hante Meuleman668761a2013-04-12 10:55:55 +020072 /* out-of-band interrupt is level-triggered which won't
Franky Linba89bf12012-04-27 18:56:59 -070073 * be cleared until dpc
74 */
75 if (sdiodev->irq_en) {
76 disable_irq_nosync(irq);
77 sdiodev->irq_en = false;
78 }
79
Arend van Spriel82d7f3c2013-12-12 11:59:04 +010080 brcmf_sdio_isr(sdiodev->bus);
Franky Linba89bf12012-04-27 18:56:59 -070081
82 return IRQ_HANDLED;
83}
84
Arend van Spriela39be272013-12-12 11:58:58 +010085static void brcmf_sdiod_ib_irqhandler(struct sdio_func *func)
Arend van Spriel5b435de2011-10-05 13:19:03 +020086{
Hante Meuleman5b3c1832012-11-14 18:46:20 -080087 struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
88 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Arend van Spriel5b435de2011-10-05 13:19:03 +020089
Hante Meuleman668761a2013-04-12 10:55:55 +020090 brcmf_dbg(INTR, "IB intr triggered\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +020091
Arend van Spriel82d7f3c2013-12-12 11:59:04 +010092 brcmf_sdio_isr(sdiodev->bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +020093}
94
Franky Linfbf59102011-12-16 18:36:53 -080095/* dummy handler for SDIO function 2 interrupt */
Arend van Spriela39be272013-12-12 11:58:58 +010096static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
Franky Linfbf59102011-12-16 18:36:53 -080097{
98}
99
Arend van Spriela39be272013-12-12 11:58:58 +0100100int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200101{
Hante Meuleman668761a2013-04-12 10:55:55 +0200102 int ret = 0;
103 u8 data;
Hans de Goede568ba382014-07-29 14:23:23 +0200104 u32 addr, gpiocontrol;
Hante Meuleman668761a2013-04-12 10:55:55 +0200105 unsigned long flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200106
Hante Meuleman668761a2013-04-12 10:55:55 +0200107 if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
108 brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
109 sdiodev->pdata->oob_irq_nr);
110 ret = request_irq(sdiodev->pdata->oob_irq_nr,
Arend van Spriela39be272013-12-12 11:58:58 +0100111 brcmf_sdiod_oob_irqhandler,
Hante Meuleman668761a2013-04-12 10:55:55 +0200112 sdiodev->pdata->oob_irq_flags,
113 "brcmf_oob_intr",
114 &sdiodev->func[1]->dev);
115 if (ret != 0) {
116 brcmf_err("request_irq failed %d\n", ret);
117 return ret;
118 }
119 sdiodev->oob_irq_requested = true;
120 spin_lock_init(&sdiodev->irq_en_lock);
121 spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
122 sdiodev->irq_en = true;
123 spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
124
125 ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr);
126 if (ret != 0) {
127 brcmf_err("enable_irq_wake failed %d\n", ret);
128 return ret;
129 }
130 sdiodev->irq_wake = true;
131
132 sdio_claim_host(sdiodev->func[1]);
133
Hans de Goede568ba382014-07-29 14:23:23 +0200134 if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) {
135 /* assign GPIO to SDIO core */
136 addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol);
137 gpiocontrol = brcmf_sdiod_regrl(sdiodev, addr, &ret);
138 gpiocontrol |= 0x2;
139 brcmf_sdiod_regwl(sdiodev, addr, gpiocontrol, &ret);
140
141 brcmf_sdiod_regwb(sdiodev, SBSDIO_GPIO_SELECT, 0xf,
142 &ret);
143 brcmf_sdiod_regwb(sdiodev, SBSDIO_GPIO_OUT, 0, &ret);
144 brcmf_sdiod_regwb(sdiodev, SBSDIO_GPIO_EN, 0x2, &ret);
145 }
146
Hante Meuleman668761a2013-04-12 10:55:55 +0200147 /* must configure SDIO_CCCR_IENx to enable irq */
Arend van Spriela39be272013-12-12 11:58:58 +0100148 data = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
Hante Meuleman668761a2013-04-12 10:55:55 +0200149 data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
Arend van Spriela39be272013-12-12 11:58:58 +0100150 brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
Hante Meuleman668761a2013-04-12 10:55:55 +0200151
152 /* redirect, configure and enable io for interrupt signal */
153 data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
154 if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
155 data |= SDIO_SEPINT_ACT_HI;
Arend van Spriela39be272013-12-12 11:58:58 +0100156 brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
Hante Meuleman668761a2013-04-12 10:55:55 +0200157
158 sdio_release_host(sdiodev->func[1]);
159 } else {
160 brcmf_dbg(SDIO, "Entering\n");
161 sdio_claim_host(sdiodev->func[1]);
Arend van Spriela39be272013-12-12 11:58:58 +0100162 sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler);
163 sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler);
Hante Meuleman668761a2013-04-12 10:55:55 +0200164 sdio_release_host(sdiodev->func[1]);
165 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200166
167 return 0;
168}
169
Arend van Spriela39be272013-12-12 11:58:58 +0100170int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200171{
Arend van Sprielc3203372013-04-03 12:40:44 +0200172 brcmf_dbg(SDIO, "Entering\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200173
Hante Meuleman668761a2013-04-12 10:55:55 +0200174 if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
175 sdio_claim_host(sdiodev->func[1]);
Arend van Spriela39be272013-12-12 11:58:58 +0100176 brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
177 brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
Hante Meuleman668761a2013-04-12 10:55:55 +0200178 sdio_release_host(sdiodev->func[1]);
179
180 if (sdiodev->oob_irq_requested) {
181 sdiodev->oob_irq_requested = false;
182 if (sdiodev->irq_wake) {
183 disable_irq_wake(sdiodev->pdata->oob_irq_nr);
184 sdiodev->irq_wake = false;
185 }
186 free_irq(sdiodev->pdata->oob_irq_nr,
187 &sdiodev->func[1]->dev);
188 sdiodev->irq_en = false;
189 }
190 } else {
191 sdio_claim_host(sdiodev->func[1]);
192 sdio_release_irq(sdiodev->func[2]);
193 sdio_release_irq(sdiodev->func[1]);
194 sdio_release_host(sdiodev->func[1]);
195 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200196
197 return 0;
198}
199
Arend van Spriela1ce7a02015-02-06 18:36:42 +0100200void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
201 enum brcmf_sdiod_state state)
202{
203 if (sdiodev->state == BRCMF_SDIOD_NOMEDIUM ||
204 state == sdiodev->state)
205 return;
206
207 brcmf_dbg(TRACE, "%d -> %d\n", sdiodev->state, state);
208 switch (sdiodev->state) {
209 case BRCMF_SDIOD_DATA:
210 /* any other state means bus interface is down */
211 brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);
212 break;
213 case BRCMF_SDIOD_DOWN:
214 /* transition from DOWN to DATA means bus interface is up */
215 if (state == BRCMF_SDIOD_DATA)
216 brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_UP);
217 break;
218 default:
219 break;
220 }
221 sdiodev->state = state;
222}
223
Arend van Spriel36c4e7e2013-12-12 11:59:06 +0100224static inline int brcmf_sdiod_f0_writeb(struct sdio_func *func,
225 uint regaddr, u8 byte)
Arend van Spriele49b06b2013-12-12 11:58:51 +0100226{
Arend van Spriele49b06b2013-12-12 11:58:51 +0100227 int err_ret;
228
229 /*
230 * Can only directly write to some F0 registers.
Arend van Spriel36c4e7e2013-12-12 11:59:06 +0100231 * Handle CCCR_IENx and CCCR_ABORT command
Arend van Spriele49b06b2013-12-12 11:58:51 +0100232 * as a special case.
233 */
Arend van Spriel71370eb2013-12-12 11:58:53 +0100234 if ((regaddr == SDIO_CCCR_ABORT) ||
Arend van Spriel36c4e7e2013-12-12 11:59:06 +0100235 (regaddr == SDIO_CCCR_IENx))
236 sdio_writeb(func, byte, regaddr, &err_ret);
237 else
238 sdio_f0_writeb(func, byte, regaddr, &err_ret);
Arend van Spriele49b06b2013-12-12 11:58:51 +0100239
240 return err_ret;
241}
242
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100243static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
244 u32 addr, u8 regsz, void *data, bool write)
Arend van Spriele49b06b2013-12-12 11:58:51 +0100245{
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100246 struct sdio_func *func;
247 int ret;
Arend van Spriele49b06b2013-12-12 11:58:51 +0100248
249 brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100250 write, fn, addr, regsz);
Arend van Spriele49b06b2013-12-12 11:58:51 +0100251
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100252 /* only allow byte access on F0 */
253 if (WARN_ON(regsz > 1 && !fn))
254 return -EINVAL;
255 func = sdiodev->func[fn];
256
257 switch (regsz) {
258 case sizeof(u8):
259 if (write) {
260 if (fn)
261 sdio_writeb(func, *(u8 *)data, addr, &ret);
262 else
263 ret = brcmf_sdiod_f0_writeb(func, addr,
264 *(u8 *)data);
265 } else {
266 if (fn)
267 *(u8 *)data = sdio_readb(func, addr, &ret);
268 else
269 *(u8 *)data = sdio_f0_readb(func, addr, &ret);
270 }
271 break;
272 case sizeof(u16):
273 if (write)
274 sdio_writew(func, *(u16 *)data, addr, &ret);
Arend van Spriele49b06b2013-12-12 11:58:51 +0100275 else
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100276 *(u16 *)data = sdio_readw(func, addr, &ret);
277 break;
278 case sizeof(u32):
279 if (write)
280 sdio_writel(func, *(u32 *)data, addr, &ret);
Arend van Spriele49b06b2013-12-12 11:58:51 +0100281 else
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100282 *(u32 *)data = sdio_readl(func, addr, &ret);
283 break;
284 default:
285 brcmf_err("invalid size: %d\n", regsz);
286 break;
Arend van Spriele49b06b2013-12-12 11:58:51 +0100287 }
288
Arend van Spriel4d1a4f12014-03-20 10:18:02 +0100289 if (ret)
290 brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
291 write ? "write" : "read", fn, addr, ret);
292
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100293 return ret;
294}
Arend van Spriele49b06b2013-12-12 11:58:51 +0100295
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100296static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
297 u8 regsz, void *data, bool write)
298{
Arend van Spriel4d1a4f12014-03-20 10:18:02 +0100299 u8 func;
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100300 s32 retry = 0;
301 int ret;
302
Arend van Spriela1ce7a02015-02-06 18:36:42 +0100303 if (sdiodev->state == BRCMF_SDIOD_NOMEDIUM)
Arend van Sprielbb350712014-01-13 22:20:29 +0100304 return -ENOMEDIUM;
305
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100306 /*
307 * figure out how to read the register based on address range
308 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
309 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
310 * The rest: function 1 silicon backplane core registers
311 */
312 if ((addr & ~REG_F0_REG_MASK) == 0)
Arend van Spriel4d1a4f12014-03-20 10:18:02 +0100313 func = SDIO_FUNC_0;
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100314 else
Arend van Spriel4d1a4f12014-03-20 10:18:02 +0100315 func = SDIO_FUNC_1;
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100316
317 do {
318 if (!write)
319 memset(data, 0, regsz);
320 /* for retry wait for 1 ms till bus get settled down */
321 if (retry)
322 usleep_range(1000, 2000);
Arend van Spriel4d1a4f12014-03-20 10:18:02 +0100323 ret = brcmf_sdiod_request_data(sdiodev, func, addr, regsz,
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100324 data, write);
Arend van Sprielbb350712014-01-13 22:20:29 +0100325 } while (ret != 0 && ret != -ENOMEDIUM &&
326 retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100327
Arend van Sprielbb350712014-01-13 22:20:29 +0100328 if (ret == -ENOMEDIUM)
Arend van Spriela1ce7a02015-02-06 18:36:42 +0100329 brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);
Arend van Spriel4d1a4f12014-03-20 10:18:02 +0100330 else if (ret != 0) {
331 /*
332 * SleepCSR register access can fail when
333 * waking up the device so reduce this noise
334 * in the logs.
335 */
336 if (addr != SBSDIO_FUNC1_SLEEPCSR)
337 brcmf_err("failed to %s data F%d@0x%05x, err: %d\n",
338 write ? "write" : "read", func, addr, ret);
339 else
340 brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
341 write ? "write" : "read", func, addr, ret);
342 }
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100343 return ret;
Arend van Spriele49b06b2013-12-12 11:58:51 +0100344}
345
Franky Lin356bae62013-06-26 14:20:17 +0200346static int
Arend van Spriela39be272013-12-12 11:58:58 +0100347brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200348{
Franky Lin7d9cfc22012-05-04 18:27:30 -0700349 int err = 0, i;
350 u8 addr[3];
Franky Lin7d9cfc22012-05-04 18:27:30 -0700351
Arend van Spriela1ce7a02015-02-06 18:36:42 +0100352 if (sdiodev->state == BRCMF_SDIOD_NOMEDIUM)
Arend van Sprielbb350712014-01-13 22:20:29 +0100353 return -ENOMEDIUM;
354
Franky Lin7d9cfc22012-05-04 18:27:30 -0700355 addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
356 addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
357 addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
358
359 for (i = 0; i < 3; i++) {
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100360 err = brcmf_sdiod_regrw_helper(sdiodev,
361 SBSDIO_FUNC1_SBADDRLOW + i,
362 sizeof(u8), &addr[i], true);
Franky Lin7d9cfc22012-05-04 18:27:30 -0700363 if (err) {
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100364 brcmf_err("failed at addr: 0x%0x\n",
Franky Lin7d9cfc22012-05-04 18:27:30 -0700365 SBSDIO_FUNC1_SBADDRLOW + i);
366 break;
367 }
368 }
Arend van Spriel5b435de2011-10-05 13:19:03 +0200369
370 return err;
371}
372
Franky Lin356bae62013-06-26 14:20:17 +0200373static int
Arend van Spriela39be272013-12-12 11:58:58 +0100374brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
Franky Lin356bae62013-06-26 14:20:17 +0200375{
376 uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
377 int err = 0;
378
379 if (bar0 != sdiodev->sbwad) {
Arend van Spriela39be272013-12-12 11:58:58 +0100380 err = brcmf_sdiod_set_sbaddr_window(sdiodev, bar0);
Franky Lin356bae62013-06-26 14:20:17 +0200381 if (err)
382 return err;
383
384 sdiodev->sbwad = bar0;
385 }
386
387 *addr &= SBSDIO_SB_OFT_ADDR_MASK;
388
389 if (width == 4)
390 *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
391
392 return 0;
393}
394
Arend van Spriela39be272013-12-12 11:58:58 +0100395u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
Franky Line9b8d912012-05-04 18:27:31 -0700396{
397 u8 data;
398 int retval;
399
Arend van Sprielc3203372013-04-03 12:40:44 +0200400 brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100401 retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
402 false);
Arend van Sprielc3203372013-04-03 12:40:44 +0200403 brcmf_dbg(SDIO, "data:0x%02x\n", data);
Franky Line9b8d912012-05-04 18:27:31 -0700404
405 if (ret)
406 *ret = retval;
407
408 return data;
409}
410
Arend van Spriela39be272013-12-12 11:58:58 +0100411u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
Franky Line9b8d912012-05-04 18:27:31 -0700412{
413 u32 data;
414 int retval;
415
Arend van Sprielc3203372013-04-03 12:40:44 +0200416 brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100417 retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr);
418 if (retval)
419 goto done;
420 retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
421 false);
Arend van Sprielc3203372013-04-03 12:40:44 +0200422 brcmf_dbg(SDIO, "data:0x%08x\n", data);
Franky Line9b8d912012-05-04 18:27:31 -0700423
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100424done:
Franky Line9b8d912012-05-04 18:27:31 -0700425 if (ret)
426 *ret = retval;
427
428 return data;
429}
430
Arend van Spriela39be272013-12-12 11:58:58 +0100431void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
Franky Line9b8d912012-05-04 18:27:31 -0700432 u8 data, int *ret)
433{
434 int retval;
435
Arend van Sprielc3203372013-04-03 12:40:44 +0200436 brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100437 retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
438 true);
Franky Line9b8d912012-05-04 18:27:31 -0700439 if (ret)
440 *ret = retval;
441}
442
Arend van Spriela39be272013-12-12 11:58:58 +0100443void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
Franky Line9b8d912012-05-04 18:27:31 -0700444 u32 data, int *ret)
445{
446 int retval;
447
Arend van Sprielc3203372013-04-03 12:40:44 +0200448 brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100449 retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr);
450 if (retval)
451 goto done;
452 retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
453 true);
Franky Line9b8d912012-05-04 18:27:31 -0700454
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100455done:
Franky Line9b8d912012-05-04 18:27:31 -0700456 if (ret)
457 *ret = retval;
458}
459
Arend van Spriela39be272013-12-12 11:58:58 +0100460static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
Arend van Spriel4aef2672013-10-15 15:44:52 +0200461 bool write, u32 addr, struct sk_buff *pkt)
462{
463 unsigned int req_sz;
Arend van Sprielbb350712014-01-13 22:20:29 +0100464 int err;
Arend van Spriel4aef2672013-10-15 15:44:52 +0200465
Arend van Spriel4aef2672013-10-15 15:44:52 +0200466 /* Single skb use the standard mmc interface */
467 req_sz = pkt->len + 3;
468 req_sz &= (uint)~3;
469
470 if (write)
Arend van Sprielbb350712014-01-13 22:20:29 +0100471 err = sdio_memcpy_toio(sdiodev->func[fn], addr,
472 ((u8 *)(pkt->data)), req_sz);
Arend van Spriel4aef2672013-10-15 15:44:52 +0200473 else if (fn == 1)
Arend van Sprielbb350712014-01-13 22:20:29 +0100474 err = sdio_memcpy_fromio(sdiodev->func[fn], ((u8 *)(pkt->data)),
475 addr, req_sz);
Arend van Spriel4aef2672013-10-15 15:44:52 +0200476 else
477 /* function 2 read is FIFO operation */
Arend van Sprielbb350712014-01-13 22:20:29 +0100478 err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr,
479 req_sz);
480 if (err == -ENOMEDIUM)
Arend van Spriela1ce7a02015-02-06 18:36:42 +0100481 brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);
Arend van Sprielbb350712014-01-13 22:20:29 +0100482 return err;
Arend van Spriel4aef2672013-10-15 15:44:52 +0200483}
484
Franky Lin78b3f1c2013-06-18 13:29:28 +0200485/**
Arend van Spriela39be272013-12-12 11:58:58 +0100486 * brcmf_sdiod_sglist_rw - SDIO interface function for block data access
Franky Lin78b3f1c2013-06-18 13:29:28 +0200487 * @sdiodev: brcmfmac sdio device
488 * @fn: SDIO function number
489 * @write: direction flag
490 * @addr: dongle memory address as source/destination
491 * @pkt: skb pointer
492 *
493 * This function takes the respbonsibility as the interface function to MMC
494 * stack for block data access. It assumes that the skb passed down by the
495 * caller has already been padded and aligned.
496 */
Arend van Spriela39be272013-12-12 11:58:58 +0100497static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
498 bool write, u32 addr,
499 struct sk_buff_head *pktlist)
Franky Lin78b3f1c2013-06-18 13:29:28 +0200500{
Franky Lin354b75b2013-06-18 13:29:29 +0200501 unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset;
Arend van Spriel71201492013-10-15 15:44:49 +0200502 unsigned int max_req_sz, orig_offset, dst_offset;
Arend van Spriel3f782742013-10-15 15:44:48 +0200503 unsigned short max_seg_cnt, seg_sz;
Franky Lin3b81a682013-06-26 14:20:18 +0200504 unsigned char *pkt_data, *orig_data, *dst_data;
505 struct sk_buff *pkt_next = NULL, *local_pkt_next;
506 struct sk_buff_head local_list, *target_list;
Franky Lin354b75b2013-06-18 13:29:29 +0200507 struct mmc_request mmc_req;
508 struct mmc_command mmc_cmd;
509 struct mmc_data mmc_dat;
Franky Lin354b75b2013-06-18 13:29:29 +0200510 struct scatterlist *sgl;
Franky Lin354b75b2013-06-18 13:29:29 +0200511 int ret = 0;
512
513 if (!pktlist->qlen)
514 return -EINVAL;
Franky Lin78b3f1c2013-06-18 13:29:28 +0200515
Franky Lin3b81a682013-06-26 14:20:18 +0200516 target_list = pktlist;
517 /* for host with broken sg support, prepare a page aligned list */
518 __skb_queue_head_init(&local_list);
519 if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
520 req_sz = 0;
521 skb_queue_walk(pktlist, pkt_next)
522 req_sz += pkt_next->len;
523 req_sz = ALIGN(req_sz, sdiodev->func[fn]->cur_blksize);
524 while (req_sz > PAGE_SIZE) {
525 pkt_next = brcmu_pkt_buf_get_skb(PAGE_SIZE);
526 if (pkt_next == NULL) {
527 ret = -ENOMEM;
528 goto exit;
529 }
530 __skb_queue_tail(&local_list, pkt_next);
531 req_sz -= PAGE_SIZE;
532 }
533 pkt_next = brcmu_pkt_buf_get_skb(req_sz);
534 if (pkt_next == NULL) {
535 ret = -ENOMEM;
536 goto exit;
537 }
538 __skb_queue_tail(&local_list, pkt_next);
539 target_list = &local_list;
540 }
541
Franky Lin354b75b2013-06-18 13:29:29 +0200542 func_blk_sz = sdiodev->func[fn]->cur_blksize;
Arend van Spriel71201492013-10-15 15:44:49 +0200543 max_req_sz = sdiodev->max_request_size;
544 max_seg_cnt = min_t(unsigned short, sdiodev->max_segment_count,
545 target_list->qlen);
Franky Lin3b81a682013-06-26 14:20:18 +0200546 seg_sz = target_list->qlen;
Franky Lin354b75b2013-06-18 13:29:29 +0200547 pkt_offset = 0;
Franky Lin3b81a682013-06-26 14:20:18 +0200548 pkt_next = target_list->next;
Franky Lin354b75b2013-06-18 13:29:29 +0200549
Arend van Spriel7f9a8dc2013-10-15 15:44:50 +0200550 memset(&mmc_req, 0, sizeof(struct mmc_request));
551 memset(&mmc_cmd, 0, sizeof(struct mmc_command));
552 memset(&mmc_dat, 0, sizeof(struct mmc_data));
553
Arend van Sprielaf1fa212014-02-27 19:25:00 +0100554 mmc_dat.sg = sdiodev->sgtable.sgl;
Arend van Spriel7f9a8dc2013-10-15 15:44:50 +0200555 mmc_dat.blksz = func_blk_sz;
556 mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
557 mmc_cmd.opcode = SD_IO_RW_EXTENDED;
558 mmc_cmd.arg = write ? 1<<31 : 0; /* write flag */
559 mmc_cmd.arg |= (fn & 0x7) << 28; /* SDIO func num */
560 mmc_cmd.arg |= 1<<27; /* block mode */
561 /* for function 1 the addr will be incremented */
562 mmc_cmd.arg |= (fn == 1) ? 1<<26 : 0;
563 mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
564 mmc_req.cmd = &mmc_cmd;
565 mmc_req.data = &mmc_dat;
566
Franky Lin354b75b2013-06-18 13:29:29 +0200567 while (seg_sz) {
568 req_sz = 0;
569 sg_cnt = 0;
Arend van Sprielaf1fa212014-02-27 19:25:00 +0100570 sgl = sdiodev->sgtable.sgl;
Franky Lin354b75b2013-06-18 13:29:29 +0200571 /* prep sg table */
Franky Lin3b81a682013-06-26 14:20:18 +0200572 while (pkt_next != (struct sk_buff *)target_list) {
Franky Lin354b75b2013-06-18 13:29:29 +0200573 pkt_data = pkt_next->data + pkt_offset;
574 sg_data_sz = pkt_next->len - pkt_offset;
Arend van Spriel71201492013-10-15 15:44:49 +0200575 if (sg_data_sz > sdiodev->max_segment_size)
576 sg_data_sz = sdiodev->max_segment_size;
Franky Lin354b75b2013-06-18 13:29:29 +0200577 if (sg_data_sz > max_req_sz - req_sz)
578 sg_data_sz = max_req_sz - req_sz;
579
580 sg_set_buf(sgl, pkt_data, sg_data_sz);
581
582 sg_cnt++;
583 sgl = sg_next(sgl);
584 req_sz += sg_data_sz;
585 pkt_offset += sg_data_sz;
586 if (pkt_offset == pkt_next->len) {
587 pkt_offset = 0;
588 pkt_next = pkt_next->next;
589 }
590
Arend van Spriel3f782742013-10-15 15:44:48 +0200591 if (req_sz >= max_req_sz || sg_cnt >= max_seg_cnt)
Franky Lin354b75b2013-06-18 13:29:29 +0200592 break;
593 }
594 seg_sz -= sg_cnt;
595
596 if (req_sz % func_blk_sz != 0) {
597 brcmf_err("sg request length %u is not %u aligned\n",
598 req_sz, func_blk_sz);
Franky Lin3b81a682013-06-26 14:20:18 +0200599 ret = -ENOTBLK;
600 goto exit;
Franky Lin354b75b2013-06-18 13:29:29 +0200601 }
Arend van Spriel7f9a8dc2013-10-15 15:44:50 +0200602
Franky Lin354b75b2013-06-18 13:29:29 +0200603 mmc_dat.sg_len = sg_cnt;
Franky Lin354b75b2013-06-18 13:29:29 +0200604 mmc_dat.blocks = req_sz / func_blk_sz;
Franky Lin354b75b2013-06-18 13:29:29 +0200605 mmc_cmd.arg |= (addr & 0x1FFFF) << 9; /* address */
606 mmc_cmd.arg |= mmc_dat.blocks & 0x1FF; /* block count */
Arend van Spriel7f9a8dc2013-10-15 15:44:50 +0200607 /* incrementing addr for function 1 */
Franky Lin354b75b2013-06-18 13:29:29 +0200608 if (fn == 1)
609 addr += req_sz;
610
611 mmc_set_data_timeout(&mmc_dat, sdiodev->func[fn]->card);
Arend van Spriel71201492013-10-15 15:44:49 +0200612 mmc_wait_for_req(sdiodev->func[fn]->card->host, &mmc_req);
Franky Lin354b75b2013-06-18 13:29:29 +0200613
614 ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
Arend van Sprielbb350712014-01-13 22:20:29 +0100615 if (ret == -ENOMEDIUM) {
Arend van Spriela1ce7a02015-02-06 18:36:42 +0100616 brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);
Arend van Sprielbb350712014-01-13 22:20:29 +0100617 break;
618 } else if (ret != 0) {
Franky Lin354b75b2013-06-18 13:29:29 +0200619 brcmf_err("CMD53 sg block %s failed %d\n",
620 write ? "write" : "read", ret);
621 ret = -EIO;
622 break;
623 }
624 }
625
Franky Lin3b81a682013-06-26 14:20:18 +0200626 if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
627 local_pkt_next = local_list.next;
628 orig_offset = 0;
629 skb_queue_walk(pktlist, pkt_next) {
630 dst_offset = 0;
631 do {
632 req_sz = local_pkt_next->len - orig_offset;
633 req_sz = min_t(uint, pkt_next->len - dst_offset,
634 req_sz);
635 orig_data = local_pkt_next->data + orig_offset;
636 dst_data = pkt_next->data + dst_offset;
637 memcpy(dst_data, orig_data, req_sz);
638 orig_offset += req_sz;
639 dst_offset += req_sz;
640 if (orig_offset == local_pkt_next->len) {
641 orig_offset = 0;
642 local_pkt_next = local_pkt_next->next;
643 }
644 if (dst_offset == pkt_next->len)
645 break;
646 } while (!skb_queue_empty(&local_list));
647 }
648 }
649
650exit:
Arend van Sprielaf1fa212014-02-27 19:25:00 +0100651 sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents);
Franky Lin3b81a682013-06-26 14:20:18 +0200652 while ((pkt_next = __skb_dequeue(&local_list)) != NULL)
653 brcmu_pkt_buf_free_skb(pkt_next);
Franky Lin354b75b2013-06-18 13:29:29 +0200654
655 return ret;
Franky Lin78b3f1c2013-06-18 13:29:28 +0200656}
657
Arend van Spriela7cdd822013-12-12 11:58:59 +0100658int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800659{
660 struct sk_buff *mypkt;
661 int err;
662
663 mypkt = brcmu_pkt_buf_get_skb(nbytes);
664 if (!mypkt) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100665 brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800666 nbytes);
667 return -EIO;
668 }
669
Arend van Spriela7cdd822013-12-12 11:58:59 +0100670 err = brcmf_sdiod_recv_pkt(sdiodev, mypkt);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800671 if (!err)
672 memcpy(buf, mypkt->data, nbytes);
673
674 brcmu_pkt_buf_free_skb(mypkt);
675 return err;
676}
677
Arend van Spriela7cdd822013-12-12 11:58:59 +0100678int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt)
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800679{
Arend van Spriela7cdd822013-12-12 11:58:59 +0100680 u32 addr = sdiodev->sbwad;
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800681 int err = 0;
682
Arend van Spriela7cdd822013-12-12 11:58:59 +0100683 brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pkt->len);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800684
Arend van Spriela7cdd822013-12-12 11:58:59 +0100685 err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800686 if (err)
Franky Lin7057fd02012-09-13 21:12:02 +0200687 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200688
Arend van Spriela7cdd822013-12-12 11:58:59 +0100689 err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, pkt);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800690
Franky Lin7057fd02012-09-13 21:12:02 +0200691done:
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800692 return err;
693}
694
Arend van Spriela7cdd822013-12-12 11:58:59 +0100695int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
696 struct sk_buff_head *pktq, uint totlen)
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800697{
Arend van Spriela413e392013-10-15 15:44:57 +0200698 struct sk_buff *glom_skb;
699 struct sk_buff *skb;
Arend van Spriela7cdd822013-12-12 11:58:59 +0100700 u32 addr = sdiodev->sbwad;
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800701 int err = 0;
702
Arend van Spriela7cdd822013-12-12 11:58:59 +0100703 brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n",
704 addr, pktq->qlen);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800705
Arend van Spriela7cdd822013-12-12 11:58:59 +0100706 err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800707 if (err)
Franky Lin7057fd02012-09-13 21:12:02 +0200708 goto done;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200709
Arend van Spriela413e392013-10-15 15:44:57 +0200710 if (pktq->qlen == 1)
Arend van Spriela7cdd822013-12-12 11:58:59 +0100711 err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
712 pktq->next);
Arend van Spriela413e392013-10-15 15:44:57 +0200713 else if (!sdiodev->sg_support) {
714 glom_skb = brcmu_pkt_buf_get_skb(totlen);
715 if (!glom_skb)
716 return -ENOMEM;
Arend van Spriela7cdd822013-12-12 11:58:59 +0100717 err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
718 glom_skb);
Arend van Spriela413e392013-10-15 15:44:57 +0200719 if (err)
720 goto done;
721
722 skb_queue_walk(pktq, skb) {
723 memcpy(skb->data, glom_skb->data, skb->len);
724 skb_pull(glom_skb, skb->len);
725 }
726 } else
Arend van Spriela7cdd822013-12-12 11:58:59 +0100727 err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, false, addr,
728 pktq);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200729
Franky Lin7057fd02012-09-13 21:12:02 +0200730done:
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800731 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200732}
733
Arend van Spriela7cdd822013-12-12 11:58:59 +0100734int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800735{
736 struct sk_buff *mypkt;
Arend van Spriela7cdd822013-12-12 11:58:59 +0100737 u32 addr = sdiodev->sbwad;
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800738 int err;
739
740 mypkt = brcmu_pkt_buf_get_skb(nbytes);
741 if (!mypkt) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100742 brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800743 nbytes);
744 return -EIO;
745 }
746
747 memcpy(mypkt->data, buf, nbytes);
Arend van Spriel4aef2672013-10-15 15:44:52 +0200748
Arend van Spriela7cdd822013-12-12 11:58:59 +0100749 err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
Arend van Spriel4aef2672013-10-15 15:44:52 +0200750
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200751 if (!err)
Arend van Spriela7cdd822013-12-12 11:58:59 +0100752 err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true, addr,
753 mypkt);
Arend van Spriel5adfeb62011-11-22 17:21:38 -0800754
755 brcmu_pkt_buf_free_skb(mypkt);
756 return err;
757
758}
759
Arend van Spriela7cdd822013-12-12 11:58:59 +0100760int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
761 struct sk_buff_head *pktq)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200762{
Arend van Sprielc8cce1f2013-10-15 15:44:55 +0200763 struct sk_buff *skb;
Arend van Spriela7cdd822013-12-12 11:58:59 +0100764 u32 addr = sdiodev->sbwad;
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200765 int err;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200766
Arend van Spriela7cdd822013-12-12 11:58:59 +0100767 brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pktq->qlen);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200768
Arend van Spriela7cdd822013-12-12 11:58:59 +0100769 err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
Arend van Sprielfcaac2b2013-10-15 15:44:53 +0200770 if (err)
771 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200772
Arend van Sprielc8cce1f2013-10-15 15:44:55 +0200773 if (pktq->qlen == 1 || !sdiodev->sg_support)
774 skb_queue_walk(pktq, skb) {
Arend van Spriela7cdd822013-12-12 11:58:59 +0100775 err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true,
776 addr, skb);
Arend van Sprielc8cce1f2013-10-15 15:44:55 +0200777 if (err)
778 break;
779 }
780 else
Arend van Spriela7cdd822013-12-12 11:58:59 +0100781 err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, true, addr,
782 pktq);
Arend van Sprielc8cce1f2013-10-15 15:44:55 +0200783
784 return err;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200785}
786
Franky Linba540b02013-04-11 13:28:47 +0200787int
Arend van Spriela39be272013-12-12 11:58:58 +0100788brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
789 u8 *data, uint size)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200790{
Franky Linba540b02013-04-11 13:28:47 +0200791 int bcmerror = 0;
792 struct sk_buff *pkt;
793 u32 sdaddr;
794 uint dsize;
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800795
Franky Linba540b02013-04-11 13:28:47 +0200796 dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
797 pkt = dev_alloc_skb(dsize);
798 if (!pkt) {
799 brcmf_err("dev_alloc_skb failed: len %d\n", dsize);
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800800 return -EIO;
801 }
Franky Linba540b02013-04-11 13:28:47 +0200802 pkt->priority = 0;
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800803
Franky Linba540b02013-04-11 13:28:47 +0200804 /* Determine initial transfer parameters */
805 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
806 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
807 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
808 else
809 dsize = size;
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800810
Franky Linba540b02013-04-11 13:28:47 +0200811 sdio_claim_host(sdiodev->func[1]);
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800812
Franky Linba540b02013-04-11 13:28:47 +0200813 /* Do the transfer(s) */
814 while (size) {
815 /* Set the backplane window to include the start address */
Arend van Spriela39be272013-12-12 11:58:58 +0100816 bcmerror = brcmf_sdiod_set_sbaddr_window(sdiodev, address);
Franky Linba540b02013-04-11 13:28:47 +0200817 if (bcmerror)
818 break;
Arend van Spriel4c6e8692011-11-22 17:21:40 -0800819
Franky Linba540b02013-04-11 13:28:47 +0200820 brcmf_dbg(SDIO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
821 write ? "write" : "read", dsize,
822 sdaddr, address & SBSDIO_SBWINDOW_MASK);
823
824 sdaddr &= SBSDIO_SB_OFT_ADDR_MASK;
825 sdaddr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
826
827 skb_put(pkt, dsize);
828 if (write)
829 memcpy(pkt->data, data, dsize);
Arend van Spriela39be272013-12-12 11:58:58 +0100830 bcmerror = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_1, write,
831 sdaddr, pkt);
Franky Linba540b02013-04-11 13:28:47 +0200832 if (bcmerror) {
833 brcmf_err("membytes transfer failed\n");
834 break;
835 }
836 if (!write)
837 memcpy(data, pkt->data, dsize);
Hante Meuleman79c868e2014-01-29 15:32:16 +0100838 skb_trim(pkt, 0);
Franky Linba540b02013-04-11 13:28:47 +0200839
840 /* Adjust for next transfer (if any) */
841 size -= dsize;
842 if (size) {
843 data += dsize;
844 address += dsize;
845 sdaddr = 0;
846 dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
847 }
848 }
849
850 dev_kfree_skb(pkt);
851
852 /* Return the window to backplane enumeration space for core access */
Arend van Spriela39be272013-12-12 11:58:58 +0100853 if (brcmf_sdiod_set_sbaddr_window(sdiodev, sdiodev->sbwad))
Franky Linba540b02013-04-11 13:28:47 +0200854 brcmf_err("FAILED to set window back to 0x%x\n",
855 sdiodev->sbwad);
856
857 sdio_release_host(sdiodev->func[1]);
858
859 return bcmerror;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200860}
861
Arend van Spriela39be272013-12-12 11:58:58 +0100862int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200863{
864 char t_func = (char)fn;
Arend van Sprielc3203372013-04-03 12:40:44 +0200865 brcmf_dbg(SDIO, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200866
867 /* issue abort cmd52 command through F0 */
Arend van Spriel71c60cf2014-01-06 12:40:36 +0100868 brcmf_sdiod_request_data(sdiodev, SDIO_FUNC_0, SDIO_CCCR_ABORT,
869 sizeof(t_func), &t_func, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200870
Arend van Sprielc3203372013-04-03 12:40:44 +0200871 brcmf_dbg(SDIO, "Exit\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200872 return 0;
873}
874
Arend van Sprielaf1fa212014-02-27 19:25:00 +0100875static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
876{
877 uint nents;
878 int err;
879
880 if (!sdiodev->sg_support)
881 return;
882
883 nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz);
884 nents += (nents >> 4) + 1;
885
886 WARN_ON(nents > sdiodev->max_segment_count);
887
888 brcmf_dbg(TRACE, "nents=%d\n", nents);
889 err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL);
890 if (err < 0) {
891 brcmf_err("allocation failed: disable scatter-gather");
892 sdiodev->sg_support = false;
893 }
894
895 sdiodev->txglomsz = brcmf_sdiod_txglomsz;
896}
897
Arend van Spriela39be272013-12-12 11:58:58 +0100898static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100899{
Arend van Spriela39be272013-12-12 11:58:58 +0100900 if (sdiodev->bus) {
Arend van Spriel9fbe2a62013-12-12 11:59:05 +0100901 brcmf_sdio_remove(sdiodev->bus);
Arend van Spriela39be272013-12-12 11:58:58 +0100902 sdiodev->bus = NULL;
903 }
904
905 /* Disable Function 2 */
906 sdio_claim_host(sdiodev->func[2]);
907 sdio_disable_func(sdiodev->func[2]);
908 sdio_release_host(sdiodev->func[2]);
909
910 /* Disable Function 1 */
911 sdio_claim_host(sdiodev->func[1]);
912 sdio_disable_func(sdiodev->func[1]);
913 sdio_release_host(sdiodev->func[1]);
914
Arend van Sprielaf1fa212014-02-27 19:25:00 +0100915 sg_free_table(&sdiodev->sgtable);
Arend van Spriela39be272013-12-12 11:58:58 +0100916 sdiodev->sbwad = 0;
917
918 return 0;
919}
920
921static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
922{
923 struct sdio_func *func;
924 struct mmc_host *host;
925 uint max_blocks;
926 int ret = 0;
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100927
928 sdiodev->num_funcs = 2;
929
930 sdio_claim_host(sdiodev->func[1]);
931
Arend van Spriela39be272013-12-12 11:58:58 +0100932 ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
933 if (ret) {
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100934 brcmf_err("Failed to set F1 blocksize\n");
Arend van Spriela39be272013-12-12 11:58:58 +0100935 sdio_release_host(sdiodev->func[1]);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100936 goto out;
937 }
Arend van Spriela39be272013-12-12 11:58:58 +0100938 ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
939 if (ret) {
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100940 brcmf_err("Failed to set F2 blocksize\n");
Arend van Spriela39be272013-12-12 11:58:58 +0100941 sdio_release_host(sdiodev->func[1]);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100942 goto out;
943 }
944
Arend van Spriel71370eb2013-12-12 11:58:53 +0100945 /* increase F2 timeout */
946 sdiodev->func[2]->enable_timeout = SDIO_WAIT_F2RDY;
947
Arend van Spriel463c30b2013-12-12 11:58:52 +0100948 /* Enable Function 1 */
Arend van Spriela39be272013-12-12 11:58:58 +0100949 ret = sdio_enable_func(sdiodev->func[1]);
950 sdio_release_host(sdiodev->func[1]);
951 if (ret) {
952 brcmf_err("Failed to enable F1: err=%d\n", ret);
Arend van Spriel463c30b2013-12-12 11:58:52 +0100953 goto out;
954 }
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100955
956 /*
Arend van Spriela39be272013-12-12 11:58:58 +0100957 * determine host related variables after brcmf_sdiod_probe()
Arend van Spriele2dc9ee2013-12-12 11:58:50 +0100958 * as func->cur_blksize is properly set and F2 init has been
959 * completed successfully.
960 */
961 func = sdiodev->func[2];
962 host = func->card->host;
963 sdiodev->sg_support = host->max_segs > 1;
964 max_blocks = min_t(uint, host->max_blk_count, 511u);
965 sdiodev->max_request_size = min_t(uint, host->max_req_size,
966 max_blocks * func->cur_blksize);
967 sdiodev->max_segment_count = min_t(uint, host->max_segs,
968 SG_MAX_SINGLE_ALLOC);
969 sdiodev->max_segment_size = host->max_seg_size;
Arend van Spriele49b06b2013-12-12 11:58:51 +0100970
Arend van Sprielaf1fa212014-02-27 19:25:00 +0100971 /* allocate scatter-gather table. sg support
972 * will be disabled upon allocation failure.
973 */
974 brcmf_sdiod_sgtable_alloc(sdiodev);
975
Arend van Spriele49b06b2013-12-12 11:58:51 +0100976 /* try to attach to the target device */
Arend van Spriel82d7f3c2013-12-12 11:59:04 +0100977 sdiodev->bus = brcmf_sdio_probe(sdiodev);
Arend van Spriele49b06b2013-12-12 11:58:51 +0100978 if (!sdiodev->bus) {
Arend van Spriele49b06b2013-12-12 11:58:51 +0100979 ret = -ENODEV;
980 goto out;
981 }
982
983out:
984 if (ret)
Arend van Spriela39be272013-12-12 11:58:58 +0100985 brcmf_sdiod_remove(sdiodev);
Arend van Spriele49b06b2013-12-12 11:58:51 +0100986
987 return ret;
988}
989
Hante Meuleman5779ae62014-07-12 08:49:34 +0200990#define BRCMF_SDIO_DEVICE(dev_id) \
Arend van Spriel8bd61f82015-01-06 23:02:54 +0100991 {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id)}
Hante Meuleman5779ae62014-07-12 08:49:34 +0200992
Arend van Spriele49b06b2013-12-12 11:58:51 +0100993/* devices we support, null terminated */
994static const struct sdio_device_id brcmf_sdmmc_ids[] = {
Arend van Spriel8bd61f82015-01-06 23:02:54 +0100995 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143),
996 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241),
997 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329),
998 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330),
999 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334),
1000 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340),
1001 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341),
1002 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362),
1003 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339),
1004 BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
Hante Meuleman5779ae62014-07-12 08:49:34 +02001005 { /* end: all zeroes */ }
Arend van Spriele49b06b2013-12-12 11:58:51 +01001006};
1007MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
1008
1009static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
1010
1011
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001012static int brcmf_ops_sdio_probe(struct sdio_func *func,
1013 const struct sdio_device_id *id)
1014{
1015 int err;
1016 struct brcmf_sdio_dev *sdiodev;
1017 struct brcmf_bus *bus_if;
1018
1019 brcmf_dbg(SDIO, "Enter\n");
1020 brcmf_dbg(SDIO, "Class=%x\n", func->class);
1021 brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
1022 brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
1023 brcmf_dbg(SDIO, "Function#: %d\n", func->num);
1024
1025 /* Consume func num 1 but dont do anything with it. */
1026 if (func->num == 1)
1027 return 0;
1028
1029 /* Ignore anything but func 2 */
1030 if (func->num != 2)
1031 return -ENODEV;
1032
1033 bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
1034 if (!bus_if)
1035 return -ENOMEM;
1036 sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
1037 if (!sdiodev) {
1038 kfree(bus_if);
1039 return -ENOMEM;
1040 }
1041
Arend van Spriel36c4e7e2013-12-12 11:59:06 +01001042 /* store refs to functions used. mmc_card does
1043 * not hold the F0 function pointer.
1044 */
1045 sdiodev->func[0] = kmemdup(func, sizeof(*func), GFP_KERNEL);
1046 sdiodev->func[0]->num = 0;
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001047 sdiodev->func[1] = func->card->sdio_func[0];
1048 sdiodev->func[2] = func;
1049
1050 sdiodev->bus_if = bus_if;
1051 bus_if->bus_priv.sdio = sdiodev;
Hante Meuleman943258b2013-12-12 11:59:02 +01001052 bus_if->proto_type = BRCMF_PROTO_BCDC;
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001053 dev_set_drvdata(&func->dev, bus_if);
1054 dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
1055 sdiodev->dev = &sdiodev->func[1]->dev;
1056 sdiodev->pdata = brcmfmac_sdio_pdata;
1057
Chen-Yu Tsai61f663d2014-06-29 16:16:59 +02001058 if (!sdiodev->pdata)
1059 brcmf_of_probe(sdiodev);
1060
Hante Meuleman330b4e42014-10-28 14:56:05 +01001061#ifdef CONFIG_PM_SLEEP
1062 /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
1063 * is true or when platform data OOB irq is true).
1064 */
1065 if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
1066 ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
Mika Westerberg89758422014-12-23 16:48:32 +02001067 (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)))
Hante Meuleman330b4e42014-10-28 14:56:05 +01001068 bus_if->wowl_supported = true;
1069#endif
1070
Arend van Spriela1ce7a02015-02-06 18:36:42 +01001071 brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
Arend van Spriel8982cd42015-01-25 20:31:34 +01001072 sdiodev->sleeping = false;
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001073 atomic_set(&sdiodev->suspend, false);
Arend van Spriel8982cd42015-01-25 20:31:34 +01001074 init_waitqueue_head(&sdiodev->idle_wait);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001075
Arend van Spriela39be272013-12-12 11:58:58 +01001076 brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
1077 err = brcmf_sdiod_probe(sdiodev);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001078 if (err) {
1079 brcmf_err("F2 error, probe failed %d...\n", err);
1080 goto fail;
1081 }
1082
1083 brcmf_dbg(SDIO, "F2 init completed...\n");
1084 return 0;
1085
1086fail:
1087 dev_set_drvdata(&func->dev, NULL);
1088 dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
Arend van Spriel36c4e7e2013-12-12 11:59:06 +01001089 kfree(sdiodev->func[0]);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001090 kfree(sdiodev);
1091 kfree(bus_if);
1092 return err;
1093}
1094
1095static void brcmf_ops_sdio_remove(struct sdio_func *func)
1096{
1097 struct brcmf_bus *bus_if;
1098 struct brcmf_sdio_dev *sdiodev;
1099
1100 brcmf_dbg(SDIO, "Enter\n");
1101 brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
1102 brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
1103 brcmf_dbg(SDIO, "Function: %d\n", func->num);
1104
1105 if (func->num != 1 && func->num != 2)
1106 return;
1107
1108 bus_if = dev_get_drvdata(&func->dev);
1109 if (bus_if) {
1110 sdiodev = bus_if->bus_priv.sdio;
Arend van Spriela39be272013-12-12 11:58:58 +01001111 brcmf_sdiod_remove(sdiodev);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001112
1113 dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
1114 dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
1115
1116 kfree(bus_if);
Arend van Spriel36c4e7e2013-12-12 11:59:06 +01001117 kfree(sdiodev->func[0]);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001118 kfree(sdiodev);
1119 }
1120
1121 brcmf_dbg(SDIO, "Exit\n");
1122}
1123
Hante Meuleman330b4e42014-10-28 14:56:05 +01001124void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
1125{
1126 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1127 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
1128
1129 brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
1130 sdiodev->wowl_enabled = enabled;
1131}
1132
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001133#ifdef CONFIG_PM_SLEEP
Arend van Spriela39be272013-12-12 11:58:58 +01001134static int brcmf_ops_sdio_suspend(struct device *dev)
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001135{
Arend van Spriel8982cd42015-01-25 20:31:34 +01001136 struct brcmf_bus *bus_if;
1137 struct brcmf_sdio_dev *sdiodev;
Hante Meuleman330b4e42014-10-28 14:56:05 +01001138 mmc_pm_flag_t sdio_flags;
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001139
Arend van Spriel3e3831c2014-02-25 20:30:38 +01001140 brcmf_dbg(SDIO, "Enter\n");
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001141
Arend van Spriel8982cd42015-01-25 20:31:34 +01001142 bus_if = dev_get_drvdata(dev);
1143 sdiodev = bus_if->bus_priv.sdio;
1144
1145 /* wait for watchdog to go idle */
1146 if (wait_event_timeout(sdiodev->idle_wait, sdiodev->sleeping,
1147 msecs_to_jiffies(3 * BRCMF_WD_POLL_MS)) == 0) {
1148 brcmf_err("bus still active\n");
1149 return -EBUSY;
1150 }
1151 /* disable watchdog */
1152 brcmf_sdio_wd_timer(sdiodev->bus, 0);
Arend van Spriel3e3831c2014-02-25 20:30:38 +01001153 atomic_set(&sdiodev->suspend, true);
1154
Hante Meuleman330b4e42014-10-28 14:56:05 +01001155 if (sdiodev->wowl_enabled) {
1156 sdio_flags = MMC_PM_KEEP_POWER;
1157 if (sdiodev->pdata->oob_irq_supported)
1158 enable_irq_wake(sdiodev->pdata->oob_irq_nr);
1159 else
1160 sdio_flags = MMC_PM_WAKE_SDIO_IRQ;
1161 if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
1162 brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001163 }
Hante Meuleman330b4e42014-10-28 14:56:05 +01001164 return 0;
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001165}
1166
Arend van Spriela39be272013-12-12 11:58:58 +01001167static int brcmf_ops_sdio_resume(struct device *dev)
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001168{
1169 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1170 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
1171
Arend van Spriel3e3831c2014-02-25 20:30:38 +01001172 brcmf_dbg(SDIO, "Enter\n");
Mika Westerberg89758422014-12-23 16:48:32 +02001173 if (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)
Hante Meuleman330b4e42014-10-28 14:56:05 +01001174 disable_irq_wake(sdiodev->pdata->oob_irq_nr);
Arend van Spriel82d7f3c2013-12-12 11:59:04 +01001175 brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001176 atomic_set(&sdiodev->suspend, false);
1177 return 0;
1178}
1179
1180static const struct dev_pm_ops brcmf_sdio_pm_ops = {
Arend van Spriela39be272013-12-12 11:58:58 +01001181 .suspend = brcmf_ops_sdio_suspend,
1182 .resume = brcmf_ops_sdio_resume,
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001183};
1184#endif /* CONFIG_PM_SLEEP */
1185
1186static struct sdio_driver brcmf_sdmmc_driver = {
1187 .probe = brcmf_ops_sdio_probe,
1188 .remove = brcmf_ops_sdio_remove,
1189 .name = BRCMFMAC_SDIO_PDATA_NAME,
1190 .id_table = brcmf_sdmmc_ids,
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001191 .drv = {
Franky Lin0b0acd82014-01-29 15:32:12 +01001192 .owner = THIS_MODULE,
1193#ifdef CONFIG_PM_SLEEP
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001194 .pm = &brcmf_sdio_pm_ops,
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001195#endif /* CONFIG_PM_SLEEP */
Franky Lin0b0acd82014-01-29 15:32:12 +01001196 },
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001197};
1198
Jean Delvarec2d23c72014-03-13 23:21:08 +01001199static int __init brcmf_sdio_pd_probe(struct platform_device *pdev)
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001200{
1201 brcmf_dbg(SDIO, "Enter\n");
1202
1203 brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
1204
1205 if (brcmfmac_sdio_pdata->power_on)
1206 brcmfmac_sdio_pdata->power_on();
1207
1208 return 0;
1209}
1210
1211static int brcmf_sdio_pd_remove(struct platform_device *pdev)
1212{
1213 brcmf_dbg(SDIO, "Enter\n");
1214
1215 if (brcmfmac_sdio_pdata->power_off)
1216 brcmfmac_sdio_pdata->power_off();
1217
1218 sdio_unregister_driver(&brcmf_sdmmc_driver);
1219
1220 return 0;
1221}
1222
1223static struct platform_driver brcmf_sdio_pd = {
1224 .remove = brcmf_sdio_pd_remove,
1225 .driver = {
1226 .name = BRCMFMAC_SDIO_PDATA_NAME,
Arend van Spriele2dc9ee2013-12-12 11:58:50 +01001227 }
1228};
1229
1230void brcmf_sdio_register(void)
1231{
1232 int ret;
1233
1234 ret = sdio_register_driver(&brcmf_sdmmc_driver);
1235 if (ret)
1236 brcmf_err("sdio_register_driver failed: %d\n", ret);
1237}
1238
1239void brcmf_sdio_exit(void)
1240{
1241 brcmf_dbg(SDIO, "Enter\n");
1242
1243 if (brcmfmac_sdio_pdata)
1244 platform_driver_unregister(&brcmf_sdio_pd);
1245 else
1246 sdio_unregister_driver(&brcmf_sdmmc_driver);
1247}
1248
1249void __init brcmf_sdio_init(void)
1250{
1251 int ret;
1252
1253 brcmf_dbg(SDIO, "Enter\n");
1254
1255 ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
1256 if (ret == -ENODEV)
1257 brcmf_dbg(SDIO, "No platform data available.\n");
1258}