bcmsdh.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /*
  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. #include <linux/types.h>
  18. #include <linux/netdevice.h>
  19. #include <linux/export.h>
  20. #include <linux/pci.h>
  21. #include <linux/pci_ids.h>
  22. #include <linux/sched.h>
  23. #include <linux/completion.h>
  24. #include <linux/mmc/sdio.h>
  25. #include <linux/mmc/sdio_func.h>
  26. #include <linux/mmc/card.h>
  27. #include <linux/platform_data/brcmfmac-sdio.h>
  28. #include <defs.h>
  29. #include <brcm_hw_ids.h>
  30. #include <brcmu_utils.h>
  31. #include <brcmu_wifi.h>
  32. #include <soc.h>
  33. #include "dhd_bus.h"
  34. #include "dhd_dbg.h"
  35. #include "sdio_host.h"
  36. #define SDIOH_API_ACCESS_RETRY_LIMIT 2
  37. static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)
  38. {
  39. struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
  40. struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
  41. brcmf_dbg(INTR, "OOB intr triggered\n");
  42. /* out-of-band interrupt is level-triggered which won't
  43. * be cleared until dpc
  44. */
  45. if (sdiodev->irq_en) {
  46. disable_irq_nosync(irq);
  47. sdiodev->irq_en = false;
  48. }
  49. brcmf_sdbrcm_isr(sdiodev->bus);
  50. return IRQ_HANDLED;
  51. }
  52. static void brcmf_sdio_ib_irqhandler(struct sdio_func *func)
  53. {
  54. struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
  55. struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
  56. brcmf_dbg(INTR, "IB intr triggered\n");
  57. brcmf_sdbrcm_isr(sdiodev->bus);
  58. }
  59. /* dummy handler for SDIO function 2 interrupt */
  60. static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
  61. {
  62. }
  63. int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
  64. {
  65. int ret = 0;
  66. u8 data;
  67. unsigned long flags;
  68. if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
  69. brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
  70. sdiodev->pdata->oob_irq_nr);
  71. ret = request_irq(sdiodev->pdata->oob_irq_nr,
  72. brcmf_sdio_oob_irqhandler,
  73. sdiodev->pdata->oob_irq_flags,
  74. "brcmf_oob_intr",
  75. &sdiodev->func[1]->dev);
  76. if (ret != 0) {
  77. brcmf_err("request_irq failed %d\n", ret);
  78. return ret;
  79. }
  80. sdiodev->oob_irq_requested = true;
  81. spin_lock_init(&sdiodev->irq_en_lock);
  82. spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
  83. sdiodev->irq_en = true;
  84. spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
  85. ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr);
  86. if (ret != 0) {
  87. brcmf_err("enable_irq_wake failed %d\n", ret);
  88. return ret;
  89. }
  90. sdiodev->irq_wake = true;
  91. sdio_claim_host(sdiodev->func[1]);
  92. /* must configure SDIO_CCCR_IENx to enable irq */
  93. data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
  94. data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
  95. brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
  96. /* redirect, configure and enable io for interrupt signal */
  97. data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
  98. if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
  99. data |= SDIO_SEPINT_ACT_HI;
  100. brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
  101. sdio_release_host(sdiodev->func[1]);
  102. } else {
  103. brcmf_dbg(SDIO, "Entering\n");
  104. sdio_claim_host(sdiodev->func[1]);
  105. sdio_claim_irq(sdiodev->func[1], brcmf_sdio_ib_irqhandler);
  106. sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
  107. sdio_release_host(sdiodev->func[1]);
  108. }
  109. return 0;
  110. }
  111. int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
  112. {
  113. brcmf_dbg(SDIO, "Entering\n");
  114. if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
  115. sdio_claim_host(sdiodev->func[1]);
  116. brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
  117. brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
  118. sdio_release_host(sdiodev->func[1]);
  119. if (sdiodev->oob_irq_requested) {
  120. sdiodev->oob_irq_requested = false;
  121. if (sdiodev->irq_wake) {
  122. disable_irq_wake(sdiodev->pdata->oob_irq_nr);
  123. sdiodev->irq_wake = false;
  124. }
  125. free_irq(sdiodev->pdata->oob_irq_nr,
  126. &sdiodev->func[1]->dev);
  127. sdiodev->irq_en = false;
  128. }
  129. } else {
  130. sdio_claim_host(sdiodev->func[1]);
  131. sdio_release_irq(sdiodev->func[2]);
  132. sdio_release_irq(sdiodev->func[1]);
  133. sdio_release_host(sdiodev->func[1]);
  134. }
  135. return 0;
  136. }
  137. int
  138. brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
  139. {
  140. int err = 0, i;
  141. u8 addr[3];
  142. s32 retry;
  143. addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
  144. addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
  145. addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
  146. for (i = 0; i < 3; i++) {
  147. retry = 0;
  148. do {
  149. if (retry)
  150. usleep_range(1000, 2000);
  151. err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
  152. SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
  153. &addr[i]);
  154. } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
  155. if (err) {
  156. brcmf_err("failed at addr:0x%0x\n",
  157. SBSDIO_FUNC1_SBADDRLOW + i);
  158. break;
  159. }
  160. }
  161. return err;
  162. }
  163. int
  164. brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
  165. void *data, bool write)
  166. {
  167. u8 func_num, reg_size;
  168. u32 bar;
  169. s32 retry = 0;
  170. int ret;
  171. /*
  172. * figure out how to read the register based on address range
  173. * 0x00 ~ 0x7FF: function 0 CCCR and FBR
  174. * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
  175. * The rest: function 1 silicon backplane core registers
  176. */
  177. if ((addr & ~REG_F0_REG_MASK) == 0) {
  178. func_num = SDIO_FUNC_0;
  179. reg_size = 1;
  180. } else if ((addr & ~REG_F1_MISC_MASK) == 0) {
  181. func_num = SDIO_FUNC_1;
  182. reg_size = 1;
  183. } else {
  184. func_num = SDIO_FUNC_1;
  185. reg_size = 4;
  186. /* Set the window for SB core register */
  187. bar = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
  188. if (bar != sdiodev->sbwad) {
  189. ret = brcmf_sdcard_set_sbaddr_window(sdiodev, bar);
  190. if (ret != 0) {
  191. memset(data, 0xFF, reg_size);
  192. return ret;
  193. }
  194. sdiodev->sbwad = bar;
  195. }
  196. addr &= SBSDIO_SB_OFT_ADDR_MASK;
  197. addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
  198. }
  199. do {
  200. if (!write)
  201. memset(data, 0, reg_size);
  202. if (retry) /* wait for 1 ms till bus get settled down */
  203. usleep_range(1000, 2000);
  204. if (reg_size == 1)
  205. ret = brcmf_sdioh_request_byte(sdiodev, write,
  206. func_num, addr, data);
  207. else
  208. ret = brcmf_sdioh_request_word(sdiodev, write,
  209. func_num, addr, data, 4);
  210. } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
  211. if (ret != 0)
  212. brcmf_err("failed with %d\n", ret);
  213. return ret;
  214. }
  215. u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
  216. {
  217. u8 data;
  218. int retval;
  219. brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
  220. retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
  221. brcmf_dbg(SDIO, "data:0x%02x\n", data);
  222. if (ret)
  223. *ret = retval;
  224. return data;
  225. }
  226. u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
  227. {
  228. u32 data;
  229. int retval;
  230. brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
  231. retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
  232. brcmf_dbg(SDIO, "data:0x%08x\n", data);
  233. if (ret)
  234. *ret = retval;
  235. return data;
  236. }
  237. void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
  238. u8 data, int *ret)
  239. {
  240. int retval;
  241. brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
  242. retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
  243. if (ret)
  244. *ret = retval;
  245. }
  246. void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
  247. u32 data, int *ret)
  248. {
  249. int retval;
  250. brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
  251. retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
  252. if (ret)
  253. *ret = retval;
  254. }
  255. static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
  256. uint flags, uint width, u32 *addr)
  257. {
  258. uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
  259. int err = 0;
  260. /* Async not implemented yet */
  261. if (flags & SDIO_REQ_ASYNC)
  262. return -ENOTSUPP;
  263. if (bar0 != sdiodev->sbwad) {
  264. err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
  265. if (err)
  266. return err;
  267. sdiodev->sbwad = bar0;
  268. }
  269. *addr &= SBSDIO_SB_OFT_ADDR_MASK;
  270. if (width == 4)
  271. *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
  272. return 0;
  273. }
  274. int
  275. brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
  276. uint flags, u8 *buf, uint nbytes)
  277. {
  278. struct sk_buff *mypkt;
  279. int err;
  280. mypkt = brcmu_pkt_buf_get_skb(nbytes);
  281. if (!mypkt) {
  282. brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
  283. nbytes);
  284. return -EIO;
  285. }
  286. err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
  287. if (!err)
  288. memcpy(buf, mypkt->data, nbytes);
  289. brcmu_pkt_buf_free_skb(mypkt);
  290. return err;
  291. }
  292. int
  293. brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
  294. uint flags, struct sk_buff *pkt)
  295. {
  296. uint incr_fix;
  297. uint width;
  298. int err = 0;
  299. brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
  300. fn, addr, pkt->len);
  301. width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
  302. err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
  303. if (err)
  304. goto done;
  305. incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
  306. err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
  307. fn, addr, pkt);
  308. done:
  309. return err;
  310. }
  311. int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
  312. uint flags, struct sk_buff_head *pktq)
  313. {
  314. uint incr_fix;
  315. uint width;
  316. int err = 0;
  317. brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
  318. fn, addr, pktq->qlen);
  319. width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
  320. err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
  321. if (err)
  322. goto done;
  323. incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
  324. err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
  325. pktq);
  326. done:
  327. return err;
  328. }
  329. int
  330. brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
  331. uint flags, u8 *buf, uint nbytes)
  332. {
  333. struct sk_buff *mypkt;
  334. int err;
  335. mypkt = brcmu_pkt_buf_get_skb(nbytes);
  336. if (!mypkt) {
  337. brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
  338. nbytes);
  339. return -EIO;
  340. }
  341. memcpy(mypkt->data, buf, nbytes);
  342. err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);
  343. brcmu_pkt_buf_free_skb(mypkt);
  344. return err;
  345. }
  346. int
  347. brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
  348. uint flags, struct sk_buff *pkt)
  349. {
  350. uint incr_fix;
  351. uint width;
  352. uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
  353. int err = 0;
  354. brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
  355. fn, addr, pkt->len);
  356. /* Async not implemented yet */
  357. if (flags & SDIO_REQ_ASYNC)
  358. return -ENOTSUPP;
  359. if (bar0 != sdiodev->sbwad) {
  360. err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
  361. if (err)
  362. goto done;
  363. sdiodev->sbwad = bar0;
  364. }
  365. addr &= SBSDIO_SB_OFT_ADDR_MASK;
  366. incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
  367. width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
  368. if (width == 4)
  369. addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
  370. err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
  371. addr, pkt);
  372. done:
  373. return err;
  374. }
  375. int
  376. brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
  377. u8 *data, uint size)
  378. {
  379. int bcmerror = 0;
  380. struct sk_buff *pkt;
  381. u32 sdaddr;
  382. uint dsize;
  383. dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
  384. pkt = dev_alloc_skb(dsize);
  385. if (!pkt) {
  386. brcmf_err("dev_alloc_skb failed: len %d\n", dsize);
  387. return -EIO;
  388. }
  389. pkt->priority = 0;
  390. /* Determine initial transfer parameters */
  391. sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
  392. if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
  393. dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
  394. else
  395. dsize = size;
  396. sdio_claim_host(sdiodev->func[1]);
  397. /* Do the transfer(s) */
  398. while (size) {
  399. /* Set the backplane window to include the start address */
  400. bcmerror = brcmf_sdcard_set_sbaddr_window(sdiodev, address);
  401. if (bcmerror)
  402. break;
  403. brcmf_dbg(SDIO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
  404. write ? "write" : "read", dsize,
  405. sdaddr, address & SBSDIO_SBWINDOW_MASK);
  406. sdaddr &= SBSDIO_SB_OFT_ADDR_MASK;
  407. sdaddr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
  408. skb_put(pkt, dsize);
  409. if (write)
  410. memcpy(pkt->data, data, dsize);
  411. bcmerror = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC,
  412. write, SDIO_FUNC_1,
  413. sdaddr, pkt);
  414. if (bcmerror) {
  415. brcmf_err("membytes transfer failed\n");
  416. break;
  417. }
  418. if (!write)
  419. memcpy(data, pkt->data, dsize);
  420. skb_trim(pkt, dsize);
  421. /* Adjust for next transfer (if any) */
  422. size -= dsize;
  423. if (size) {
  424. data += dsize;
  425. address += dsize;
  426. sdaddr = 0;
  427. dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
  428. }
  429. }
  430. dev_kfree_skb(pkt);
  431. /* Return the window to backplane enumeration space for core access */
  432. if (brcmf_sdcard_set_sbaddr_window(sdiodev, sdiodev->sbwad))
  433. brcmf_err("FAILED to set window back to 0x%x\n",
  434. sdiodev->sbwad);
  435. sdio_release_host(sdiodev->func[1]);
  436. return bcmerror;
  437. }
  438. int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
  439. {
  440. char t_func = (char)fn;
  441. brcmf_dbg(SDIO, "Enter\n");
  442. /* issue abort cmd52 command through F0 */
  443. brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
  444. SDIO_CCCR_ABORT, &t_func);
  445. brcmf_dbg(SDIO, "Exit\n");
  446. return 0;
  447. }
  448. int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
  449. {
  450. u32 regs = 0;
  451. int ret = 0;
  452. ret = brcmf_sdioh_attach(sdiodev);
  453. if (ret)
  454. goto out;
  455. regs = SI_ENUM_BASE;
  456. /* try to attach to the target device */
  457. sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
  458. if (!sdiodev->bus) {
  459. brcmf_err("device attach failed\n");
  460. ret = -ENODEV;
  461. goto out;
  462. }
  463. out:
  464. if (ret)
  465. brcmf_sdio_remove(sdiodev);
  466. return ret;
  467. }
  468. EXPORT_SYMBOL(brcmf_sdio_probe);
  469. int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
  470. {
  471. sdiodev->bus_if->state = BRCMF_BUS_DOWN;
  472. if (sdiodev->bus) {
  473. brcmf_sdbrcm_disconnect(sdiodev->bus);
  474. sdiodev->bus = NULL;
  475. }
  476. brcmf_sdioh_detach(sdiodev);
  477. sdiodev->sbwad = 0;
  478. return 0;
  479. }
  480. EXPORT_SYMBOL(brcmf_sdio_remove);
  481. void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
  482. {
  483. if (enable)
  484. brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
  485. else
  486. brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
  487. }