diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/mmci.c | 156 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 39 | ||||
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 48 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-s3c.c | 20 |
4 files changed, 148 insertions, 115 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 4917af96bae1..840b301b5671 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; |
@@ -539,9 +575,13 @@ static int mmci_get_cd(struct mmc_host *mmc) | |||
539 | if (host->gpio_cd == -ENOSYS) | 575 | if (host->gpio_cd == -ENOSYS) |
540 | status = host->plat->status(mmc_dev(host->mmc)); | 576 | status = host->plat->status(mmc_dev(host->mmc)); |
541 | else | 577 | else |
542 | status = gpio_get_value(host->gpio_cd); | 578 | status = !gpio_get_value(host->gpio_cd); |
543 | 579 | ||
544 | return !status; | 580 | /* |
581 | * Use positive logic throughout - status is zero for no card, | ||
582 | * non-zero for card inserted. | ||
583 | */ | ||
584 | return status; | ||
545 | } | 585 | } |
546 | 586 | ||
547 | static const struct mmc_host_ops mmci_ops = { | 587 | static const struct mmc_host_ops mmci_ops = { |
@@ -551,21 +591,10 @@ static const struct mmc_host_ops mmci_ops = { | |||
551 | .get_cd = mmci_get_cd, | 591 | .get_cd = mmci_get_cd, |
552 | }; | 592 | }; |
553 | 593 | ||
554 | static void mmci_check_status(unsigned long data) | ||
555 | { | ||
556 | struct mmci_host *host = (struct mmci_host *)data; | ||
557 | unsigned int status = mmci_get_cd(host->mmc); | ||
558 | |||
559 | if (status ^ host->oldstat) | ||
560 | mmc_detect_change(host->mmc, 0); | ||
561 | |||
562 | host->oldstat = status; | ||
563 | mod_timer(&host->timer, jiffies + HZ); | ||
564 | } | ||
565 | |||
566 | 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) |
567 | { | 595 | { |
568 | 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; | ||
569 | struct mmci_host *host; | 598 | struct mmci_host *host; |
570 | struct mmc_host *mmc; | 599 | struct mmc_host *mmc; |
571 | int ret; | 600 | int ret; |
@@ -609,6 +638,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
609 | goto clk_free; | 638 | goto clk_free; |
610 | 639 | ||
611 | host->plat = plat; | 640 | host->plat = plat; |
641 | host->variant = variant; | ||
612 | host->mclk = clk_get_rate(host->clk); | 642 | host->mclk = clk_get_rate(host->clk); |
613 | /* | 643 | /* |
614 | * According to the spec, mclk is max 100 MHz, | 644 | * According to the spec, mclk is max 100 MHz, |
@@ -669,6 +699,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
669 | if (host->vcc == NULL) | 699 | if (host->vcc == NULL) |
670 | mmc->ocr_avail = plat->ocr_mask; | 700 | mmc->ocr_avail = plat->ocr_mask; |
671 | mmc->caps = plat->capabilities; | 701 | mmc->caps = plat->capabilities; |
702 | mmc->caps |= MMC_CAP_NEEDS_POLL; | ||
672 | 703 | ||
673 | /* | 704 | /* |
674 | * We can do SGIO | 705 | * We can do SGIO |
@@ -677,10 +708,11 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
677 | mmc->max_phys_segs = NR_SG; | 708 | mmc->max_phys_segs = NR_SG; |
678 | 709 | ||
679 | /* | 710 | /* |
680 | * 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 |
681 | * 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. | ||
682 | */ | 714 | */ |
683 | mmc->max_req_size = 65535; | 715 | mmc->max_req_size = (1 << variant->datalength_bits) - 1; |
684 | 716 | ||
685 | /* | 717 | /* |
686 | * Set the maximum segment size. Since we aren't doing DMA | 718 | * Set the maximum segment size. Since we aren't doing DMA |
@@ -734,7 +766,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
734 | writel(MCI_IRQENABLE, host->base + MMCIMASK0); | 766 | writel(MCI_IRQENABLE, host->base + MMCIMASK0); |
735 | 767 | ||
736 | amba_set_drvdata(dev, mmc); | 768 | amba_set_drvdata(dev, mmc); |
737 | host->oldstat = mmci_get_cd(host->mmc); | ||
738 | 769 | ||
739 | mmc_add_host(mmc); | 770 | mmc_add_host(mmc); |
740 | 771 | ||
@@ -742,12 +773,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
742 | mmc_hostname(mmc), amba_rev(dev), amba_config(dev), | 773 | mmc_hostname(mmc), amba_rev(dev), amba_config(dev), |
743 | (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]); |
744 | 775 | ||
745 | init_timer(&host->timer); | ||
746 | host->timer.data = (unsigned long)host; | ||
747 | host->timer.function = mmci_check_status; | ||
748 | host->timer.expires = jiffies + HZ; | ||
749 | add_timer(&host->timer); | ||
750 | |||
751 | return 0; | 776 | return 0; |
752 | 777 | ||
753 | irq0_free: | 778 | irq0_free: |
@@ -781,8 +806,6 @@ static int __devexit mmci_remove(struct amba_device *dev) | |||
781 | if (mmc) { | 806 | if (mmc) { |
782 | struct mmci_host *host = mmc_priv(mmc); | 807 | struct mmci_host *host = mmc_priv(mmc); |
783 | 808 | ||
784 | del_timer_sync(&host->timer); | ||
785 | |||
786 | mmc_remove_host(mmc); | 809 | mmc_remove_host(mmc); |
787 | 810 | ||
788 | writel(0, host->base + MMCIMASK0); | 811 | writel(0, host->base + MMCIMASK0); |
@@ -856,19 +879,28 @@ static struct amba_id mmci_ids[] = { | |||
856 | { | 879 | { |
857 | .id = 0x00041180, | 880 | .id = 0x00041180, |
858 | .mask = 0x000fffff, | 881 | .mask = 0x000fffff, |
882 | .data = &variant_arm, | ||
859 | }, | 883 | }, |
860 | { | 884 | { |
861 | .id = 0x00041181, | 885 | .id = 0x00041181, |
862 | .mask = 0x000fffff, | 886 | .mask = 0x000fffff, |
887 | .data = &variant_arm, | ||
863 | }, | 888 | }, |
864 | /* ST Micro variants */ | 889 | /* ST Micro variants */ |
865 | { | 890 | { |
866 | .id = 0x00180180, | 891 | .id = 0x00180180, |
867 | .mask = 0x00ffffff, | 892 | .mask = 0x00ffffff, |
893 | .data = &variant_u300, | ||
868 | }, | 894 | }, |
869 | { | 895 | { |
870 | .id = 0x00280180, | 896 | .id = 0x00280180, |
871 | .mask = 0x00ffffff, | 897 | .mask = 0x00ffffff, |
898 | .data = &variant_u300, | ||
899 | }, | ||
900 | { | ||
901 | .id = 0x00480180, | ||
902 | .mask = 0x00ffffff, | ||
903 | .data = &variant_ux500, | ||
872 | }, | 904 | }, |
873 | { 0, 0 }, | 905 | { 0, 0 }, |
874 | }; | 906 | }; |
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index d77062e5e3af..68970cfb81e1 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 d9d4a72e0ec7..350f78e86245 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 | ||
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index af217924a76e..ad30f074ee15 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c | |||
@@ -365,6 +365,26 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
365 | 365 | ||
366 | static int __devexit sdhci_s3c_remove(struct platform_device *pdev) | 366 | static int __devexit sdhci_s3c_remove(struct platform_device *pdev) |
367 | { | 367 | { |
368 | struct sdhci_host *host = platform_get_drvdata(pdev); | ||
369 | struct sdhci_s3c *sc = sdhci_priv(host); | ||
370 | int ptr; | ||
371 | |||
372 | sdhci_remove_host(host, 1); | ||
373 | |||
374 | for (ptr = 0; ptr < 3; ptr++) { | ||
375 | clk_disable(sc->clk_bus[ptr]); | ||
376 | clk_put(sc->clk_bus[ptr]); | ||
377 | } | ||
378 | clk_disable(sc->clk_io); | ||
379 | clk_put(sc->clk_io); | ||
380 | |||
381 | iounmap(host->ioaddr); | ||
382 | release_resource(sc->ioarea); | ||
383 | kfree(sc->ioarea); | ||
384 | |||
385 | sdhci_free_host(host); | ||
386 | platform_set_drvdata(pdev, NULL); | ||
387 | |||
368 | return 0; | 388 | return 0; |
369 | } | 389 | } |
370 | 390 | ||