.. | .. |
---|
| 1 | +// SPDX-License-Identifier: ISC |
---|
1 | 2 | /* |
---|
2 | 3 | * 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 | 4 | */ |
---|
16 | 5 | /* ****************** SDIO CARD Interface Functions **************************/ |
---|
17 | 6 | |
---|
.. | .. |
---|
54 | 43 | |
---|
55 | 44 | #define SDIO_FUNC1_BLOCKSIZE 64 |
---|
56 | 45 | #define SDIO_FUNC2_BLOCKSIZE 512 |
---|
| 46 | +#define SDIO_4373_FUNC2_BLOCKSIZE 256 |
---|
| 47 | +#define SDIO_435X_FUNC2_BLOCKSIZE 256 |
---|
| 48 | +#define SDIO_4329_FUNC2_BLOCKSIZE 128 |
---|
57 | 49 | /* Maximum milliseconds to wait for F2 to come up */ |
---|
58 | 50 | #define SDIO_WAIT_F2RDY 3000 |
---|
59 | 51 | |
---|
.. | .. |
---|
82 | 74 | sdiodev->irq_en = false; |
---|
83 | 75 | } |
---|
84 | 76 | |
---|
85 | | - brcmf_sdio_isr(sdiodev->bus); |
---|
| 77 | + brcmf_sdio_isr(sdiodev->bus, true); |
---|
86 | 78 | |
---|
87 | 79 | return IRQ_HANDLED; |
---|
88 | 80 | } |
---|
.. | .. |
---|
94 | 86 | |
---|
95 | 87 | brcmf_dbg(INTR, "IB intr triggered\n"); |
---|
96 | 88 | |
---|
97 | | - brcmf_sdio_isr(sdiodev->bus); |
---|
| 89 | + brcmf_sdio_isr(sdiodev->bus, false); |
---|
98 | 90 | } |
---|
99 | 91 | |
---|
100 | 92 | /* dummy handler for SDIO function 2 interrupt */ |
---|
.. | .. |
---|
130 | 122 | brcmf_err("enable_irq_wake failed %d\n", ret); |
---|
131 | 123 | return ret; |
---|
132 | 124 | } |
---|
133 | | - sdiodev->irq_wake = true; |
---|
| 125 | + disable_irq_wake(pdata->oob_irq_nr); |
---|
134 | 126 | |
---|
135 | 127 | sdio_claim_host(sdiodev->func1); |
---|
136 | 128 | |
---|
.. | .. |
---|
189 | 181 | sdio_release_host(sdiodev->func1); |
---|
190 | 182 | |
---|
191 | 183 | sdiodev->oob_irq_requested = false; |
---|
192 | | - if (sdiodev->irq_wake) { |
---|
193 | | - disable_irq_wake(pdata->oob_irq_nr); |
---|
194 | | - sdiodev->irq_wake = false; |
---|
195 | | - } |
---|
196 | 184 | free_irq(pdata->oob_irq_nr, &sdiodev->func1->dev); |
---|
197 | 185 | sdiodev->irq_en = false; |
---|
198 | 186 | sdiodev->oob_irq_requested = false; |
---|
.. | .. |
---|
315 | 303 | /* bail out as things are really fishy here */ |
---|
316 | 304 | WARN(1, "invalid sdio function number: %d\n", func->num); |
---|
317 | 305 | err = -ENOMEDIUM; |
---|
318 | | - }; |
---|
| 306 | + } |
---|
319 | 307 | |
---|
320 | 308 | if (err == -ENOMEDIUM) |
---|
321 | 309 | brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM); |
---|
.. | .. |
---|
342 | 330 | return err; |
---|
343 | 331 | } |
---|
344 | 332 | |
---|
| 333 | +static int mmc_submit_one(struct mmc_data *md, struct mmc_request *mr, |
---|
| 334 | + struct mmc_command *mc, int sg_cnt, int req_sz, |
---|
| 335 | + int func_blk_sz, u32 *addr, |
---|
| 336 | + struct brcmf_sdio_dev *sdiodev, |
---|
| 337 | + struct sdio_func *func, int write) |
---|
| 338 | +{ |
---|
| 339 | + int ret; |
---|
| 340 | + |
---|
| 341 | + md->sg_len = sg_cnt; |
---|
| 342 | + md->blocks = req_sz / func_blk_sz; |
---|
| 343 | + mc->arg |= (*addr & 0x1FFFF) << 9; /* address */ |
---|
| 344 | + mc->arg |= md->blocks & 0x1FF; /* block count */ |
---|
| 345 | + /* incrementing addr for function 1 */ |
---|
| 346 | + if (func->num == 1) |
---|
| 347 | + *addr += req_sz; |
---|
| 348 | + |
---|
| 349 | + mmc_set_data_timeout(md, func->card); |
---|
| 350 | + mmc_wait_for_req(func->card->host, mr); |
---|
| 351 | + |
---|
| 352 | + ret = mc->error ? mc->error : md->error; |
---|
| 353 | + if (ret == -ENOMEDIUM) { |
---|
| 354 | + brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM); |
---|
| 355 | + } else if (ret != 0) { |
---|
| 356 | + brcmf_err("CMD53 sg block %s failed %d\n", |
---|
| 357 | + write ? "write" : "read", ret); |
---|
| 358 | + ret = -EIO; |
---|
| 359 | + } |
---|
| 360 | + |
---|
| 361 | + return ret; |
---|
| 362 | +} |
---|
| 363 | + |
---|
345 | 364 | /** |
---|
346 | 365 | * brcmf_sdiod_sglist_rw - SDIO interface function for block data access |
---|
347 | 366 | * @sdiodev: brcmfmac sdio device |
---|
.. | .. |
---|
360 | 379 | struct sk_buff_head *pktlist) |
---|
361 | 380 | { |
---|
362 | 381 | unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset; |
---|
363 | | - unsigned int max_req_sz, orig_offset, dst_offset; |
---|
364 | | - unsigned short max_seg_cnt, seg_sz; |
---|
| 382 | + unsigned int max_req_sz, src_offset, dst_offset; |
---|
365 | 383 | unsigned char *pkt_data, *orig_data, *dst_data; |
---|
366 | | - struct sk_buff *pkt_next = NULL, *local_pkt_next; |
---|
367 | 384 | struct sk_buff_head local_list, *target_list; |
---|
| 385 | + struct sk_buff *pkt_next = NULL, *src; |
---|
| 386 | + unsigned short max_seg_cnt; |
---|
368 | 387 | struct mmc_request mmc_req; |
---|
369 | 388 | struct mmc_command mmc_cmd; |
---|
370 | 389 | struct mmc_data mmc_dat; |
---|
.. | .. |
---|
404 | 423 | max_req_sz = sdiodev->max_request_size; |
---|
405 | 424 | max_seg_cnt = min_t(unsigned short, sdiodev->max_segment_count, |
---|
406 | 425 | target_list->qlen); |
---|
407 | | - seg_sz = target_list->qlen; |
---|
408 | | - pkt_offset = 0; |
---|
409 | | - pkt_next = target_list->next; |
---|
410 | 426 | |
---|
411 | 427 | memset(&mmc_req, 0, sizeof(struct mmc_request)); |
---|
412 | 428 | memset(&mmc_cmd, 0, sizeof(struct mmc_command)); |
---|
.. | .. |
---|
425 | 441 | mmc_req.cmd = &mmc_cmd; |
---|
426 | 442 | mmc_req.data = &mmc_dat; |
---|
427 | 443 | |
---|
428 | | - while (seg_sz) { |
---|
429 | | - req_sz = 0; |
---|
430 | | - sg_cnt = 0; |
---|
431 | | - sgl = sdiodev->sgtable.sgl; |
---|
432 | | - /* prep sg table */ |
---|
433 | | - while (pkt_next != (struct sk_buff *)target_list) { |
---|
| 444 | + req_sz = 0; |
---|
| 445 | + sg_cnt = 0; |
---|
| 446 | + sgl = sdiodev->sgtable.sgl; |
---|
| 447 | + skb_queue_walk(target_list, pkt_next) { |
---|
| 448 | + pkt_offset = 0; |
---|
| 449 | + while (pkt_offset < pkt_next->len) { |
---|
434 | 450 | pkt_data = pkt_next->data + pkt_offset; |
---|
435 | 451 | sg_data_sz = pkt_next->len - pkt_offset; |
---|
436 | 452 | if (sg_data_sz > sdiodev->max_segment_size) |
---|
.. | .. |
---|
439 | 455 | sg_data_sz = max_req_sz - req_sz; |
---|
440 | 456 | |
---|
441 | 457 | sg_set_buf(sgl, pkt_data, sg_data_sz); |
---|
442 | | - |
---|
443 | 458 | sg_cnt++; |
---|
| 459 | + |
---|
444 | 460 | sgl = sg_next(sgl); |
---|
445 | 461 | req_sz += sg_data_sz; |
---|
446 | 462 | pkt_offset += sg_data_sz; |
---|
447 | | - if (pkt_offset == pkt_next->len) { |
---|
448 | | - pkt_offset = 0; |
---|
449 | | - pkt_next = pkt_next->next; |
---|
| 463 | + if (req_sz >= max_req_sz || sg_cnt >= max_seg_cnt) { |
---|
| 464 | + ret = mmc_submit_one(&mmc_dat, &mmc_req, &mmc_cmd, |
---|
| 465 | + sg_cnt, req_sz, func_blk_sz, |
---|
| 466 | + &addr, sdiodev, func, write); |
---|
| 467 | + if (ret) |
---|
| 468 | + goto exit_queue_walk; |
---|
| 469 | + req_sz = 0; |
---|
| 470 | + sg_cnt = 0; |
---|
| 471 | + sgl = sdiodev->sgtable.sgl; |
---|
450 | 472 | } |
---|
451 | | - |
---|
452 | | - if (req_sz >= max_req_sz || sg_cnt >= max_seg_cnt) |
---|
453 | | - break; |
---|
454 | | - } |
---|
455 | | - seg_sz -= sg_cnt; |
---|
456 | | - |
---|
457 | | - if (req_sz % func_blk_sz != 0) { |
---|
458 | | - brcmf_err("sg request length %u is not %u aligned\n", |
---|
459 | | - req_sz, func_blk_sz); |
---|
460 | | - ret = -ENOTBLK; |
---|
461 | | - goto exit; |
---|
462 | | - } |
---|
463 | | - |
---|
464 | | - mmc_dat.sg_len = sg_cnt; |
---|
465 | | - mmc_dat.blocks = req_sz / func_blk_sz; |
---|
466 | | - mmc_cmd.arg |= (addr & 0x1FFFF) << 9; /* address */ |
---|
467 | | - mmc_cmd.arg |= mmc_dat.blocks & 0x1FF; /* block count */ |
---|
468 | | - /* incrementing addr for function 1 */ |
---|
469 | | - if (func->num == 1) |
---|
470 | | - addr += req_sz; |
---|
471 | | - |
---|
472 | | - mmc_set_data_timeout(&mmc_dat, func->card); |
---|
473 | | - mmc_wait_for_req(func->card->host, &mmc_req); |
---|
474 | | - |
---|
475 | | - ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error; |
---|
476 | | - if (ret == -ENOMEDIUM) { |
---|
477 | | - brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM); |
---|
478 | | - break; |
---|
479 | | - } else if (ret != 0) { |
---|
480 | | - brcmf_err("CMD53 sg block %s failed %d\n", |
---|
481 | | - write ? "write" : "read", ret); |
---|
482 | | - ret = -EIO; |
---|
483 | | - break; |
---|
484 | 473 | } |
---|
485 | 474 | } |
---|
486 | | - |
---|
| 475 | + if (sg_cnt) |
---|
| 476 | + ret = mmc_submit_one(&mmc_dat, &mmc_req, &mmc_cmd, |
---|
| 477 | + sg_cnt, req_sz, func_blk_sz, |
---|
| 478 | + &addr, sdiodev, func, write); |
---|
| 479 | +exit_queue_walk: |
---|
487 | 480 | if (!write && sdiodev->settings->bus.sdio.broken_sg_support) { |
---|
488 | | - local_pkt_next = local_list.next; |
---|
489 | | - orig_offset = 0; |
---|
| 481 | + src = __skb_peek(&local_list); |
---|
| 482 | + src_offset = 0; |
---|
490 | 483 | skb_queue_walk(pktlist, pkt_next) { |
---|
491 | 484 | dst_offset = 0; |
---|
492 | | - do { |
---|
493 | | - req_sz = local_pkt_next->len - orig_offset; |
---|
494 | | - req_sz = min_t(uint, pkt_next->len - dst_offset, |
---|
495 | | - req_sz); |
---|
496 | | - orig_data = local_pkt_next->data + orig_offset; |
---|
| 485 | + |
---|
| 486 | + /* This is safe because we must have enough SKB data |
---|
| 487 | + * in the local list to cover everything in pktlist. |
---|
| 488 | + */ |
---|
| 489 | + while (1) { |
---|
| 490 | + req_sz = pkt_next->len - dst_offset; |
---|
| 491 | + if (req_sz > src->len - src_offset) |
---|
| 492 | + req_sz = src->len - src_offset; |
---|
| 493 | + |
---|
| 494 | + orig_data = src->data + src_offset; |
---|
497 | 495 | dst_data = pkt_next->data + dst_offset; |
---|
498 | 496 | memcpy(dst_data, orig_data, req_sz); |
---|
499 | | - orig_offset += req_sz; |
---|
500 | | - dst_offset += req_sz; |
---|
501 | | - if (orig_offset == local_pkt_next->len) { |
---|
502 | | - orig_offset = 0; |
---|
503 | | - local_pkt_next = local_pkt_next->next; |
---|
| 497 | + |
---|
| 498 | + src_offset += req_sz; |
---|
| 499 | + if (src_offset == src->len) { |
---|
| 500 | + src_offset = 0; |
---|
| 501 | + src = skb_peek_next(src, &local_list); |
---|
504 | 502 | } |
---|
| 503 | + dst_offset += req_sz; |
---|
505 | 504 | if (dst_offset == pkt_next->len) |
---|
506 | 505 | break; |
---|
507 | | - } while (!skb_queue_empty(&local_list)); |
---|
| 506 | + } |
---|
508 | 507 | } |
---|
509 | 508 | } |
---|
510 | 509 | |
---|
.. | .. |
---|
576 | 575 | |
---|
577 | 576 | if (pktq->qlen == 1) |
---|
578 | 577 | err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr, |
---|
579 | | - pktq->next); |
---|
| 578 | + __skb_peek(pktq)); |
---|
580 | 579 | else if (!sdiodev->sg_support) { |
---|
581 | 580 | glom_skb = brcmu_pkt_buf_get_skb(totlen); |
---|
582 | 581 | if (!glom_skb) |
---|
.. | .. |
---|
865 | 864 | } |
---|
866 | 865 | #endif /* CONFIG_PM_SLEEP */ |
---|
867 | 866 | |
---|
868 | | -static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) |
---|
| 867 | +int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) |
---|
869 | 868 | { |
---|
870 | 869 | sdiodev->state = BRCMF_SDIOD_DOWN; |
---|
871 | 870 | if (sdiodev->bus) { |
---|
.. | .. |
---|
900 | 899 | host->caps |= MMC_CAP_NONREMOVABLE; |
---|
901 | 900 | } |
---|
902 | 901 | |
---|
903 | | -static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) |
---|
| 902 | +int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) |
---|
904 | 903 | { |
---|
905 | 904 | int ret = 0; |
---|
| 905 | + unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE; |
---|
906 | 906 | |
---|
907 | 907 | sdio_claim_host(sdiodev->func1); |
---|
908 | 908 | |
---|
.. | .. |
---|
912 | 912 | sdio_release_host(sdiodev->func1); |
---|
913 | 913 | goto out; |
---|
914 | 914 | } |
---|
915 | | - ret = sdio_set_block_size(sdiodev->func2, SDIO_FUNC2_BLOCKSIZE); |
---|
| 915 | + switch (sdiodev->func2->device) { |
---|
| 916 | + case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373: |
---|
| 917 | + f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE; |
---|
| 918 | + break; |
---|
| 919 | + case SDIO_DEVICE_ID_BROADCOM_4359: |
---|
| 920 | + case SDIO_DEVICE_ID_BROADCOM_4354: |
---|
| 921 | + case SDIO_DEVICE_ID_BROADCOM_4356: |
---|
| 922 | + f2_blksz = SDIO_435X_FUNC2_BLOCKSIZE; |
---|
| 923 | + break; |
---|
| 924 | + case SDIO_DEVICE_ID_BROADCOM_4329: |
---|
| 925 | + f2_blksz = SDIO_4329_FUNC2_BLOCKSIZE; |
---|
| 926 | + break; |
---|
| 927 | + default: |
---|
| 928 | + break; |
---|
| 929 | + } |
---|
| 930 | + |
---|
| 931 | + ret = sdio_set_block_size(sdiodev->func2, f2_blksz); |
---|
916 | 932 | if (ret) { |
---|
917 | 933 | brcmf_err("Failed to set F2 blocksize\n"); |
---|
918 | 934 | sdio_release_host(sdiodev->func1); |
---|
919 | 935 | goto out; |
---|
| 936 | + } else { |
---|
| 937 | + brcmf_dbg(SDIO, "set F2 blocksize to %d\n", f2_blksz); |
---|
920 | 938 | } |
---|
921 | 939 | |
---|
922 | 940 | /* increase F2 timeout */ |
---|
.. | .. |
---|
961 | 979 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340), |
---|
962 | 980 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), |
---|
963 | 981 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), |
---|
964 | | - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364), |
---|
| 982 | + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364), |
---|
965 | 983 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), |
---|
966 | 984 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339), |
---|
967 | 985 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430), |
---|
.. | .. |
---|
969 | 987 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455), |
---|
970 | 988 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), |
---|
971 | 989 | BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356), |
---|
972 | | - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373), |
---|
| 990 | + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359), |
---|
| 991 | + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373), |
---|
| 992 | + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012), |
---|
| 993 | + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359), |
---|
973 | 994 | { /* end: all zeroes */ } |
---|
974 | 995 | }; |
---|
975 | 996 | MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); |
---|
.. | .. |
---|
1107 | 1128 | struct sdio_func *func; |
---|
1108 | 1129 | struct brcmf_bus *bus_if; |
---|
1109 | 1130 | struct brcmf_sdio_dev *sdiodev; |
---|
1110 | | - mmc_pm_flag_t sdio_flags; |
---|
| 1131 | + mmc_pm_flag_t pm_caps, sdio_flags; |
---|
| 1132 | + int ret = 0; |
---|
1111 | 1133 | |
---|
1112 | 1134 | func = container_of(dev, struct sdio_func, dev); |
---|
1113 | 1135 | brcmf_dbg(SDIO, "Enter: F%d\n", func->num); |
---|
.. | .. |
---|
1118 | 1140 | bus_if = dev_get_drvdata(dev); |
---|
1119 | 1141 | sdiodev = bus_if->bus_priv.sdio; |
---|
1120 | 1142 | |
---|
1121 | | - brcmf_sdiod_freezer_on(sdiodev); |
---|
1122 | | - brcmf_sdio_wd_timer(sdiodev->bus, 0); |
---|
| 1143 | + pm_caps = sdio_get_host_pm_caps(func); |
---|
1123 | 1144 | |
---|
1124 | | - sdio_flags = MMC_PM_KEEP_POWER; |
---|
1125 | | - if (sdiodev->wowl_enabled) { |
---|
1126 | | - if (sdiodev->settings->bus.sdio.oob_irq_supported) |
---|
1127 | | - enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); |
---|
1128 | | - else |
---|
1129 | | - sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; |
---|
| 1145 | + if (pm_caps & MMC_PM_KEEP_POWER) { |
---|
| 1146 | + /* preserve card power during suspend */ |
---|
| 1147 | + brcmf_sdiod_freezer_on(sdiodev); |
---|
| 1148 | + brcmf_sdio_wd_timer(sdiodev->bus, 0); |
---|
| 1149 | + |
---|
| 1150 | + sdio_flags = MMC_PM_KEEP_POWER; |
---|
| 1151 | + if (sdiodev->wowl_enabled) { |
---|
| 1152 | + if (sdiodev->settings->bus.sdio.oob_irq_supported) |
---|
| 1153 | + enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); |
---|
| 1154 | + else |
---|
| 1155 | + sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; |
---|
| 1156 | + } |
---|
| 1157 | + |
---|
| 1158 | + if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) |
---|
| 1159 | + brcmf_err("Failed to set pm_flags %x\n", sdio_flags); |
---|
| 1160 | + |
---|
| 1161 | + } else { |
---|
| 1162 | + /* power will be cut so remove device, probe again in resume */ |
---|
| 1163 | + brcmf_sdiod_intr_unregister(sdiodev); |
---|
| 1164 | + ret = brcmf_sdiod_remove(sdiodev); |
---|
| 1165 | + if (ret) |
---|
| 1166 | + brcmf_err("Failed to remove device on suspend\n"); |
---|
1130 | 1167 | } |
---|
1131 | | - if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) |
---|
1132 | | - brcmf_err("Failed to set pm_flags %x\n", sdio_flags); |
---|
1133 | | - return 0; |
---|
| 1168 | + |
---|
| 1169 | + return ret; |
---|
1134 | 1170 | } |
---|
1135 | 1171 | |
---|
1136 | 1172 | static int brcmf_ops_sdio_resume(struct device *dev) |
---|
.. | .. |
---|
1138 | 1174 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
---|
1139 | 1175 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
---|
1140 | 1176 | struct sdio_func *func = container_of(dev, struct sdio_func, dev); |
---|
| 1177 | + mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(func); |
---|
| 1178 | + int ret = 0; |
---|
1141 | 1179 | |
---|
1142 | 1180 | brcmf_dbg(SDIO, "Enter: F%d\n", func->num); |
---|
1143 | 1181 | if (func->num != 2) |
---|
1144 | 1182 | return 0; |
---|
1145 | 1183 | |
---|
1146 | | - brcmf_sdiod_freezer_off(sdiodev); |
---|
1147 | | - return 0; |
---|
| 1184 | + if (!(pm_caps & MMC_PM_KEEP_POWER)) { |
---|
| 1185 | + /* bus was powered off and device removed, probe again */ |
---|
| 1186 | + ret = brcmf_sdiod_probe(sdiodev); |
---|
| 1187 | + if (ret) |
---|
| 1188 | + brcmf_err("Failed to probe device on resume\n"); |
---|
| 1189 | + } else { |
---|
| 1190 | + if (sdiodev->wowl_enabled && |
---|
| 1191 | + sdiodev->settings->bus.sdio.oob_irq_supported) |
---|
| 1192 | + disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); |
---|
| 1193 | + |
---|
| 1194 | + brcmf_sdiod_freezer_off(sdiodev); |
---|
| 1195 | + } |
---|
| 1196 | + |
---|
| 1197 | + return ret; |
---|
1148 | 1198 | } |
---|
1149 | 1199 | |
---|
1150 | 1200 | static const struct dev_pm_ops brcmf_sdio_pm_ops = { |
---|
.. | .. |
---|
1167 | 1217 | }, |
---|
1168 | 1218 | }; |
---|
1169 | 1219 | |
---|
1170 | | -void brcmf_sdio_register(void) |
---|
| 1220 | +int brcmf_sdio_register(void) |
---|
1171 | 1221 | { |
---|
1172 | | - int ret; |
---|
1173 | | - |
---|
1174 | | - ret = sdio_register_driver(&brcmf_sdmmc_driver); |
---|
1175 | | - if (ret) |
---|
1176 | | - brcmf_err("sdio_register_driver failed: %d\n", ret); |
---|
| 1222 | + return sdio_register_driver(&brcmf_sdmmc_driver); |
---|
1177 | 1223 | } |
---|
1178 | 1224 | |
---|
1179 | 1225 | void brcmf_sdio_exit(void) |
---|