diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/host/mmci.c | 148 | ||||
| -rw-r--r-- | drivers/mmc/host/mmci.h | 39 | ||||
| -rw-r--r-- | drivers/mmc/host/mxcmmc.c | 48 |
3 files changed, 122 insertions, 113 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2ed435bd4b6..840b301b567 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | #include <linux/amba/mmci.h> | 26 | #include <linux/amba/mmci.h> |
| 27 | #include <linux/regulator/consumer.h> | 27 | #include <linux/regulator/consumer.h> |
| 28 | 28 | ||
| 29 | #include <asm/cacheflush.h> | ||
| 30 | #include <asm/div64.h> | 29 | #include <asm/div64.h> |
| 31 | #include <asm/io.h> | 30 | #include <asm/io.h> |
| 32 | #include <asm/sizes.h> | 31 | #include <asm/sizes.h> |
| @@ -37,12 +36,39 @@ | |||
| 37 | 36 | ||
| 38 | static unsigned int fmax = 515633; | 37 | static unsigned int fmax = 515633; |
| 39 | 38 | ||
| 39 | /** | ||
| 40 | * struct variant_data - MMCI variant-specific quirks | ||
| 41 | * @clkreg: default value for MCICLOCK register | ||
| 42 | * @clkreg_enable: enable value for MMCICLOCK register | ||
| 43 | * @datalength_bits: number of bits in the MMCIDATALENGTH register | ||
| 44 | */ | ||
| 45 | struct variant_data { | ||
| 46 | unsigned int clkreg; | ||
| 47 | unsigned int clkreg_enable; | ||
| 48 | unsigned int datalength_bits; | ||
| 49 | }; | ||
| 50 | |||
| 51 | static struct variant_data variant_arm = { | ||
| 52 | .datalength_bits = 16, | ||
| 53 | }; | ||
| 54 | |||
| 55 | static struct variant_data variant_u300 = { | ||
| 56 | .clkreg_enable = 1 << 13, /* HWFCEN */ | ||
| 57 | .datalength_bits = 16, | ||
| 58 | }; | ||
| 59 | |||
| 60 | static struct variant_data variant_ux500 = { | ||
| 61 | .clkreg = MCI_CLK_ENABLE, | ||
| 62 | .clkreg_enable = 1 << 14, /* HWFCEN */ | ||
| 63 | .datalength_bits = 24, | ||
| 64 | }; | ||
| 40 | /* | 65 | /* |
| 41 | * This must be called with host->lock held | 66 | * This must be called with host->lock held |
| 42 | */ | 67 | */ |
| 43 | static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) | 68 | static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) |
| 44 | { | 69 | { |
| 45 | u32 clk = 0; | 70 | struct variant_data *variant = host->variant; |
| 71 | u32 clk = variant->clkreg; | ||
| 46 | 72 | ||
| 47 | if (desired) { | 73 | if (desired) { |
| 48 | if (desired >= host->mclk) { | 74 | if (desired >= host->mclk) { |
| @@ -54,8 +80,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) | |||
| 54 | clk = 255; | 80 | clk = 255; |
| 55 | host->cclk = host->mclk / (2 * (clk + 1)); | 81 | host->cclk = host->mclk / (2 * (clk + 1)); |
| 56 | } | 82 | } |
| 57 | if (host->hw_designer == AMBA_VENDOR_ST) | 83 | |
| 58 | clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */ | 84 | clk |= variant->clkreg_enable; |
| 59 | clk |= MCI_CLK_ENABLE; | 85 | clk |= MCI_CLK_ENABLE; |
| 60 | /* This hasn't proven to be worthwhile */ | 86 | /* This hasn't proven to be worthwhile */ |
| 61 | /* clk |= MCI_CLK_PWRSAVE; */ | 87 | /* clk |= MCI_CLK_PWRSAVE; */ |
| @@ -98,6 +124,18 @@ static void mmci_stop_data(struct mmci_host *host) | |||
| 98 | host->data = NULL; | 124 | host->data = NULL; |
| 99 | } | 125 | } |
| 100 | 126 | ||
| 127 | static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) | ||
| 128 | { | ||
| 129 | unsigned int flags = SG_MITER_ATOMIC; | ||
| 130 | |||
| 131 | if (data->flags & MMC_DATA_READ) | ||
| 132 | flags |= SG_MITER_TO_SG; | ||
| 133 | else | ||
| 134 | flags |= SG_MITER_FROM_SG; | ||
| 135 | |||
| 136 | sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); | ||
| 137 | } | ||
| 138 | |||
| 101 | static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) | 139 | static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) |
| 102 | { | 140 | { |
| 103 | unsigned int datactrl, timeout, irqmask; | 141 | unsigned int datactrl, timeout, irqmask; |
| @@ -109,7 +147,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) | |||
| 109 | data->blksz, data->blocks, data->flags); | 147 | data->blksz, data->blocks, data->flags); |
| 110 | 148 | ||
| 111 | host->data = data; | 149 | host->data = data; |
| 112 | host->size = data->blksz; | 150 | host->size = data->blksz * data->blocks; |
| 113 | host->data_xfered = 0; | 151 | host->data_xfered = 0; |
| 114 | 152 | ||
| 115 | mmci_init_sg(host, data); | 153 | mmci_init_sg(host, data); |
| @@ -210,8 +248,17 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, | |||
| 210 | * We hit an error condition. Ensure that any data | 248 | * We hit an error condition. Ensure that any data |
| 211 | * partially written to a page is properly coherent. | 249 | * partially written to a page is properly coherent. |
| 212 | */ | 250 | */ |
| 213 | if (host->sg_len && data->flags & MMC_DATA_READ) | 251 | if (data->flags & MMC_DATA_READ) { |
| 214 | flush_dcache_page(sg_page(host->sg_ptr)); | 252 | struct sg_mapping_iter *sg_miter = &host->sg_miter; |
| 253 | unsigned long flags; | ||
| 254 | |||
| 255 | local_irq_save(flags); | ||
| 256 | if (sg_miter_next(sg_miter)) { | ||
| 257 | flush_dcache_page(sg_miter->page); | ||
| 258 | sg_miter_stop(sg_miter); | ||
| 259 | } | ||
| 260 | local_irq_restore(flags); | ||
| 261 | } | ||
| 215 | } | 262 | } |
| 216 | if (status & MCI_DATAEND) { | 263 | if (status & MCI_DATAEND) { |
| 217 | mmci_stop_data(host); | 264 | mmci_stop_data(host); |
| @@ -314,15 +361,18 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem | |||
| 314 | static irqreturn_t mmci_pio_irq(int irq, void *dev_id) | 361 | static irqreturn_t mmci_pio_irq(int irq, void *dev_id) |
| 315 | { | 362 | { |
| 316 | struct mmci_host *host = dev_id; | 363 | struct mmci_host *host = dev_id; |
| 364 | struct sg_mapping_iter *sg_miter = &host->sg_miter; | ||
| 317 | void __iomem *base = host->base; | 365 | void __iomem *base = host->base; |
| 366 | unsigned long flags; | ||
| 318 | u32 status; | 367 | u32 status; |
| 319 | 368 | ||
| 320 | status = readl(base + MMCISTATUS); | 369 | status = readl(base + MMCISTATUS); |
| 321 | 370 | ||
| 322 | dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); | 371 | dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); |
| 323 | 372 | ||
| 373 | local_irq_save(flags); | ||
| 374 | |||
| 324 | do { | 375 | do { |
| 325 | unsigned long flags; | ||
| 326 | unsigned int remain, len; | 376 | unsigned int remain, len; |
| 327 | char *buffer; | 377 | char *buffer; |
| 328 | 378 | ||
| @@ -336,11 +386,11 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) | |||
| 336 | if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) | 386 | if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) |
| 337 | break; | 387 | break; |
| 338 | 388 | ||
| 339 | /* | 389 | if (!sg_miter_next(sg_miter)) |
| 340 | * Map the current scatter buffer. | 390 | break; |
| 341 | */ | 391 | |
| 342 | buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; | 392 | buffer = sg_miter->addr; |
| 343 | remain = host->sg_ptr->length - host->sg_off; | 393 | remain = sg_miter->length; |
| 344 | 394 | ||
| 345 | len = 0; | 395 | len = 0; |
| 346 | if (status & MCI_RXACTIVE) | 396 | if (status & MCI_RXACTIVE) |
| @@ -348,31 +398,24 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) | |||
| 348 | if (status & MCI_TXACTIVE) | 398 | if (status & MCI_TXACTIVE) |
| 349 | len = mmci_pio_write(host, buffer, remain, status); | 399 | len = mmci_pio_write(host, buffer, remain, status); |
| 350 | 400 | ||
| 351 | /* | 401 | sg_miter->consumed = len; |
| 352 | * Unmap the buffer. | ||
| 353 | */ | ||
| 354 | mmci_kunmap_atomic(host, buffer, &flags); | ||
| 355 | 402 | ||
| 356 | host->sg_off += len; | ||
| 357 | host->size -= len; | 403 | host->size -= len; |
| 358 | remain -= len; | 404 | remain -= len; |
| 359 | 405 | ||
| 360 | if (remain) | 406 | if (remain) |
| 361 | break; | 407 | break; |
| 362 | 408 | ||
| 363 | /* | ||
| 364 | * If we were reading, and we have completed this | ||
| 365 | * page, ensure that the data cache is coherent. | ||
| 366 | */ | ||
| 367 | if (status & MCI_RXACTIVE) | 409 | if (status & MCI_RXACTIVE) |
| 368 | flush_dcache_page(sg_page(host->sg_ptr)); | 410 | flush_dcache_page(sg_miter->page); |
| 369 | |||
| 370 | if (!mmci_next_sg(host)) | ||
| 371 | break; | ||
| 372 | 411 | ||
| 373 | status = readl(base + MMCISTATUS); | 412 | status = readl(base + MMCISTATUS); |
| 374 | } while (1); | 413 | } while (1); |
| 375 | 414 | ||
| 415 | sg_miter_stop(sg_miter); | ||
| 416 | |||
| 417 | local_irq_restore(flags); | ||
| 418 | |||
| 376 | /* | 419 | /* |
| 377 | * If we're nearing the end of the read, switch to | 420 | * If we're nearing the end of the read, switch to |
| 378 | * "any data available" mode. | 421 | * "any data available" mode. |
| @@ -477,16 +520,9 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 477 | /* This implicitly enables the regulator */ | 520 | /* This implicitly enables the regulator */ |
| 478 | mmc_regulator_set_ocr(host->vcc, ios->vdd); | 521 | mmc_regulator_set_ocr(host->vcc, ios->vdd); |
| 479 | #endif | 522 | #endif |
| 480 | /* | 523 | if (host->plat->vdd_handler) |
| 481 | * The translate_vdd function is not used if you have | 524 | pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd, |
| 482 | * an external regulator, or your design is really weird. | 525 | ios->power_mode); |
| 483 | * Using it would mean sending in power control BOTH using | ||
| 484 | * a regulator AND the 4 MMCIPWR bits. If we don't have | ||
| 485 | * a regulator, we might have some other platform specific | ||
| 486 | * power control behind this translate function. | ||
| 487 | */ | ||
| 488 | if (!host->vcc && host->plat->translate_vdd) | ||
| 489 | pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); | ||
| 490 | /* The ST version does not have this, fall through to POWER_ON */ | 526 | /* The ST version does not have this, fall through to POWER_ON */ |
| 491 | if (host->hw_designer != AMBA_VENDOR_ST) { | 527 | if (host->hw_designer != AMBA_VENDOR_ST) { |
| 492 | pwr |= MCI_PWR_UP; | 528 | pwr |= MCI_PWR_UP; |
| @@ -555,21 +591,10 @@ static const struct mmc_host_ops mmci_ops = { | |||
| 555 | .get_cd = mmci_get_cd, | 591 | .get_cd = mmci_get_cd, |
| 556 | }; | 592 | }; |
| 557 | 593 | ||
| 558 | static void mmci_check_status(unsigned long data) | ||
| 559 | { | ||
| 560 | struct mmci_host *host = (struct mmci_host *)data; | ||
| 561 | unsigned int status = mmci_get_cd(host->mmc); | ||
| 562 | |||
| 563 | if (status ^ host->oldstat) | ||
| 564 | mmc_detect_change(host->mmc, 0); | ||
| 565 | |||
| 566 | host->oldstat = status; | ||
| 567 | mod_timer(&host->timer, jiffies + HZ); | ||
| 568 | } | ||
| 569 | |||
| 570 | static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | 594 | static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) |
| 571 | { | 595 | { |
| 572 | struct mmci_platform_data *plat = dev->dev.platform_data; | 596 | struct mmci_platform_data *plat = dev->dev.platform_data; |
| 597 | struct variant_data *variant = id->data; | ||
| 573 | struct mmci_host *host; | 598 | struct mmci_host *host; |
| 574 | struct mmc_host *mmc; | 599 | struct mmc_host *mmc; |
| 575 | int ret; | 600 | int ret; |
| @@ -613,6 +638,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
| 613 | goto clk_free; | 638 | goto clk_free; |
| 614 | 639 | ||
| 615 | host->plat = plat; | 640 | host->plat = plat; |
| 641 | host->variant = variant; | ||
| 616 | host->mclk = clk_get_rate(host->clk); | 642 | host->mclk = clk_get_rate(host->clk); |
| 617 | /* | 643 | /* |
| 618 | * According to the spec, mclk is max 100 MHz, | 644 | * According to the spec, mclk is max 100 MHz, |
| @@ -673,6 +699,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
| 673 | if (host->vcc == NULL) | 699 | if (host->vcc == NULL) |
| 674 | mmc->ocr_avail = plat->ocr_mask; | 700 | mmc->ocr_avail = plat->ocr_mask; |
| 675 | mmc->caps = plat->capabilities; | 701 | mmc->caps = plat->capabilities; |
| 702 | mmc->caps |= MMC_CAP_NEEDS_POLL; | ||
| 676 | 703 | ||
| 677 | /* | 704 | /* |
| 678 | * We can do SGIO | 705 | * We can do SGIO |
| @@ -681,10 +708,11 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
| 681 | mmc->max_phys_segs = NR_SG; | 708 | mmc->max_phys_segs = NR_SG; |
| 682 | 709 | ||
| 683 | /* | 710 | /* |
| 684 | * Since we only have a 16-bit data length register, we must | 711 | * Since only a certain number of bits are valid in the data length |
| 685 | * ensure that we don't exceed 2^16-1 bytes in a single request. | 712 | * register, we must ensure that we don't exceed 2^num-1 bytes in a |
| 713 | * single request. | ||
| 686 | */ | 714 | */ |
| 687 | mmc->max_req_size = 65535; | 715 | mmc->max_req_size = (1 << variant->datalength_bits) - 1; |
| 688 | 716 | ||
| 689 | /* | 717 | /* |
| 690 | * Set the maximum segment size. Since we aren't doing DMA | 718 | * Set the maximum segment size. Since we aren't doing DMA |
| @@ -738,7 +766,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
| 738 | writel(MCI_IRQENABLE, host->base + MMCIMASK0); | 766 | writel(MCI_IRQENABLE, host->base + MMCIMASK0); |
| 739 | 767 | ||
| 740 | amba_set_drvdata(dev, mmc); | 768 | amba_set_drvdata(dev, mmc); |
| 741 | host->oldstat = mmci_get_cd(host->mmc); | ||
| 742 | 769 | ||
| 743 | mmc_add_host(mmc); | 770 | mmc_add_host(mmc); |
| 744 | 771 | ||
| @@ -746,12 +773,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
| 746 | mmc_hostname(mmc), amba_rev(dev), amba_config(dev), | 773 | mmc_hostname(mmc), amba_rev(dev), amba_config(dev), |
| 747 | (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); | 774 | (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); |
| 748 | 775 | ||
| 749 | init_timer(&host->timer); | ||
| 750 | host->timer.data = (unsigned long)host; | ||
| 751 | host->timer.function = mmci_check_status; | ||
| 752 | host->timer.expires = jiffies + HZ; | ||
| 753 | add_timer(&host->timer); | ||
| 754 | |||
| 755 | return 0; | 776 | return 0; |
| 756 | 777 | ||
| 757 | irq0_free: | 778 | irq0_free: |
| @@ -785,8 +806,6 @@ static int __devexit mmci_remove(struct amba_device *dev) | |||
| 785 | if (mmc) { | 806 | if (mmc) { |
| 786 | struct mmci_host *host = mmc_priv(mmc); | 807 | struct mmci_host *host = mmc_priv(mmc); |
| 787 | 808 | ||
| 788 | del_timer_sync(&host->timer); | ||
| 789 | |||
| 790 | mmc_remove_host(mmc); | 809 | mmc_remove_host(mmc); |
| 791 | 810 | ||
| 792 | writel(0, host->base + MMCIMASK0); | 811 | writel(0, host->base + MMCIMASK0); |
| @@ -860,19 +879,28 @@ static struct amba_id mmci_ids[] = { | |||
| 860 | { | 879 | { |
| 861 | .id = 0x00041180, | 880 | .id = 0x00041180, |
| 862 | .mask = 0x000fffff, | 881 | .mask = 0x000fffff, |
| 882 | .data = &variant_arm, | ||
| 863 | }, | 883 | }, |
| 864 | { | 884 | { |
| 865 | .id = 0x00041181, | 885 | .id = 0x00041181, |
| 866 | .mask = 0x000fffff, | 886 | .mask = 0x000fffff, |
| 887 | .data = &variant_arm, | ||
| 867 | }, | 888 | }, |
| 868 | /* ST Micro variants */ | 889 | /* ST Micro variants */ |
| 869 | { | 890 | { |
| 870 | .id = 0x00180180, | 891 | .id = 0x00180180, |
| 871 | .mask = 0x00ffffff, | 892 | .mask = 0x00ffffff, |
| 893 | .data = &variant_u300, | ||
| 872 | }, | 894 | }, |
| 873 | { | 895 | { |
| 874 | .id = 0x00280180, | 896 | .id = 0x00280180, |
| 875 | .mask = 0x00ffffff, | 897 | .mask = 0x00ffffff, |
| 898 | .data = &variant_u300, | ||
| 899 | }, | ||
| 900 | { | ||
| 901 | .id = 0x00480180, | ||
| 902 | .mask = 0x00ffffff, | ||
| 903 | .data = &variant_ux500, | ||
| 876 | }, | 904 | }, |
| 877 | { 0, 0 }, | 905 | { 0, 0 }, |
| 878 | }; | 906 | }; |
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index d77062e5e3a..68970cfb81e 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h | |||
| @@ -28,8 +28,6 @@ | |||
| 28 | #define MCI_4BIT_BUS (1 << 11) | 28 | #define MCI_4BIT_BUS (1 << 11) |
| 29 | /* 8bit wide buses supported in ST Micro versions */ | 29 | /* 8bit wide buses supported in ST Micro versions */ |
| 30 | #define MCI_ST_8BIT_BUS (1 << 12) | 30 | #define MCI_ST_8BIT_BUS (1 << 12) |
| 31 | /* HW flow control on the ST Micro version */ | ||
| 32 | #define MCI_ST_FCEN (1 << 13) | ||
| 33 | 31 | ||
| 34 | #define MMCIARGUMENT 0x008 | 32 | #define MMCIARGUMENT 0x008 |
| 35 | #define MMCICOMMAND 0x00c | 33 | #define MMCICOMMAND 0x00c |
| @@ -145,6 +143,7 @@ | |||
| 145 | #define NR_SG 16 | 143 | #define NR_SG 16 |
| 146 | 144 | ||
| 147 | struct clk; | 145 | struct clk; |
| 146 | struct variant_data; | ||
| 148 | 147 | ||
| 149 | struct mmci_host { | 148 | struct mmci_host { |
| 150 | void __iomem *base; | 149 | void __iomem *base; |
| @@ -164,6 +163,7 @@ struct mmci_host { | |||
| 164 | unsigned int cclk; | 163 | unsigned int cclk; |
| 165 | u32 pwr; | 164 | u32 pwr; |
| 166 | struct mmci_platform_data *plat; | 165 | struct mmci_platform_data *plat; |
| 166 | struct variant_data *variant; | ||
| 167 | 167 | ||
| 168 | u8 hw_designer; | 168 | u8 hw_designer; |
| 169 | u8 hw_revision:4; | 169 | u8 hw_revision:4; |
| @@ -171,42 +171,9 @@ struct mmci_host { | |||
| 171 | struct timer_list timer; | 171 | struct timer_list timer; |
| 172 | unsigned int oldstat; | 172 | unsigned int oldstat; |
| 173 | 173 | ||
| 174 | unsigned int sg_len; | ||
| 175 | |||
| 176 | /* pio stuff */ | 174 | /* pio stuff */ |
| 177 | struct scatterlist *sg_ptr; | 175 | struct sg_mapping_iter sg_miter; |
| 178 | unsigned int sg_off; | ||
| 179 | unsigned int size; | 176 | unsigned int size; |
| 180 | struct regulator *vcc; | 177 | struct regulator *vcc; |
| 181 | }; | 178 | }; |
| 182 | 179 | ||
| 183 | static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) | ||
| 184 | { | ||
| 185 | /* | ||
| 186 | * Ideally, we want the higher levels to pass us a scatter list. | ||
| 187 | */ | ||
| 188 | host->sg_len = data->sg_len; | ||
| 189 | host->sg_ptr = data->sg; | ||
| 190 | host->sg_off = 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | static inline int mmci_next_sg(struct mmci_host *host) | ||
| 194 | { | ||
| 195 | host->sg_ptr++; | ||
| 196 | host->sg_off = 0; | ||
| 197 | return --host->sg_len; | ||
| 198 | } | ||
| 199 | |||
| 200 | static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags) | ||
| 201 | { | ||
| 202 | struct scatterlist *sg = host->sg_ptr; | ||
| 203 | |||
| 204 | local_irq_save(*flags); | ||
| 205 | return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; | ||
| 206 | } | ||
| 207 | |||
| 208 | static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags) | ||
| 209 | { | ||
| 210 | kunmap_atomic(buffer, KM_BIO_SRC_IRQ); | ||
| 211 | local_irq_restore(*flags); | ||
| 212 | } | ||
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index d9d4a72e0ec..350f78e8624 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c | |||
| @@ -119,6 +119,7 @@ struct mxcmci_host { | |||
| 119 | int detect_irq; | 119 | int detect_irq; |
| 120 | int dma; | 120 | int dma; |
| 121 | int do_dma; | 121 | int do_dma; |
| 122 | int default_irq_mask; | ||
| 122 | int use_sdio; | 123 | int use_sdio; |
| 123 | unsigned int power_mode; | 124 | unsigned int power_mode; |
| 124 | struct imxmmc_platform_data *pdata; | 125 | struct imxmmc_platform_data *pdata; |
| @@ -228,7 +229,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) | |||
| 228 | static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, | 229 | static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, |
| 229 | unsigned int cmdat) | 230 | unsigned int cmdat) |
| 230 | { | 231 | { |
| 231 | u32 int_cntr; | 232 | u32 int_cntr = host->default_irq_mask; |
| 232 | unsigned long flags; | 233 | unsigned long flags; |
| 233 | 234 | ||
| 234 | WARN_ON(host->cmd != NULL); | 235 | WARN_ON(host->cmd != NULL); |
| @@ -275,7 +276,7 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, | |||
| 275 | static void mxcmci_finish_request(struct mxcmci_host *host, | 276 | static void mxcmci_finish_request(struct mxcmci_host *host, |
| 276 | struct mmc_request *req) | 277 | struct mmc_request *req) |
| 277 | { | 278 | { |
| 278 | u32 int_cntr = 0; | 279 | u32 int_cntr = host->default_irq_mask; |
| 279 | unsigned long flags; | 280 | unsigned long flags; |
| 280 | 281 | ||
| 281 | spin_lock_irqsave(&host->lock, flags); | 282 | spin_lock_irqsave(&host->lock, flags); |
| @@ -585,6 +586,9 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) | |||
| 585 | (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) | 586 | (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) |
| 586 | mxcmci_data_done(host, stat); | 587 | mxcmci_data_done(host, stat); |
| 587 | #endif | 588 | #endif |
| 589 | if (host->default_irq_mask && | ||
| 590 | (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL))) | ||
| 591 | mmc_detect_change(host->mmc, msecs_to_jiffies(200)); | ||
| 588 | return IRQ_HANDLED; | 592 | return IRQ_HANDLED; |
| 589 | } | 593 | } |
| 590 | 594 | ||
| @@ -809,6 +813,12 @@ static int mxcmci_probe(struct platform_device *pdev) | |||
| 809 | else | 813 | else |
| 810 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | 814 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; |
| 811 | 815 | ||
| 816 | if (host->pdata && host->pdata->dat3_card_detect) | ||
| 817 | host->default_irq_mask = | ||
| 818 | INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN; | ||
| 819 | else | ||
| 820 | host->default_irq_mask = 0; | ||
| 821 | |||
| 812 | host->res = r; | 822 | host->res = r; |
| 813 | host->irq = irq; | 823 | host->irq = irq; |
| 814 | 824 | ||
| @@ -835,7 +845,7 @@ static int mxcmci_probe(struct platform_device *pdev) | |||
| 835 | /* recommended in data sheet */ | 845 | /* recommended in data sheet */ |
| 836 | writew(0x2db4, host->base + MMC_REG_READ_TO); | 846 | writew(0x2db4, host->base + MMC_REG_READ_TO); |
| 837 | 847 | ||
| 838 | writel(0, host->base + MMC_REG_INT_CNTR); | 848 | writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR); |
| 839 | 849 | ||
| 840 | #ifdef HAS_DMA | 850 | #ifdef HAS_DMA |
| 841 | host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); | 851 | host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); |
| @@ -926,43 +936,47 @@ static int mxcmci_remove(struct platform_device *pdev) | |||
| 926 | } | 936 | } |
| 927 | 937 | ||
| 928 | #ifdef CONFIG_PM | 938 | #ifdef CONFIG_PM |
| 929 | static int mxcmci_suspend(struct platform_device *dev, pm_message_t state) | 939 | static int mxcmci_suspend(struct device *dev) |
| 930 | { | 940 | { |
| 931 | struct mmc_host *mmc = platform_get_drvdata(dev); | 941 | struct mmc_host *mmc = dev_get_drvdata(dev); |
| 942 | struct mxcmci_host *host = mmc_priv(mmc); | ||
| 932 | int ret = 0; | 943 | int ret = 0; |
| 933 | 944 | ||
| 934 | if (mmc) | 945 | if (mmc) |
| 935 | ret = mmc_suspend_host(mmc); | 946 | ret = mmc_suspend_host(mmc); |
| 947 | clk_disable(host->clk); | ||
| 936 | 948 | ||
| 937 | return ret; | 949 | return ret; |
| 938 | } | 950 | } |
| 939 | 951 | ||
| 940 | static int mxcmci_resume(struct platform_device *dev) | 952 | static int mxcmci_resume(struct device *dev) |
| 941 | { | 953 | { |
| 942 | struct mmc_host *mmc = platform_get_drvdata(dev); | 954 | struct mmc_host *mmc = dev_get_drvdata(dev); |
| 943 | struct mxcmci_host *host; | 955 | struct mxcmci_host *host = mmc_priv(mmc); |
| 944 | int ret = 0; | 956 | int ret = 0; |
| 945 | 957 | ||
| 946 | if (mmc) { | 958 | clk_enable(host->clk); |
| 947 | host = mmc_priv(mmc); | 959 | if (mmc) |
| 948 | ret = mmc_resume_host(mmc); | 960 | ret = mmc_resume_host(mmc); |
| 949 | } | ||
| 950 | 961 | ||
| 951 | return ret; | 962 | return ret; |
| 952 | } | 963 | } |
| 953 | #else | 964 | |
| 954 | #define mxcmci_suspend NULL | 965 | static const struct dev_pm_ops mxcmci_pm_ops = { |
| 955 | #define mxcmci_resume NULL | 966 | .suspend = mxcmci_suspend, |
| 956 | #endif /* CONFIG_PM */ | 967 | .resume = mxcmci_resume, |
| 968 | }; | ||
| 969 | #endif | ||
| 957 | 970 | ||
| 958 | static struct platform_driver mxcmci_driver = { | 971 | static struct platform_driver mxcmci_driver = { |
| 959 | .probe = mxcmci_probe, | 972 | .probe = mxcmci_probe, |
| 960 | .remove = mxcmci_remove, | 973 | .remove = mxcmci_remove, |
| 961 | .suspend = mxcmci_suspend, | ||
| 962 | .resume = mxcmci_resume, | ||
| 963 | .driver = { | 974 | .driver = { |
| 964 | .name = DRIVER_NAME, | 975 | .name = DRIVER_NAME, |
| 965 | .owner = THIS_MODULE, | 976 | .owner = THIS_MODULE, |
| 977 | #ifdef CONFIG_PM | ||
| 978 | .pm = &mxcmci_pm_ops, | ||
| 979 | #endif | ||
| 966 | } | 980 | } |
| 967 | }; | 981 | }; |
| 968 | 982 | ||
