| .. | .. |
|---|
| 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) |
|---|