diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2010-06-30 06:16:24 -0400 |
---|---|---|
committer | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2010-07-26 08:27:25 -0400 |
commit | 2dcf78c0eeae3bd07082821557014f25f02ca2e9 (patch) | |
tree | 8ca5c4c7f35c9a9ab07fcd9732124c905e609aa1 /drivers/mmc | |
parent | 6b6322676add0fa2713d0ec89a28390fd4d907f5 (diff) | |
parent | 5109a4597f7e758b8d20694392d0361a0b4c43b1 (diff) |
Merge branch 'imx/for-2.6.36' of git://git.pengutronix.de/git/ukl/linux-2.6 into HEAD
There are some more conflicts than detected by git, namely support for
the newly added cpuimx machines needed to be converted to dynamic device
registration.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Conflicts:
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/devices.c
arch/arm/mach-imx/devices.h
arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
arch/arm/mach-mx2/Kconfig
arch/arm/mach-mx25/Makefile
arch/arm/mach-mx25/devices.c
arch/arm/plat-mxc/include/mach/mx25.h
arch/arm/plat-mxc/include/mach/mxc_nand.h
Diffstat (limited to 'drivers/mmc')
35 files changed, 1721 insertions, 281 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3168ebd616b2..569e94da844c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1252,9 +1252,8 @@ EXPORT_SYMBOL(mmc_card_can_sleep); | |||
1252 | /** | 1252 | /** |
1253 | * mmc_suspend_host - suspend a host | 1253 | * mmc_suspend_host - suspend a host |
1254 | * @host: mmc host | 1254 | * @host: mmc host |
1255 | * @state: suspend mode (PM_SUSPEND_xxx) | ||
1256 | */ | 1255 | */ |
1257 | int mmc_suspend_host(struct mmc_host *host, pm_message_t state) | 1256 | int mmc_suspend_host(struct mmc_host *host) |
1258 | { | 1257 | { |
1259 | int err = 0; | 1258 | int err = 0; |
1260 | 1259 | ||
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 0d96080d44b0..63772e7e7608 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c | |||
@@ -79,8 +79,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, | |||
79 | * we cannot use the retries field in mmc_command. | 79 | * we cannot use the retries field in mmc_command. |
80 | */ | 80 | */ |
81 | for (i = 0;i <= retries;i++) { | 81 | for (i = 0;i <= retries;i++) { |
82 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
83 | |||
84 | err = mmc_app_cmd(host, card); | 82 | err = mmc_app_cmd(host, card); |
85 | if (err) { | 83 | if (err) { |
86 | /* no point in retrying; no APP commands allowed */ | 84 | /* no point in retrying; no APP commands allowed */ |
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index ff27c8c71355..0f687cdeb064 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c | |||
@@ -406,6 +406,36 @@ void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret) | |||
406 | EXPORT_SYMBOL_GPL(sdio_writeb); | 406 | EXPORT_SYMBOL_GPL(sdio_writeb); |
407 | 407 | ||
408 | /** | 408 | /** |
409 | * sdio_writeb_readb - write and read a byte from SDIO function | ||
410 | * @func: SDIO function to access | ||
411 | * @write_byte: byte to write | ||
412 | * @addr: address to write to | ||
413 | * @err_ret: optional status value from transfer | ||
414 | * | ||
415 | * Performs a RAW (Read after Write) operation as defined by SDIO spec - | ||
416 | * single byte is written to address space of a given SDIO function and | ||
417 | * response is read back from the same address, both using single request. | ||
418 | * If there is a problem with the operation, 0xff is returned and | ||
419 | * @err_ret will contain the error code. | ||
420 | */ | ||
421 | u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte, | ||
422 | unsigned int addr, int *err_ret) | ||
423 | { | ||
424 | int ret; | ||
425 | u8 val; | ||
426 | |||
427 | ret = mmc_io_rw_direct(func->card, 1, func->num, addr, | ||
428 | write_byte, &val); | ||
429 | if (err_ret) | ||
430 | *err_ret = ret; | ||
431 | if (ret) | ||
432 | val = 0xff; | ||
433 | |||
434 | return val; | ||
435 | } | ||
436 | EXPORT_SYMBOL_GPL(sdio_writeb_readb); | ||
437 | |||
438 | /** | ||
409 | * sdio_memcpy_fromio - read a chunk of memory from a SDIO function | 439 | * sdio_memcpy_fromio - read a chunk of memory from a SDIO function |
410 | * @func: SDIO function to access | 440 | * @func: SDIO function to access |
411 | * @dst: buffer to store the data | 441 | * @dst: buffer to store the data |
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2e13b94769fd..e171e77f6129 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
@@ -136,6 +136,18 @@ config MMC_SDHCI_S3C | |||
136 | 136 | ||
137 | If unsure, say N. | 137 | If unsure, say N. |
138 | 138 | ||
139 | config MMC_SDHCI_SPEAR | ||
140 | tristate "SDHCI support on ST SPEAr platform" | ||
141 | depends on MMC_SDHCI && PLAT_SPEAR | ||
142 | help | ||
143 | This selects the Secure Digital Host Controller Interface (SDHCI) | ||
144 | often referrered to as the HSMMC block in some of the ST SPEAR range | ||
145 | of SoC | ||
146 | |||
147 | If you have a controller with this interface, say Y or M here. | ||
148 | |||
149 | If unsure, say N. | ||
150 | |||
139 | config MMC_SDHCI_S3C_DMA | 151 | config MMC_SDHCI_S3C_DMA |
140 | bool "DMA support on S3C SDHCI" | 152 | bool "DMA support on S3C SDHCI" |
141 | depends on MMC_SDHCI_S3C && EXPERIMENTAL | 153 | depends on MMC_SDHCI_S3C && EXPERIMENTAL |
@@ -412,3 +424,11 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND | |||
412 | depends on SDH_BFIN | 424 | depends on SDH_BFIN |
413 | help | 425 | help |
414 | If you say yes here SD-Cards may work on the EZkit. | 426 | If you say yes here SD-Cards may work on the EZkit. |
427 | |||
428 | config MMC_SH_MMCIF | ||
429 | tristate "SuperH Internal MMCIF support" | ||
430 | depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE) | ||
431 | help | ||
432 | This selects the MMC Host Interface controler (MMCIF). | ||
433 | |||
434 | This driver supports MMCIF in sh7724/sh7757/sh7372. | ||
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index f4803977dfce..e30c2ee48894 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile | |||
@@ -14,6 +14,7 @@ obj-$(CONFIG_MMC_SDHCI) += sdhci.o | |||
14 | obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o | 14 | obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o |
15 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o | 15 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o |
16 | obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o | 16 | obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o |
17 | obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o | ||
17 | obj-$(CONFIG_MMC_WBSD) += wbsd.o | 18 | obj-$(CONFIG_MMC_WBSD) += wbsd.o |
18 | obj-$(CONFIG_MMC_AU1X) += au1xmmc.o | 19 | obj-$(CONFIG_MMC_AU1X) += au1xmmc.o |
19 | obj-$(CONFIG_MMC_OMAP) += omap.o | 20 | obj-$(CONFIG_MMC_OMAP) += omap.o |
@@ -34,6 +35,7 @@ obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o | |||
34 | obj-$(CONFIG_MMC_CB710) += cb710-mmc.o | 35 | obj-$(CONFIG_MMC_CB710) += cb710-mmc.o |
35 | obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o | 36 | obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o |
36 | obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o | 37 | obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o |
38 | obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o | ||
37 | 39 | ||
38 | obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o | 40 | obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o |
39 | sdhci-of-y := sdhci-of-core.o | 41 | sdhci-of-y := sdhci-of-core.o |
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 336d9f553f3e..5f3a599ead07 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c | |||
@@ -1157,7 +1157,7 @@ static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state) | |||
1157 | enable_irq_wake(host->board->det_pin); | 1157 | enable_irq_wake(host->board->det_pin); |
1158 | 1158 | ||
1159 | if (mmc) | 1159 | if (mmc) |
1160 | ret = mmc_suspend_host(mmc, state); | 1160 | ret = mmc_suspend_host(mmc); |
1161 | 1161 | ||
1162 | return ret; | 1162 | return ret; |
1163 | } | 1163 | } |
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index df0e8a88d85f..95ef864ad8f9 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
@@ -173,6 +173,7 @@ struct atmel_mci { | |||
173 | * @mmc: The mmc_host representing this slot. | 173 | * @mmc: The mmc_host representing this slot. |
174 | * @host: The MMC controller this slot is using. | 174 | * @host: The MMC controller this slot is using. |
175 | * @sdc_reg: Value of SDCR to be written before using this slot. | 175 | * @sdc_reg: Value of SDCR to be written before using this slot. |
176 | * @sdio_irq: SDIO irq mask for this slot. | ||
176 | * @mrq: mmc_request currently being processed or waiting to be | 177 | * @mrq: mmc_request currently being processed or waiting to be |
177 | * processed, or NULL when the slot is idle. | 178 | * processed, or NULL when the slot is idle. |
178 | * @queue_node: List node for placing this node in the @queue list of | 179 | * @queue_node: List node for placing this node in the @queue list of |
@@ -191,6 +192,7 @@ struct atmel_mci_slot { | |||
191 | struct atmel_mci *host; | 192 | struct atmel_mci *host; |
192 | 193 | ||
193 | u32 sdc_reg; | 194 | u32 sdc_reg; |
195 | u32 sdio_irq; | ||
194 | 196 | ||
195 | struct mmc_request *mrq; | 197 | struct mmc_request *mrq; |
196 | struct list_head queue_node; | 198 | struct list_head queue_node; |
@@ -792,7 +794,7 @@ static void atmci_start_request(struct atmel_mci *host, | |||
792 | mci_writel(host, SDCR, slot->sdc_reg); | 794 | mci_writel(host, SDCR, slot->sdc_reg); |
793 | 795 | ||
794 | iflags = mci_readl(host, IMR); | 796 | iflags = mci_readl(host, IMR); |
795 | if (iflags) | 797 | if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB)) |
796 | dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", | 798 | dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", |
797 | iflags); | 799 | iflags); |
798 | 800 | ||
@@ -952,10 +954,21 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
952 | if (mci_has_rwproof()) | 954 | if (mci_has_rwproof()) |
953 | host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF); | 955 | host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF); |
954 | 956 | ||
955 | if (list_empty(&host->queue)) | 957 | if (atmci_is_mci2()) { |
958 | /* setup High Speed mode in relation with card capacity */ | ||
959 | if (ios->timing == MMC_TIMING_SD_HS) | ||
960 | host->cfg_reg |= MCI_CFG_HSMODE; | ||
961 | else | ||
962 | host->cfg_reg &= ~MCI_CFG_HSMODE; | ||
963 | } | ||
964 | |||
965 | if (list_empty(&host->queue)) { | ||
956 | mci_writel(host, MR, host->mode_reg); | 966 | mci_writel(host, MR, host->mode_reg); |
957 | else | 967 | if (atmci_is_mci2()) |
968 | mci_writel(host, CFG, host->cfg_reg); | ||
969 | } else { | ||
958 | host->need_clock_update = true; | 970 | host->need_clock_update = true; |
971 | } | ||
959 | 972 | ||
960 | spin_unlock_bh(&host->lock); | 973 | spin_unlock_bh(&host->lock); |
961 | } else { | 974 | } else { |
@@ -1030,11 +1043,23 @@ static int atmci_get_cd(struct mmc_host *mmc) | |||
1030 | return present; | 1043 | return present; |
1031 | } | 1044 | } |
1032 | 1045 | ||
1046 | static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
1047 | { | ||
1048 | struct atmel_mci_slot *slot = mmc_priv(mmc); | ||
1049 | struct atmel_mci *host = slot->host; | ||
1050 | |||
1051 | if (enable) | ||
1052 | mci_writel(host, IER, slot->sdio_irq); | ||
1053 | else | ||
1054 | mci_writel(host, IDR, slot->sdio_irq); | ||
1055 | } | ||
1056 | |||
1033 | static const struct mmc_host_ops atmci_ops = { | 1057 | static const struct mmc_host_ops atmci_ops = { |
1034 | .request = atmci_request, | 1058 | .request = atmci_request, |
1035 | .set_ios = atmci_set_ios, | 1059 | .set_ios = atmci_set_ios, |
1036 | .get_ro = atmci_get_ro, | 1060 | .get_ro = atmci_get_ro, |
1037 | .get_cd = atmci_get_cd, | 1061 | .get_cd = atmci_get_cd, |
1062 | .enable_sdio_irq = atmci_enable_sdio_irq, | ||
1038 | }; | 1063 | }; |
1039 | 1064 | ||
1040 | /* Called with host->lock held */ | 1065 | /* Called with host->lock held */ |
@@ -1052,8 +1077,11 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) | |||
1052 | * necessary if set_ios() is called when a different slot is | 1077 | * necessary if set_ios() is called when a different slot is |
1053 | * busy transfering data. | 1078 | * busy transfering data. |
1054 | */ | 1079 | */ |
1055 | if (host->need_clock_update) | 1080 | if (host->need_clock_update) { |
1056 | mci_writel(host, MR, host->mode_reg); | 1081 | mci_writel(host, MR, host->mode_reg); |
1082 | if (atmci_is_mci2()) | ||
1083 | mci_writel(host, CFG, host->cfg_reg); | ||
1084 | } | ||
1057 | 1085 | ||
1058 | host->cur_slot->mrq = NULL; | 1086 | host->cur_slot->mrq = NULL; |
1059 | host->mrq = NULL; | 1087 | host->mrq = NULL; |
@@ -1483,6 +1511,19 @@ static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) | |||
1483 | tasklet_schedule(&host->tasklet); | 1511 | tasklet_schedule(&host->tasklet); |
1484 | } | 1512 | } |
1485 | 1513 | ||
1514 | static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) | ||
1515 | { | ||
1516 | int i; | ||
1517 | |||
1518 | for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { | ||
1519 | struct atmel_mci_slot *slot = host->slot[i]; | ||
1520 | if (slot && (status & slot->sdio_irq)) { | ||
1521 | mmc_signal_sdio_irq(slot->mmc); | ||
1522 | } | ||
1523 | } | ||
1524 | } | ||
1525 | |||
1526 | |||
1486 | static irqreturn_t atmci_interrupt(int irq, void *dev_id) | 1527 | static irqreturn_t atmci_interrupt(int irq, void *dev_id) |
1487 | { | 1528 | { |
1488 | struct atmel_mci *host = dev_id; | 1529 | struct atmel_mci *host = dev_id; |
@@ -1522,6 +1563,10 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) | |||
1522 | 1563 | ||
1523 | if (pending & MCI_CMDRDY) | 1564 | if (pending & MCI_CMDRDY) |
1524 | atmci_cmd_interrupt(host, status); | 1565 | atmci_cmd_interrupt(host, status); |
1566 | |||
1567 | if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB)) | ||
1568 | atmci_sdio_interrupt(host, status); | ||
1569 | |||
1525 | } while (pass_count++ < 5); | 1570 | } while (pass_count++ < 5); |
1526 | 1571 | ||
1527 | return pass_count ? IRQ_HANDLED : IRQ_NONE; | 1572 | return pass_count ? IRQ_HANDLED : IRQ_NONE; |
@@ -1544,7 +1589,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) | |||
1544 | 1589 | ||
1545 | static int __init atmci_init_slot(struct atmel_mci *host, | 1590 | static int __init atmci_init_slot(struct atmel_mci *host, |
1546 | struct mci_slot_pdata *slot_data, unsigned int id, | 1591 | struct mci_slot_pdata *slot_data, unsigned int id, |
1547 | u32 sdc_reg) | 1592 | u32 sdc_reg, u32 sdio_irq) |
1548 | { | 1593 | { |
1549 | struct mmc_host *mmc; | 1594 | struct mmc_host *mmc; |
1550 | struct atmel_mci_slot *slot; | 1595 | struct atmel_mci_slot *slot; |
@@ -1560,11 +1605,16 @@ static int __init atmci_init_slot(struct atmel_mci *host, | |||
1560 | slot->wp_pin = slot_data->wp_pin; | 1605 | slot->wp_pin = slot_data->wp_pin; |
1561 | slot->detect_is_active_high = slot_data->detect_is_active_high; | 1606 | slot->detect_is_active_high = slot_data->detect_is_active_high; |
1562 | slot->sdc_reg = sdc_reg; | 1607 | slot->sdc_reg = sdc_reg; |
1608 | slot->sdio_irq = sdio_irq; | ||
1563 | 1609 | ||
1564 | mmc->ops = &atmci_ops; | 1610 | mmc->ops = &atmci_ops; |
1565 | mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); | 1611 | mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); |
1566 | mmc->f_max = host->bus_hz / 2; | 1612 | mmc->f_max = host->bus_hz / 2; |
1567 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | 1613 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; |
1614 | if (sdio_irq) | ||
1615 | mmc->caps |= MMC_CAP_SDIO_IRQ; | ||
1616 | if (atmci_is_mci2()) | ||
1617 | mmc->caps |= MMC_CAP_SD_HIGHSPEED; | ||
1568 | if (slot_data->bus_width >= 4) | 1618 | if (slot_data->bus_width >= 4) |
1569 | mmc->caps |= MMC_CAP_4_BIT_DATA; | 1619 | mmc->caps |= MMC_CAP_4_BIT_DATA; |
1570 | 1620 | ||
@@ -1753,13 +1803,13 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
1753 | ret = -ENODEV; | 1803 | ret = -ENODEV; |
1754 | if (pdata->slot[0].bus_width) { | 1804 | if (pdata->slot[0].bus_width) { |
1755 | ret = atmci_init_slot(host, &pdata->slot[0], | 1805 | ret = atmci_init_slot(host, &pdata->slot[0], |
1756 | 0, MCI_SDCSEL_SLOT_A); | 1806 | 0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA); |
1757 | if (!ret) | 1807 | if (!ret) |
1758 | nr_slots++; | 1808 | nr_slots++; |
1759 | } | 1809 | } |
1760 | if (pdata->slot[1].bus_width) { | 1810 | if (pdata->slot[1].bus_width) { |
1761 | ret = atmci_init_slot(host, &pdata->slot[1], | 1811 | ret = atmci_init_slot(host, &pdata->slot[1], |
1762 | 1, MCI_SDCSEL_SLOT_B); | 1812 | 1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB); |
1763 | if (!ret) | 1813 | if (!ret) |
1764 | nr_slots++; | 1814 | nr_slots++; |
1765 | } | 1815 | } |
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index f5834449400e..c8da5d30a861 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c | |||
@@ -1142,7 +1142,7 @@ static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state) | |||
1142 | struct au1xmmc_host *host = platform_get_drvdata(pdev); | 1142 | struct au1xmmc_host *host = platform_get_drvdata(pdev); |
1143 | int ret; | 1143 | int ret; |
1144 | 1144 | ||
1145 | ret = mmc_suspend_host(host->mmc, state); | 1145 | ret = mmc_suspend_host(host->mmc); |
1146 | if (ret) | 1146 | if (ret) |
1147 | return ret; | 1147 | return ret; |
1148 | 1148 | ||
diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index 6919e844072c..4b0e677d7295 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c | |||
@@ -576,7 +576,7 @@ static int sdh_suspend(struct platform_device *dev, pm_message_t state) | |||
576 | int ret = 0; | 576 | int ret = 0; |
577 | 577 | ||
578 | if (mmc) | 578 | if (mmc) |
579 | ret = mmc_suspend_host(mmc, state); | 579 | ret = mmc_suspend_host(mmc); |
580 | 580 | ||
581 | bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON); | 581 | bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON); |
582 | peripheral_free_list(drv_data->pin_req); | 582 | peripheral_free_list(drv_data->pin_req); |
diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index 92a324f7417c..ca3bdc831900 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c | |||
@@ -675,7 +675,7 @@ static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state) | |||
675 | struct mmc_host *mmc = cb710_slot_to_mmc(slot); | 675 | struct mmc_host *mmc = cb710_slot_to_mmc(slot); |
676 | int err; | 676 | int err; |
677 | 677 | ||
678 | err = mmc_suspend_host(mmc, state); | 678 | err = mmc_suspend_host(mmc); |
679 | if (err) | 679 | if (err) |
680 | return err; | 680 | return err; |
681 | 681 | ||
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 3bd0ba294e9d..33d9f1b00862 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c | |||
@@ -137,15 +137,15 @@ | |||
137 | 137 | ||
138 | /* | 138 | /* |
139 | * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units, | 139 | * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units, |
140 | * and we handle up to NR_SG segments. MMC_BLOCK_BOUNCE kicks in only | 140 | * and we handle up to MAX_NR_SG segments. MMC_BLOCK_BOUNCE kicks in only |
141 | * for drivers with max_hw_segs == 1, making the segments bigger (64KB) | 141 | * for drivers with max_hw_segs == 1, making the segments bigger (64KB) |
142 | * than the page or two that's otherwise typical. NR_SG == 16 gives at | 142 | * than the page or two that's otherwise typical. nr_sg (passed from |
143 | * least the same throughput boost, using EDMA transfer linkage instead | 143 | * platform data) == 16 gives at least the same throughput boost, using |
144 | * of spending CPU time copying pages. | 144 | * EDMA transfer linkage instead of spending CPU time copying pages. |
145 | */ | 145 | */ |
146 | #define MAX_CCNT ((1 << 16) - 1) | 146 | #define MAX_CCNT ((1 << 16) - 1) |
147 | 147 | ||
148 | #define NR_SG 16 | 148 | #define MAX_NR_SG 16 |
149 | 149 | ||
150 | static unsigned rw_threshold = 32; | 150 | static unsigned rw_threshold = 32; |
151 | module_param(rw_threshold, uint, S_IRUGO); | 151 | module_param(rw_threshold, uint, S_IRUGO); |
@@ -171,6 +171,7 @@ struct mmc_davinci_host { | |||
171 | #define DAVINCI_MMC_DATADIR_READ 1 | 171 | #define DAVINCI_MMC_DATADIR_READ 1 |
172 | #define DAVINCI_MMC_DATADIR_WRITE 2 | 172 | #define DAVINCI_MMC_DATADIR_WRITE 2 |
173 | unsigned char data_dir; | 173 | unsigned char data_dir; |
174 | unsigned char suspended; | ||
174 | 175 | ||
175 | /* buffer is used during PIO of one scatterlist segment, and | 176 | /* buffer is used during PIO of one scatterlist segment, and |
176 | * is updated along with buffer_bytes_left. bytes_left applies | 177 | * is updated along with buffer_bytes_left. bytes_left applies |
@@ -192,7 +193,7 @@ struct mmc_davinci_host { | |||
192 | struct edmacc_param tx_template; | 193 | struct edmacc_param tx_template; |
193 | struct edmacc_param rx_template; | 194 | struct edmacc_param rx_template; |
194 | unsigned n_link; | 195 | unsigned n_link; |
195 | u32 links[NR_SG - 1]; | 196 | u32 links[MAX_NR_SG - 1]; |
196 | 197 | ||
197 | /* For PIO we walk scatterlists one segment at a time. */ | 198 | /* For PIO we walk scatterlists one segment at a time. */ |
198 | unsigned int sg_len; | 199 | unsigned int sg_len; |
@@ -202,6 +203,8 @@ struct mmc_davinci_host { | |||
202 | u8 version; | 203 | u8 version; |
203 | /* for ns in one cycle calculation */ | 204 | /* for ns in one cycle calculation */ |
204 | unsigned ns_in_one_cycle; | 205 | unsigned ns_in_one_cycle; |
206 | /* Number of sg segments */ | ||
207 | u8 nr_sg; | ||
205 | #ifdef CONFIG_CPU_FREQ | 208 | #ifdef CONFIG_CPU_FREQ |
206 | struct notifier_block freq_transition; | 209 | struct notifier_block freq_transition; |
207 | #endif | 210 | #endif |
@@ -568,6 +571,7 @@ davinci_release_dma_channels(struct mmc_davinci_host *host) | |||
568 | 571 | ||
569 | static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host) | 572 | static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host) |
570 | { | 573 | { |
574 | u32 link_size; | ||
571 | int r, i; | 575 | int r, i; |
572 | 576 | ||
573 | /* Acquire master DMA write channel */ | 577 | /* Acquire master DMA write channel */ |
@@ -593,7 +597,8 @@ static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host) | |||
593 | /* Allocate parameter RAM slots, which will later be bound to a | 597 | /* Allocate parameter RAM slots, which will later be bound to a |
594 | * channel as needed to handle a scatterlist. | 598 | * channel as needed to handle a scatterlist. |
595 | */ | 599 | */ |
596 | for (i = 0; i < ARRAY_SIZE(host->links); i++) { | 600 | link_size = min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links)); |
601 | for (i = 0; i < link_size; i++) { | ||
597 | r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY); | 602 | r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY); |
598 | if (r < 0) { | 603 | if (r < 0) { |
599 | dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n", | 604 | dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n", |
@@ -905,19 +910,26 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host, | |||
905 | } | 910 | } |
906 | } | 911 | } |
907 | 912 | ||
908 | static void | 913 | static inline void mmc_davinci_reset_ctrl(struct mmc_davinci_host *host, |
909 | davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data) | 914 | int val) |
910 | { | 915 | { |
911 | u32 temp; | 916 | u32 temp; |
912 | 917 | ||
913 | /* reset command and data state machines */ | ||
914 | temp = readl(host->base + DAVINCI_MMCCTL); | 918 | temp = readl(host->base + DAVINCI_MMCCTL); |
915 | writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST, | 919 | if (val) /* reset */ |
916 | host->base + DAVINCI_MMCCTL); | 920 | temp |= MMCCTL_CMDRST | MMCCTL_DATRST; |
921 | else /* enable */ | ||
922 | temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST); | ||
917 | 923 | ||
918 | temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST); | ||
919 | udelay(10); | ||
920 | writel(temp, host->base + DAVINCI_MMCCTL); | 924 | writel(temp, host->base + DAVINCI_MMCCTL); |
925 | udelay(10); | ||
926 | } | ||
927 | |||
928 | static void | ||
929 | davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data) | ||
930 | { | ||
931 | mmc_davinci_reset_ctrl(host, 1); | ||
932 | mmc_davinci_reset_ctrl(host, 0); | ||
921 | } | 933 | } |
922 | 934 | ||
923 | static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) | 935 | static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) |
@@ -1121,15 +1133,8 @@ static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host) | |||
1121 | #endif | 1133 | #endif |
1122 | static void __init init_mmcsd_host(struct mmc_davinci_host *host) | 1134 | static void __init init_mmcsd_host(struct mmc_davinci_host *host) |
1123 | { | 1135 | { |
1124 | /* DAT line portion is diabled and in reset state */ | ||
1125 | writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_DATRST, | ||
1126 | host->base + DAVINCI_MMCCTL); | ||
1127 | |||
1128 | /* CMD line portion is diabled and in reset state */ | ||
1129 | writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_CMDRST, | ||
1130 | host->base + DAVINCI_MMCCTL); | ||
1131 | 1136 | ||
1132 | udelay(10); | 1137 | mmc_davinci_reset_ctrl(host, 1); |
1133 | 1138 | ||
1134 | writel(0, host->base + DAVINCI_MMCCLK); | 1139 | writel(0, host->base + DAVINCI_MMCCLK); |
1135 | writel(MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK); | 1140 | writel(MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK); |
@@ -1137,12 +1142,7 @@ static void __init init_mmcsd_host(struct mmc_davinci_host *host) | |||
1137 | writel(0x1FFF, host->base + DAVINCI_MMCTOR); | 1142 | writel(0x1FFF, host->base + DAVINCI_MMCTOR); |
1138 | writel(0xFFFF, host->base + DAVINCI_MMCTOD); | 1143 | writel(0xFFFF, host->base + DAVINCI_MMCTOD); |
1139 | 1144 | ||
1140 | writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_DATRST, | 1145 | mmc_davinci_reset_ctrl(host, 0); |
1141 | host->base + DAVINCI_MMCCTL); | ||
1142 | writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_CMDRST, | ||
1143 | host->base + DAVINCI_MMCCTL); | ||
1144 | |||
1145 | udelay(10); | ||
1146 | } | 1146 | } |
1147 | 1147 | ||
1148 | static int __init davinci_mmcsd_probe(struct platform_device *pdev) | 1148 | static int __init davinci_mmcsd_probe(struct platform_device *pdev) |
@@ -1202,6 +1202,12 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) | |||
1202 | 1202 | ||
1203 | init_mmcsd_host(host); | 1203 | init_mmcsd_host(host); |
1204 | 1204 | ||
1205 | if (pdata->nr_sg) | ||
1206 | host->nr_sg = pdata->nr_sg - 1; | ||
1207 | |||
1208 | if (host->nr_sg > MAX_NR_SG || !host->nr_sg) | ||
1209 | host->nr_sg = MAX_NR_SG; | ||
1210 | |||
1205 | host->use_dma = use_dma; | 1211 | host->use_dma = use_dma; |
1206 | host->irq = irq; | 1212 | host->irq = irq; |
1207 | 1213 | ||
@@ -1327,32 +1333,65 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) | |||
1327 | } | 1333 | } |
1328 | 1334 | ||
1329 | #ifdef CONFIG_PM | 1335 | #ifdef CONFIG_PM |
1330 | static int davinci_mmcsd_suspend(struct platform_device *pdev, pm_message_t msg) | 1336 | static int davinci_mmcsd_suspend(struct device *dev) |
1331 | { | 1337 | { |
1338 | struct platform_device *pdev = to_platform_device(dev); | ||
1332 | struct mmc_davinci_host *host = platform_get_drvdata(pdev); | 1339 | struct mmc_davinci_host *host = platform_get_drvdata(pdev); |
1340 | int ret; | ||
1333 | 1341 | ||
1334 | return mmc_suspend_host(host->mmc, msg); | 1342 | mmc_host_enable(host->mmc); |
1343 | ret = mmc_suspend_host(host->mmc); | ||
1344 | if (!ret) { | ||
1345 | writel(0, host->base + DAVINCI_MMCIM); | ||
1346 | mmc_davinci_reset_ctrl(host, 1); | ||
1347 | mmc_host_disable(host->mmc); | ||
1348 | clk_disable(host->clk); | ||
1349 | host->suspended = 1; | ||
1350 | } else { | ||
1351 | host->suspended = 0; | ||
1352 | mmc_host_disable(host->mmc); | ||
1353 | } | ||
1354 | |||
1355 | return ret; | ||
1335 | } | 1356 | } |
1336 | 1357 | ||
1337 | static int davinci_mmcsd_resume(struct platform_device *pdev) | 1358 | static int davinci_mmcsd_resume(struct device *dev) |
1338 | { | 1359 | { |
1360 | struct platform_device *pdev = to_platform_device(dev); | ||
1339 | struct mmc_davinci_host *host = platform_get_drvdata(pdev); | 1361 | struct mmc_davinci_host *host = platform_get_drvdata(pdev); |
1362 | int ret; | ||
1363 | |||
1364 | if (!host->suspended) | ||
1365 | return 0; | ||
1340 | 1366 | ||
1341 | return mmc_resume_host(host->mmc); | 1367 | clk_enable(host->clk); |
1368 | mmc_host_enable(host->mmc); | ||
1369 | |||
1370 | mmc_davinci_reset_ctrl(host, 0); | ||
1371 | ret = mmc_resume_host(host->mmc); | ||
1372 | if (!ret) | ||
1373 | host->suspended = 0; | ||
1374 | |||
1375 | return ret; | ||
1342 | } | 1376 | } |
1377 | |||
1378 | static const struct dev_pm_ops davinci_mmcsd_pm = { | ||
1379 | .suspend = davinci_mmcsd_suspend, | ||
1380 | .resume = davinci_mmcsd_resume, | ||
1381 | }; | ||
1382 | |||
1383 | #define davinci_mmcsd_pm_ops (&davinci_mmcsd_pm) | ||
1343 | #else | 1384 | #else |
1344 | #define davinci_mmcsd_suspend NULL | 1385 | #define davinci_mmcsd_pm_ops NULL |
1345 | #define davinci_mmcsd_resume NULL | ||
1346 | #endif | 1386 | #endif |
1347 | 1387 | ||
1348 | static struct platform_driver davinci_mmcsd_driver = { | 1388 | static struct platform_driver davinci_mmcsd_driver = { |
1349 | .driver = { | 1389 | .driver = { |
1350 | .name = "davinci_mmc", | 1390 | .name = "davinci_mmc", |
1351 | .owner = THIS_MODULE, | 1391 | .owner = THIS_MODULE, |
1392 | .pm = davinci_mmcsd_pm_ops, | ||
1352 | }, | 1393 | }, |
1353 | .remove = __exit_p(davinci_mmcsd_remove), | 1394 | .remove = __exit_p(davinci_mmcsd_remove), |
1354 | .suspend = davinci_mmcsd_suspend, | ||
1355 | .resume = davinci_mmcsd_resume, | ||
1356 | }; | 1395 | }; |
1357 | 1396 | ||
1358 | static int __init davinci_mmcsd_init(void) | 1397 | static int __init davinci_mmcsd_init(void) |
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index bf98d7cc928a..9a68ff4353a2 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c | |||
@@ -1115,7 +1115,7 @@ static int imxmci_suspend(struct platform_device *dev, pm_message_t state) | |||
1115 | int ret = 0; | 1115 | int ret = 0; |
1116 | 1116 | ||
1117 | if (mmc) | 1117 | if (mmc) |
1118 | ret = mmc_suspend_host(mmc, state); | 1118 | ret = mmc_suspend_host(mmc); |
1119 | 1119 | ||
1120 | return ret; | 1120 | return ret; |
1121 | } | 1121 | } |
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ff115d920888..4917af96bae1 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c | |||
@@ -824,7 +824,7 @@ static int mmci_suspend(struct amba_device *dev, pm_message_t state) | |||
824 | if (mmc) { | 824 | if (mmc) { |
825 | struct mmci_host *host = mmc_priv(mmc); | 825 | struct mmci_host *host = mmc_priv(mmc); |
826 | 826 | ||
827 | ret = mmc_suspend_host(mmc, state); | 827 | ret = mmc_suspend_host(mmc); |
828 | if (ret == 0) | 828 | if (ret == 0) |
829 | writel(0, host->base + MMCIMASK0); | 829 | writel(0, host->base + MMCIMASK0); |
830 | } | 830 | } |
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 61f1d27fed3f..24e09454e522 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c | |||
@@ -1327,7 +1327,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) | |||
1327 | disable_irq(host->stat_irq); | 1327 | disable_irq(host->stat_irq); |
1328 | 1328 | ||
1329 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) | 1329 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) |
1330 | rc = mmc_suspend_host(mmc, state); | 1330 | rc = mmc_suspend_host(mmc); |
1331 | if (!rc) | 1331 | if (!rc) |
1332 | msmsdcc_writel(host, 0, MMCIMASK0); | 1332 | msmsdcc_writel(host, 0, MMCIMASK0); |
1333 | if (host->clks_on) | 1333 | if (host->clks_on) |
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 34e23489811a..366eefa77c5a 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c | |||
@@ -865,7 +865,7 @@ static int mvsd_suspend(struct platform_device *dev, pm_message_t state) | |||
865 | int ret = 0; | 865 | int ret = 0; |
866 | 866 | ||
867 | if (mmc) | 867 | if (mmc) |
868 | ret = mmc_suspend_host(mmc, state); | 868 | ret = mmc_suspend_host(mmc); |
869 | 869 | ||
870 | return ret; | 870 | return ret; |
871 | } | 871 | } |
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 74c87e023866..fdf33e837a73 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c | |||
@@ -942,7 +942,7 @@ static int mxcmci_suspend(struct platform_device *dev, pm_message_t state) | |||
942 | int ret = 0; | 942 | int ret = 0; |
943 | 943 | ||
944 | if (mmc) | 944 | if (mmc) |
945 | ret = mmc_suspend_host(mmc, state); | 945 | ret = mmc_suspend_host(mmc); |
946 | 946 | ||
947 | return ret; | 947 | return ret; |
948 | } | 948 | } |
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 84d280406341..2b281680e320 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c | |||
@@ -39,30 +39,30 @@ | |||
39 | #include <plat/fpga.h> | 39 | #include <plat/fpga.h> |
40 | 40 | ||
41 | #define OMAP_MMC_REG_CMD 0x00 | 41 | #define OMAP_MMC_REG_CMD 0x00 |
42 | #define OMAP_MMC_REG_ARGL 0x04 | 42 | #define OMAP_MMC_REG_ARGL 0x01 |
43 | #define OMAP_MMC_REG_ARGH 0x08 | 43 | #define OMAP_MMC_REG_ARGH 0x02 |
44 | #define OMAP_MMC_REG_CON 0x0c | 44 | #define OMAP_MMC_REG_CON 0x03 |
45 | #define OMAP_MMC_REG_STAT 0x10 | 45 | #define OMAP_MMC_REG_STAT 0x04 |
46 | #define OMAP_MMC_REG_IE 0x14 | 46 | #define OMAP_MMC_REG_IE 0x05 |
47 | #define OMAP_MMC_REG_CTO 0x18 | 47 | #define OMAP_MMC_REG_CTO 0x06 |
48 | #define OMAP_MMC_REG_DTO 0x1c | 48 | #define OMAP_MMC_REG_DTO 0x07 |
49 | #define OMAP_MMC_REG_DATA 0x20 | 49 | #define OMAP_MMC_REG_DATA 0x08 |
50 | #define OMAP_MMC_REG_BLEN 0x24 | 50 | #define OMAP_MMC_REG_BLEN 0x09 |
51 | #define OMAP_MMC_REG_NBLK 0x28 | 51 | #define OMAP_MMC_REG_NBLK 0x0a |
52 | #define OMAP_MMC_REG_BUF 0x2c | 52 | #define OMAP_MMC_REG_BUF 0x0b |
53 | #define OMAP_MMC_REG_SDIO 0x34 | 53 | #define OMAP_MMC_REG_SDIO 0x0d |
54 | #define OMAP_MMC_REG_REV 0x3c | 54 | #define OMAP_MMC_REG_REV 0x0f |
55 | #define OMAP_MMC_REG_RSP0 0x40 | 55 | #define OMAP_MMC_REG_RSP0 0x10 |
56 | #define OMAP_MMC_REG_RSP1 0x44 | 56 | #define OMAP_MMC_REG_RSP1 0x11 |
57 | #define OMAP_MMC_REG_RSP2 0x48 | 57 | #define OMAP_MMC_REG_RSP2 0x12 |
58 | #define OMAP_MMC_REG_RSP3 0x4c | 58 | #define OMAP_MMC_REG_RSP3 0x13 |
59 | #define OMAP_MMC_REG_RSP4 0x50 | 59 | #define OMAP_MMC_REG_RSP4 0x14 |
60 | #define OMAP_MMC_REG_RSP5 0x54 | 60 | #define OMAP_MMC_REG_RSP5 0x15 |
61 | #define OMAP_MMC_REG_RSP6 0x58 | 61 | #define OMAP_MMC_REG_RSP6 0x16 |
62 | #define OMAP_MMC_REG_RSP7 0x5c | 62 | #define OMAP_MMC_REG_RSP7 0x17 |
63 | #define OMAP_MMC_REG_IOSR 0x60 | 63 | #define OMAP_MMC_REG_IOSR 0x18 |
64 | #define OMAP_MMC_REG_SYSC 0x64 | 64 | #define OMAP_MMC_REG_SYSC 0x19 |
65 | #define OMAP_MMC_REG_SYSS 0x68 | 65 | #define OMAP_MMC_REG_SYSS 0x1a |
66 | 66 | ||
67 | #define OMAP_MMC_STAT_CARD_ERR (1 << 14) | 67 | #define OMAP_MMC_STAT_CARD_ERR (1 << 14) |
68 | #define OMAP_MMC_STAT_CARD_IRQ (1 << 13) | 68 | #define OMAP_MMC_STAT_CARD_IRQ (1 << 13) |
@@ -78,8 +78,9 @@ | |||
78 | #define OMAP_MMC_STAT_CARD_BUSY (1 << 2) | 78 | #define OMAP_MMC_STAT_CARD_BUSY (1 << 2) |
79 | #define OMAP_MMC_STAT_END_OF_CMD (1 << 0) | 79 | #define OMAP_MMC_STAT_END_OF_CMD (1 << 0) |
80 | 80 | ||
81 | #define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG_##reg) | 81 | #define OMAP_MMC_REG(host, reg) (OMAP_MMC_REG_##reg << (host)->reg_shift) |
82 | #define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg) | 82 | #define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG(host, reg)) |
83 | #define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG(host, reg)) | ||
83 | 84 | ||
84 | /* | 85 | /* |
85 | * Command types | 86 | * Command types |
@@ -133,6 +134,7 @@ struct mmc_omap_host { | |||
133 | int irq; | 134 | int irq; |
134 | unsigned char bus_mode; | 135 | unsigned char bus_mode; |
135 | unsigned char hw_bus_mode; | 136 | unsigned char hw_bus_mode; |
137 | unsigned int reg_shift; | ||
136 | 138 | ||
137 | struct work_struct cmd_abort_work; | 139 | struct work_struct cmd_abort_work; |
138 | unsigned abort:1; | 140 | unsigned abort:1; |
@@ -680,9 +682,9 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write) | |||
680 | host->data->bytes_xfered += n; | 682 | host->data->bytes_xfered += n; |
681 | 683 | ||
682 | if (write) { | 684 | if (write) { |
683 | __raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n); | 685 | __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); |
684 | } else { | 686 | } else { |
685 | __raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n); | 687 | __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); |
686 | } | 688 | } |
687 | } | 689 | } |
688 | 690 | ||
@@ -900,7 +902,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) | |||
900 | int dst_port = 0; | 902 | int dst_port = 0; |
901 | int sync_dev = 0; | 903 | int sync_dev = 0; |
902 | 904 | ||
903 | data_addr = host->phys_base + OMAP_MMC_REG_DATA; | 905 | data_addr = host->phys_base + OMAP_MMC_REG(host, DATA); |
904 | frame = data->blksz; | 906 | frame = data->blksz; |
905 | count = sg_dma_len(sg); | 907 | count = sg_dma_len(sg); |
906 | 908 | ||
@@ -1493,6 +1495,8 @@ static int __init mmc_omap_probe(struct platform_device *pdev) | |||
1493 | } | 1495 | } |
1494 | } | 1496 | } |
1495 | 1497 | ||
1498 | host->reg_shift = (cpu_is_omap7xx() ? 1 : 2); | ||
1499 | |||
1496 | return 0; | 1500 | return 0; |
1497 | 1501 | ||
1498 | err_plat_cleanup: | 1502 | err_plat_cleanup: |
@@ -1557,7 +1561,7 @@ static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg) | |||
1557 | struct mmc_omap_slot *slot; | 1561 | struct mmc_omap_slot *slot; |
1558 | 1562 | ||
1559 | slot = host->slots[i]; | 1563 | slot = host->slots[i]; |
1560 | ret = mmc_suspend_host(slot->mmc, mesg); | 1564 | ret = mmc_suspend_host(slot->mmc); |
1561 | if (ret < 0) { | 1565 | if (ret < 0) { |
1562 | while (--i >= 0) { | 1566 | while (--i >= 0) { |
1563 | slot = host->slots[i]; | 1567 | slot = host->slots[i]; |
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e9caf694c59e..b032828c6126 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -157,12 +157,10 @@ struct omap_hsmmc_host { | |||
157 | */ | 157 | */ |
158 | struct regulator *vcc; | 158 | struct regulator *vcc; |
159 | struct regulator *vcc_aux; | 159 | struct regulator *vcc_aux; |
160 | struct semaphore sem; | ||
161 | struct work_struct mmc_carddetect_work; | 160 | struct work_struct mmc_carddetect_work; |
162 | void __iomem *base; | 161 | void __iomem *base; |
163 | resource_size_t mapbase; | 162 | resource_size_t mapbase; |
164 | spinlock_t irq_lock; /* Prevent races with irq handler */ | 163 | spinlock_t irq_lock; /* Prevent races with irq handler */ |
165 | unsigned long flags; | ||
166 | unsigned int id; | 164 | unsigned int id; |
167 | unsigned int dma_len; | 165 | unsigned int dma_len; |
168 | unsigned int dma_sg_idx; | 166 | unsigned int dma_sg_idx; |
@@ -183,6 +181,7 @@ struct omap_hsmmc_host { | |||
183 | int protect_card; | 181 | int protect_card; |
184 | int reqs_blocked; | 182 | int reqs_blocked; |
185 | int use_reg; | 183 | int use_reg; |
184 | int req_in_progress; | ||
186 | 185 | ||
187 | struct omap_mmc_platform_data *pdata; | 186 | struct omap_mmc_platform_data *pdata; |
188 | }; | 187 | }; |
@@ -524,6 +523,27 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host) | |||
524 | dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n"); | 523 | dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n"); |
525 | } | 524 | } |
526 | 525 | ||
526 | static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host) | ||
527 | { | ||
528 | unsigned int irq_mask; | ||
529 | |||
530 | if (host->use_dma) | ||
531 | irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE); | ||
532 | else | ||
533 | irq_mask = INT_EN_MASK; | ||
534 | |||
535 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | ||
536 | OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); | ||
537 | OMAP_HSMMC_WRITE(host->base, IE, irq_mask); | ||
538 | } | ||
539 | |||
540 | static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) | ||
541 | { | ||
542 | OMAP_HSMMC_WRITE(host->base, ISE, 0); | ||
543 | OMAP_HSMMC_WRITE(host->base, IE, 0); | ||
544 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | ||
545 | } | ||
546 | |||
527 | #ifdef CONFIG_PM | 547 | #ifdef CONFIG_PM |
528 | 548 | ||
529 | /* | 549 | /* |
@@ -592,9 +612,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) | |||
592 | && time_before(jiffies, timeout)) | 612 | && time_before(jiffies, timeout)) |
593 | ; | 613 | ; |
594 | 614 | ||
595 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | 615 | omap_hsmmc_disable_irq(host); |
596 | OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); | ||
597 | OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); | ||
598 | 616 | ||
599 | /* Do not initialize card-specific things if the power is off */ | 617 | /* Do not initialize card-specific things if the power is off */ |
600 | if (host->power_mode == MMC_POWER_OFF) | 618 | if (host->power_mode == MMC_POWER_OFF) |
@@ -697,6 +715,8 @@ static void send_init_stream(struct omap_hsmmc_host *host) | |||
697 | return; | 715 | return; |
698 | 716 | ||
699 | disable_irq(host->irq); | 717 | disable_irq(host->irq); |
718 | |||
719 | OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); | ||
700 | OMAP_HSMMC_WRITE(host->base, CON, | 720 | OMAP_HSMMC_WRITE(host->base, CON, |
701 | OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM); | 721 | OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM); |
702 | OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD); | 722 | OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD); |
@@ -762,17 +782,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, | |||
762 | mmc_hostname(host->mmc), cmd->opcode, cmd->arg); | 782 | mmc_hostname(host->mmc), cmd->opcode, cmd->arg); |
763 | host->cmd = cmd; | 783 | host->cmd = cmd; |
764 | 784 | ||
765 | /* | 785 | omap_hsmmc_enable_irq(host); |
766 | * Clear status bits and enable interrupts | ||
767 | */ | ||
768 | OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); | ||
769 | OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); | ||
770 | |||
771 | if (host->use_dma) | ||
772 | OMAP_HSMMC_WRITE(host->base, IE, | ||
773 | INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE)); | ||
774 | else | ||
775 | OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); | ||
776 | 786 | ||
777 | host->response_busy = 0; | 787 | host->response_busy = 0; |
778 | if (cmd->flags & MMC_RSP_PRESENT) { | 788 | if (cmd->flags & MMC_RSP_PRESENT) { |
@@ -806,13 +816,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, | |||
806 | if (host->use_dma) | 816 | if (host->use_dma) |
807 | cmdreg |= DMA_EN; | 817 | cmdreg |= DMA_EN; |
808 | 818 | ||
809 | /* | 819 | host->req_in_progress = 1; |
810 | * In an interrupt context (i.e. STOP command), the spinlock is unlocked | ||
811 | * by the interrupt handler, otherwise (i.e. for a new request) it is | ||
812 | * unlocked here. | ||
813 | */ | ||
814 | if (!in_interrupt()) | ||
815 | spin_unlock_irqrestore(&host->irq_lock, host->flags); | ||
816 | 820 | ||
817 | OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg); | 821 | OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg); |
818 | OMAP_HSMMC_WRITE(host->base, CMD, cmdreg); | 822 | OMAP_HSMMC_WRITE(host->base, CMD, cmdreg); |
@@ -827,6 +831,23 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data) | |||
827 | return DMA_FROM_DEVICE; | 831 | return DMA_FROM_DEVICE; |
828 | } | 832 | } |
829 | 833 | ||
834 | static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) | ||
835 | { | ||
836 | int dma_ch; | ||
837 | |||
838 | spin_lock(&host->irq_lock); | ||
839 | host->req_in_progress = 0; | ||
840 | dma_ch = host->dma_ch; | ||
841 | spin_unlock(&host->irq_lock); | ||
842 | |||
843 | omap_hsmmc_disable_irq(host); | ||
844 | /* Do not complete the request if DMA is still in progress */ | ||
845 | if (mrq->data && host->use_dma && dma_ch != -1) | ||
846 | return; | ||
847 | host->mrq = NULL; | ||
848 | mmc_request_done(host->mmc, mrq); | ||
849 | } | ||
850 | |||
830 | /* | 851 | /* |
831 | * Notify the transfer complete to MMC core | 852 | * Notify the transfer complete to MMC core |
832 | */ | 853 | */ |
@@ -843,25 +864,19 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data) | |||
843 | return; | 864 | return; |
844 | } | 865 | } |
845 | 866 | ||
846 | host->mrq = NULL; | 867 | omap_hsmmc_request_done(host, mrq); |
847 | mmc_request_done(host->mmc, mrq); | ||
848 | return; | 868 | return; |
849 | } | 869 | } |
850 | 870 | ||
851 | host->data = NULL; | 871 | host->data = NULL; |
852 | 872 | ||
853 | if (host->use_dma && host->dma_ch != -1) | ||
854 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, | ||
855 | omap_hsmmc_get_dma_dir(host, data)); | ||
856 | |||
857 | if (!data->error) | 873 | if (!data->error) |
858 | data->bytes_xfered += data->blocks * (data->blksz); | 874 | data->bytes_xfered += data->blocks * (data->blksz); |
859 | else | 875 | else |
860 | data->bytes_xfered = 0; | 876 | data->bytes_xfered = 0; |
861 | 877 | ||
862 | if (!data->stop) { | 878 | if (!data->stop) { |
863 | host->mrq = NULL; | 879 | omap_hsmmc_request_done(host, data->mrq); |
864 | mmc_request_done(host->mmc, data->mrq); | ||
865 | return; | 880 | return; |
866 | } | 881 | } |
867 | omap_hsmmc_start_command(host, data->stop, NULL); | 882 | omap_hsmmc_start_command(host, data->stop, NULL); |
@@ -887,10 +902,8 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) | |||
887 | cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10); | 902 | cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10); |
888 | } | 903 | } |
889 | } | 904 | } |
890 | if ((host->data == NULL && !host->response_busy) || cmd->error) { | 905 | if ((host->data == NULL && !host->response_busy) || cmd->error) |
891 | host->mrq = NULL; | 906 | omap_hsmmc_request_done(host, cmd->mrq); |
892 | mmc_request_done(host->mmc, cmd->mrq); | ||
893 | } | ||
894 | } | 907 | } |
895 | 908 | ||
896 | /* | 909 | /* |
@@ -898,14 +911,19 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) | |||
898 | */ | 911 | */ |
899 | static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) | 912 | static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) |
900 | { | 913 | { |
914 | int dma_ch; | ||
915 | |||
901 | host->data->error = errno; | 916 | host->data->error = errno; |
902 | 917 | ||
903 | if (host->use_dma && host->dma_ch != -1) { | 918 | spin_lock(&host->irq_lock); |
919 | dma_ch = host->dma_ch; | ||
920 | host->dma_ch = -1; | ||
921 | spin_unlock(&host->irq_lock); | ||
922 | |||
923 | if (host->use_dma && dma_ch != -1) { | ||
904 | dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len, | 924 | dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len, |
905 | omap_hsmmc_get_dma_dir(host, host->data)); | 925 | omap_hsmmc_get_dma_dir(host, host->data)); |
906 | omap_free_dma(host->dma_ch); | 926 | omap_free_dma(dma_ch); |
907 | host->dma_ch = -1; | ||
908 | up(&host->sem); | ||
909 | } | 927 | } |
910 | host->data = NULL; | 928 | host->data = NULL; |
911 | } | 929 | } |
@@ -967,28 +985,21 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, | |||
967 | __func__); | 985 | __func__); |
968 | } | 986 | } |
969 | 987 | ||
970 | /* | 988 | static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) |
971 | * MMC controller IRQ handler | ||
972 | */ | ||
973 | static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) | ||
974 | { | 989 | { |
975 | struct omap_hsmmc_host *host = dev_id; | ||
976 | struct mmc_data *data; | 990 | struct mmc_data *data; |
977 | int end_cmd = 0, end_trans = 0, status; | 991 | int end_cmd = 0, end_trans = 0; |
978 | 992 | ||
979 | spin_lock(&host->irq_lock); | 993 | if (!host->req_in_progress) { |
980 | 994 | do { | |
981 | if (host->mrq == NULL) { | 995 | OMAP_HSMMC_WRITE(host->base, STAT, status); |
982 | OMAP_HSMMC_WRITE(host->base, STAT, | 996 | /* Flush posted write */ |
983 | OMAP_HSMMC_READ(host->base, STAT)); | 997 | status = OMAP_HSMMC_READ(host->base, STAT); |
984 | /* Flush posted write */ | 998 | } while (status & INT_EN_MASK); |
985 | OMAP_HSMMC_READ(host->base, STAT); | 999 | return; |
986 | spin_unlock(&host->irq_lock); | ||
987 | return IRQ_HANDLED; | ||
988 | } | 1000 | } |
989 | 1001 | ||
990 | data = host->data; | 1002 | data = host->data; |
991 | status = OMAP_HSMMC_READ(host->base, STAT); | ||
992 | dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); | 1003 | dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); |
993 | 1004 | ||
994 | if (status & ERR) { | 1005 | if (status & ERR) { |
@@ -1041,15 +1052,27 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) | |||
1041 | } | 1052 | } |
1042 | 1053 | ||
1043 | OMAP_HSMMC_WRITE(host->base, STAT, status); | 1054 | OMAP_HSMMC_WRITE(host->base, STAT, status); |
1044 | /* Flush posted write */ | ||
1045 | OMAP_HSMMC_READ(host->base, STAT); | ||
1046 | 1055 | ||
1047 | if (end_cmd || ((status & CC) && host->cmd)) | 1056 | if (end_cmd || ((status & CC) && host->cmd)) |
1048 | omap_hsmmc_cmd_done(host, host->cmd); | 1057 | omap_hsmmc_cmd_done(host, host->cmd); |
1049 | if ((end_trans || (status & TC)) && host->mrq) | 1058 | if ((end_trans || (status & TC)) && host->mrq) |
1050 | omap_hsmmc_xfer_done(host, data); | 1059 | omap_hsmmc_xfer_done(host, data); |
1060 | } | ||
1051 | 1061 | ||
1052 | spin_unlock(&host->irq_lock); | 1062 | /* |
1063 | * MMC controller IRQ handler | ||
1064 | */ | ||
1065 | static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) | ||
1066 | { | ||
1067 | struct omap_hsmmc_host *host = dev_id; | ||
1068 | int status; | ||
1069 | |||
1070 | status = OMAP_HSMMC_READ(host->base, STAT); | ||
1071 | do { | ||
1072 | omap_hsmmc_do_irq(host, status); | ||
1073 | /* Flush posted write */ | ||
1074 | status = OMAP_HSMMC_READ(host->base, STAT); | ||
1075 | } while (status & INT_EN_MASK); | ||
1053 | 1076 | ||
1054 | return IRQ_HANDLED; | 1077 | return IRQ_HANDLED; |
1055 | } | 1078 | } |
@@ -1244,31 +1267,47 @@ static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host, | |||
1244 | /* | 1267 | /* |
1245 | * DMA call back function | 1268 | * DMA call back function |
1246 | */ | 1269 | */ |
1247 | static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data) | 1270 | static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) |
1248 | { | 1271 | { |
1249 | struct omap_hsmmc_host *host = data; | 1272 | struct omap_hsmmc_host *host = cb_data; |
1273 | struct mmc_data *data = host->mrq->data; | ||
1274 | int dma_ch, req_in_progress; | ||
1250 | 1275 | ||
1251 | if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ) | 1276 | if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ) |
1252 | dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n"); | 1277 | dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n"); |
1253 | 1278 | ||
1254 | if (host->dma_ch < 0) | 1279 | spin_lock(&host->irq_lock); |
1280 | if (host->dma_ch < 0) { | ||
1281 | spin_unlock(&host->irq_lock); | ||
1255 | return; | 1282 | return; |
1283 | } | ||
1256 | 1284 | ||
1257 | host->dma_sg_idx++; | 1285 | host->dma_sg_idx++; |
1258 | if (host->dma_sg_idx < host->dma_len) { | 1286 | if (host->dma_sg_idx < host->dma_len) { |
1259 | /* Fire up the next transfer. */ | 1287 | /* Fire up the next transfer. */ |
1260 | omap_hsmmc_config_dma_params(host, host->data, | 1288 | omap_hsmmc_config_dma_params(host, data, |
1261 | host->data->sg + host->dma_sg_idx); | 1289 | data->sg + host->dma_sg_idx); |
1290 | spin_unlock(&host->irq_lock); | ||
1262 | return; | 1291 | return; |
1263 | } | 1292 | } |
1264 | 1293 | ||
1265 | omap_free_dma(host->dma_ch); | 1294 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, |
1295 | omap_hsmmc_get_dma_dir(host, data)); | ||
1296 | |||
1297 | req_in_progress = host->req_in_progress; | ||
1298 | dma_ch = host->dma_ch; | ||
1266 | host->dma_ch = -1; | 1299 | host->dma_ch = -1; |
1267 | /* | 1300 | spin_unlock(&host->irq_lock); |
1268 | * DMA Callback: run in interrupt context. | 1301 | |
1269 | * mutex_unlock will throw a kernel warning if used. | 1302 | omap_free_dma(dma_ch); |
1270 | */ | 1303 | |
1271 | up(&host->sem); | 1304 | /* If DMA has finished after TC, complete the request */ |
1305 | if (!req_in_progress) { | ||
1306 | struct mmc_request *mrq = host->mrq; | ||
1307 | |||
1308 | host->mrq = NULL; | ||
1309 | mmc_request_done(host->mmc, mrq); | ||
1310 | } | ||
1272 | } | 1311 | } |
1273 | 1312 | ||
1274 | /* | 1313 | /* |
@@ -1277,7 +1316,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data) | |||
1277 | static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, | 1316 | static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, |
1278 | struct mmc_request *req) | 1317 | struct mmc_request *req) |
1279 | { | 1318 | { |
1280 | int dma_ch = 0, ret = 0, err = 1, i; | 1319 | int dma_ch = 0, ret = 0, i; |
1281 | struct mmc_data *data = req->data; | 1320 | struct mmc_data *data = req->data; |
1282 | 1321 | ||
1283 | /* Sanity check: all the SG entries must be aligned by block size. */ | 1322 | /* Sanity check: all the SG entries must be aligned by block size. */ |
@@ -1294,23 +1333,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, | |||
1294 | */ | 1333 | */ |
1295 | return -EINVAL; | 1334 | return -EINVAL; |
1296 | 1335 | ||
1297 | /* | 1336 | BUG_ON(host->dma_ch != -1); |
1298 | * If for some reason the DMA transfer is still active, | ||
1299 | * we wait for timeout period and free the dma | ||
1300 | */ | ||
1301 | if (host->dma_ch != -1) { | ||
1302 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
1303 | schedule_timeout(100); | ||
1304 | if (down_trylock(&host->sem)) { | ||
1305 | omap_free_dma(host->dma_ch); | ||
1306 | host->dma_ch = -1; | ||
1307 | up(&host->sem); | ||
1308 | return err; | ||
1309 | } | ||
1310 | } else { | ||
1311 | if (down_trylock(&host->sem)) | ||
1312 | return err; | ||
1313 | } | ||
1314 | 1337 | ||
1315 | ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data), | 1338 | ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data), |
1316 | "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch); | 1339 | "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch); |
@@ -1410,37 +1433,27 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) | |||
1410 | struct omap_hsmmc_host *host = mmc_priv(mmc); | 1433 | struct omap_hsmmc_host *host = mmc_priv(mmc); |
1411 | int err; | 1434 | int err; |
1412 | 1435 | ||
1413 | /* | 1436 | BUG_ON(host->req_in_progress); |
1414 | * Prevent races with the interrupt handler because of unexpected | 1437 | BUG_ON(host->dma_ch != -1); |
1415 | * interrupts, but not if we are already in interrupt context i.e. | 1438 | if (host->protect_card) { |
1416 | * retries. | 1439 | if (host->reqs_blocked < 3) { |
1417 | */ | 1440 | /* |
1418 | if (!in_interrupt()) { | 1441 | * Ensure the controller is left in a consistent |
1419 | spin_lock_irqsave(&host->irq_lock, host->flags); | 1442 | * state by resetting the command and data state |
1420 | /* | 1443 | * machines. |
1421 | * Protect the card from I/O if there is a possibility | 1444 | */ |
1422 | * it can be removed. | 1445 | omap_hsmmc_reset_controller_fsm(host, SRD); |
1423 | */ | 1446 | omap_hsmmc_reset_controller_fsm(host, SRC); |
1424 | if (host->protect_card) { | 1447 | host->reqs_blocked += 1; |
1425 | if (host->reqs_blocked < 3) { | 1448 | } |
1426 | /* | 1449 | req->cmd->error = -EBADF; |
1427 | * Ensure the controller is left in a consistent | 1450 | if (req->data) |
1428 | * state by resetting the command and data state | 1451 | req->data->error = -EBADF; |
1429 | * machines. | 1452 | req->cmd->retries = 0; |
1430 | */ | 1453 | mmc_request_done(mmc, req); |
1431 | omap_hsmmc_reset_controller_fsm(host, SRD); | 1454 | return; |
1432 | omap_hsmmc_reset_controller_fsm(host, SRC); | 1455 | } else if (host->reqs_blocked) |
1433 | host->reqs_blocked += 1; | 1456 | host->reqs_blocked = 0; |
1434 | } | ||
1435 | req->cmd->error = -EBADF; | ||
1436 | if (req->data) | ||
1437 | req->data->error = -EBADF; | ||
1438 | spin_unlock_irqrestore(&host->irq_lock, host->flags); | ||
1439 | mmc_request_done(mmc, req); | ||
1440 | return; | ||
1441 | } else if (host->reqs_blocked) | ||
1442 | host->reqs_blocked = 0; | ||
1443 | } | ||
1444 | WARN_ON(host->mrq != NULL); | 1457 | WARN_ON(host->mrq != NULL); |
1445 | host->mrq = req; | 1458 | host->mrq = req; |
1446 | err = omap_hsmmc_prepare_data(host, req); | 1459 | err = omap_hsmmc_prepare_data(host, req); |
@@ -1449,8 +1462,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) | |||
1449 | if (req->data) | 1462 | if (req->data) |
1450 | req->data->error = err; | 1463 | req->data->error = err; |
1451 | host->mrq = NULL; | 1464 | host->mrq = NULL; |
1452 | if (!in_interrupt()) | ||
1453 | spin_unlock_irqrestore(&host->irq_lock, host->flags); | ||
1454 | mmc_request_done(mmc, req); | 1465 | mmc_request_done(mmc, req); |
1455 | return; | 1466 | return; |
1456 | } | 1467 | } |
@@ -2019,7 +2030,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
2019 | mmc->f_min = 400000; | 2030 | mmc->f_min = 400000; |
2020 | mmc->f_max = 52000000; | 2031 | mmc->f_max = 52000000; |
2021 | 2032 | ||
2022 | sema_init(&host->sem, 1); | ||
2023 | spin_lock_init(&host->irq_lock); | 2033 | spin_lock_init(&host->irq_lock); |
2024 | 2034 | ||
2025 | host->iclk = clk_get(&pdev->dev, "ick"); | 2035 | host->iclk = clk_get(&pdev->dev, "ick"); |
@@ -2162,8 +2172,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
2162 | } | 2172 | } |
2163 | } | 2173 | } |
2164 | 2174 | ||
2165 | OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); | 2175 | omap_hsmmc_disable_irq(host); |
2166 | OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); | ||
2167 | 2176 | ||
2168 | mmc_host_lazy_disable(host->mmc); | 2177 | mmc_host_lazy_disable(host->mmc); |
2169 | 2178 | ||
@@ -2258,10 +2267,12 @@ static int omap_hsmmc_remove(struct platform_device *pdev) | |||
2258 | } | 2267 | } |
2259 | 2268 | ||
2260 | #ifdef CONFIG_PM | 2269 | #ifdef CONFIG_PM |
2261 | static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state) | 2270 | static int omap_hsmmc_suspend(struct device *dev) |
2262 | { | 2271 | { |
2263 | int ret = 0; | 2272 | int ret = 0; |
2273 | struct platform_device *pdev = to_platform_device(dev); | ||
2264 | struct omap_hsmmc_host *host = platform_get_drvdata(pdev); | 2274 | struct omap_hsmmc_host *host = platform_get_drvdata(pdev); |
2275 | pm_message_t state = PMSG_SUSPEND; /* unused by MMC core */ | ||
2265 | 2276 | ||
2266 | if (host && host->suspended) | 2277 | if (host && host->suspended) |
2267 | return 0; | 2278 | return 0; |
@@ -2281,12 +2292,9 @@ static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state) | |||
2281 | } | 2292 | } |
2282 | cancel_work_sync(&host->mmc_carddetect_work); | 2293 | cancel_work_sync(&host->mmc_carddetect_work); |
2283 | mmc_host_enable(host->mmc); | 2294 | mmc_host_enable(host->mmc); |
2284 | ret = mmc_suspend_host(host->mmc, state); | 2295 | ret = mmc_suspend_host(host->mmc); |
2285 | if (ret == 0) { | 2296 | if (ret == 0) { |
2286 | OMAP_HSMMC_WRITE(host->base, ISE, 0); | 2297 | omap_hsmmc_disable_irq(host); |
2287 | OMAP_HSMMC_WRITE(host->base, IE, 0); | ||
2288 | |||
2289 | |||
2290 | OMAP_HSMMC_WRITE(host->base, HCTL, | 2298 | OMAP_HSMMC_WRITE(host->base, HCTL, |
2291 | OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); | 2299 | OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); |
2292 | mmc_host_disable(host->mmc); | 2300 | mmc_host_disable(host->mmc); |
@@ -2310,9 +2318,10 @@ static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state) | |||
2310 | } | 2318 | } |
2311 | 2319 | ||
2312 | /* Routine to resume the MMC device */ | 2320 | /* Routine to resume the MMC device */ |
2313 | static int omap_hsmmc_resume(struct platform_device *pdev) | 2321 | static int omap_hsmmc_resume(struct device *dev) |
2314 | { | 2322 | { |
2315 | int ret = 0; | 2323 | int ret = 0; |
2324 | struct platform_device *pdev = to_platform_device(dev); | ||
2316 | struct omap_hsmmc_host *host = platform_get_drvdata(pdev); | 2325 | struct omap_hsmmc_host *host = platform_get_drvdata(pdev); |
2317 | 2326 | ||
2318 | if (host && !host->suspended) | 2327 | if (host && !host->suspended) |
@@ -2363,13 +2372,17 @@ clk_en_err: | |||
2363 | #define omap_hsmmc_resume NULL | 2372 | #define omap_hsmmc_resume NULL |
2364 | #endif | 2373 | #endif |
2365 | 2374 | ||
2366 | static struct platform_driver omap_hsmmc_driver = { | 2375 | static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { |
2367 | .remove = omap_hsmmc_remove, | ||
2368 | .suspend = omap_hsmmc_suspend, | 2376 | .suspend = omap_hsmmc_suspend, |
2369 | .resume = omap_hsmmc_resume, | 2377 | .resume = omap_hsmmc_resume, |
2378 | }; | ||
2379 | |||
2380 | static struct platform_driver omap_hsmmc_driver = { | ||
2381 | .remove = omap_hsmmc_remove, | ||
2370 | .driver = { | 2382 | .driver = { |
2371 | .name = DRIVER_NAME, | 2383 | .name = DRIVER_NAME, |
2372 | .owner = THIS_MODULE, | 2384 | .owner = THIS_MODULE, |
2385 | .pm = &omap_hsmmc_dev_pm_ops, | ||
2373 | }, | 2386 | }, |
2374 | }; | 2387 | }; |
2375 | 2388 | ||
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index e4f00e70a749..0a4e43f37140 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c | |||
@@ -813,7 +813,7 @@ static int pxamci_suspend(struct device *dev) | |||
813 | int ret = 0; | 813 | int ret = 0; |
814 | 814 | ||
815 | if (mmc) | 815 | if (mmc) |
816 | ret = mmc_suspend_host(mmc, PMSG_SUSPEND); | 816 | ret = mmc_suspend_host(mmc); |
817 | 817 | ||
818 | return ret; | 818 | return ret; |
819 | } | 819 | } |
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 2fdf7689ae6c..2e16e0a90a5e 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c | |||
@@ -1881,9 +1881,8 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); | |||
1881 | static int s3cmci_suspend(struct device *dev) | 1881 | static int s3cmci_suspend(struct device *dev) |
1882 | { | 1882 | { |
1883 | struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); | 1883 | struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); |
1884 | struct pm_message event = { PM_EVENT_SUSPEND }; | ||
1885 | 1884 | ||
1886 | return mmc_suspend_host(mmc, event); | 1885 | return mmc_suspend_host(mmc); |
1887 | } | 1886 | } |
1888 | 1887 | ||
1889 | static int s3cmci_resume(struct device *dev) | 1888 | static int s3cmci_resume(struct device *dev) |
diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c index 7802a543d8fc..a2e9820cd42f 100644 --- a/drivers/mmc/host/sdhci-of-core.c +++ b/drivers/mmc/host/sdhci-of-core.c | |||
@@ -89,7 +89,7 @@ static int sdhci_of_suspend(struct of_device *ofdev, pm_message_t state) | |||
89 | { | 89 | { |
90 | struct sdhci_host *host = dev_get_drvdata(&ofdev->dev); | 90 | struct sdhci_host *host = dev_get_drvdata(&ofdev->dev); |
91 | 91 | ||
92 | return mmc_suspend_host(host->mmc, state); | 92 | return mmc_suspend_host(host->mmc); |
93 | } | 93 | } |
94 | 94 | ||
95 | static int sdhci_of_resume(struct of_device *ofdev) | 95 | static int sdhci_of_resume(struct of_device *ofdev) |
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index d5b11a17e648..c8623de13af3 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c | |||
@@ -129,12 +129,12 @@ struct sdhci_of_data sdhci_esdhc = { | |||
129 | SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | | 129 | SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | |
130 | SDHCI_QUIRK_NO_CARD_NO_RESET, | 130 | SDHCI_QUIRK_NO_CARD_NO_RESET, |
131 | .ops = { | 131 | .ops = { |
132 | .readl = sdhci_be32bs_readl, | 132 | .read_l = sdhci_be32bs_readl, |
133 | .readw = esdhc_readw, | 133 | .read_w = esdhc_readw, |
134 | .readb = sdhci_be32bs_readb, | 134 | .read_b = sdhci_be32bs_readb, |
135 | .writel = sdhci_be32bs_writel, | 135 | .write_l = sdhci_be32bs_writel, |
136 | .writew = esdhc_writew, | 136 | .write_w = esdhc_writew, |
137 | .writeb = esdhc_writeb, | 137 | .write_b = esdhc_writeb, |
138 | .set_clock = esdhc_set_clock, | 138 | .set_clock = esdhc_set_clock, |
139 | .enable_dma = esdhc_enable_dma, | 139 | .enable_dma = esdhc_enable_dma, |
140 | .get_max_clock = esdhc_get_max_clock, | 140 | .get_max_clock = esdhc_get_max_clock, |
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 35117f3ed757..68ddb7546ae2 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c | |||
@@ -55,11 +55,11 @@ struct sdhci_of_data sdhci_hlwd = { | |||
55 | .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | | 55 | .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | |
56 | SDHCI_QUIRK_32BIT_DMA_SIZE, | 56 | SDHCI_QUIRK_32BIT_DMA_SIZE, |
57 | .ops = { | 57 | .ops = { |
58 | .readl = sdhci_be32bs_readl, | 58 | .read_l = sdhci_be32bs_readl, |
59 | .readw = sdhci_be32bs_readw, | 59 | .read_w = sdhci_be32bs_readw, |
60 | .readb = sdhci_be32bs_readb, | 60 | .read_b = sdhci_be32bs_readb, |
61 | .writel = sdhci_hlwd_writel, | 61 | .write_l = sdhci_hlwd_writel, |
62 | .writew = sdhci_hlwd_writew, | 62 | .write_w = sdhci_hlwd_writew, |
63 | .writeb = sdhci_hlwd_writeb, | 63 | .write_b = sdhci_hlwd_writeb, |
64 | }, | 64 | }, |
65 | }; | 65 | }; |
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 6701af629c30..65483fdea45b 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c | |||
@@ -628,7 +628,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( | |||
628 | host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot)); | 628 | host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot)); |
629 | if (IS_ERR(host)) { | 629 | if (IS_ERR(host)) { |
630 | dev_err(&pdev->dev, "cannot allocate host\n"); | 630 | dev_err(&pdev->dev, "cannot allocate host\n"); |
631 | return ERR_PTR(PTR_ERR(host)); | 631 | return ERR_CAST(host); |
632 | } | 632 | } |
633 | 633 | ||
634 | slot = sdhci_priv(host); | 634 | slot = sdhci_priv(host); |
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 297f40ae6ad5..b6ee0d719698 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/mmc/host.h> | 29 | #include <linux/mmc/host.h> |
30 | 30 | ||
31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/sdhci-pltfm.h> | ||
32 | 33 | ||
33 | #include "sdhci.h" | 34 | #include "sdhci.h" |
34 | 35 | ||
@@ -49,19 +50,18 @@ static struct sdhci_ops sdhci_pltfm_ops = { | |||
49 | 50 | ||
50 | static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) | 51 | static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) |
51 | { | 52 | { |
53 | struct sdhci_pltfm_data *pdata = pdev->dev.platform_data; | ||
52 | struct sdhci_host *host; | 54 | struct sdhci_host *host; |
53 | struct resource *iomem; | 55 | struct resource *iomem; |
54 | int ret; | 56 | int ret; |
55 | 57 | ||
56 | BUG_ON(pdev == NULL); | ||
57 | |||
58 | iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 58 | iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
59 | if (!iomem) { | 59 | if (!iomem) { |
60 | ret = -ENOMEM; | 60 | ret = -ENOMEM; |
61 | goto err; | 61 | goto err; |
62 | } | 62 | } |
63 | 63 | ||
64 | if (resource_size(iomem) != 0x100) | 64 | if (resource_size(iomem) < 0x100) |
65 | dev_err(&pdev->dev, "Invalid iomem size. You may " | 65 | dev_err(&pdev->dev, "Invalid iomem size. You may " |
66 | "experience problems.\n"); | 66 | "experience problems.\n"); |
67 | 67 | ||
@@ -76,7 +76,12 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) | |||
76 | } | 76 | } |
77 | 77 | ||
78 | host->hw_name = "platform"; | 78 | host->hw_name = "platform"; |
79 | host->ops = &sdhci_pltfm_ops; | 79 | if (pdata && pdata->ops) |
80 | host->ops = pdata->ops; | ||
81 | else | ||
82 | host->ops = &sdhci_pltfm_ops; | ||
83 | if (pdata) | ||
84 | host->quirks = pdata->quirks; | ||
80 | host->irq = platform_get_irq(pdev, 0); | 85 | host->irq = platform_get_irq(pdev, 0); |
81 | 86 | ||
82 | if (!request_mem_region(iomem->start, resource_size(iomem), | 87 | if (!request_mem_region(iomem->start, resource_size(iomem), |
@@ -93,6 +98,12 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) | |||
93 | goto err_remap; | 98 | goto err_remap; |
94 | } | 99 | } |
95 | 100 | ||
101 | if (pdata && pdata->init) { | ||
102 | ret = pdata->init(host); | ||
103 | if (ret) | ||
104 | goto err_plat_init; | ||
105 | } | ||
106 | |||
96 | ret = sdhci_add_host(host); | 107 | ret = sdhci_add_host(host); |
97 | if (ret) | 108 | if (ret) |
98 | goto err_add_host; | 109 | goto err_add_host; |
@@ -102,6 +113,9 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) | |||
102 | return 0; | 113 | return 0; |
103 | 114 | ||
104 | err_add_host: | 115 | err_add_host: |
116 | if (pdata && pdata->exit) | ||
117 | pdata->exit(host); | ||
118 | err_plat_init: | ||
105 | iounmap(host->ioaddr); | 119 | iounmap(host->ioaddr); |
106 | err_remap: | 120 | err_remap: |
107 | release_mem_region(iomem->start, resource_size(iomem)); | 121 | release_mem_region(iomem->start, resource_size(iomem)); |
@@ -114,6 +128,7 @@ err: | |||
114 | 128 | ||
115 | static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) | 129 | static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) |
116 | { | 130 | { |
131 | struct sdhci_pltfm_data *pdata = pdev->dev.platform_data; | ||
117 | struct sdhci_host *host = platform_get_drvdata(pdev); | 132 | struct sdhci_host *host = platform_get_drvdata(pdev); |
118 | struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 133 | struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
119 | int dead; | 134 | int dead; |
@@ -125,6 +140,8 @@ static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) | |||
125 | dead = 1; | 140 | dead = 1; |
126 | 141 | ||
127 | sdhci_remove_host(host, dead); | 142 | sdhci_remove_host(host, dead); |
143 | if (pdata && pdata->exit) | ||
144 | pdata->exit(host); | ||
128 | iounmap(host->ioaddr); | 145 | iounmap(host->ioaddr); |
129 | release_mem_region(iomem->start, resource_size(iomem)); | 146 | release_mem_region(iomem->start, resource_size(iomem)); |
130 | sdhci_free_host(host); | 147 | sdhci_free_host(host); |
@@ -165,4 +182,3 @@ MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver"); | |||
165 | MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); | 182 | MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); |
166 | MODULE_LICENSE("GPL v2"); | 183 | MODULE_LICENSE("GPL v2"); |
167 | MODULE_ALIAS("platform:sdhci"); | 184 | MODULE_ALIAS("platform:sdhci"); |
168 | |||
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 2136794c0cfa..af217924a76e 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c | |||
@@ -317,12 +317,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
317 | host->irq = irq; | 317 | host->irq = irq; |
318 | 318 | ||
319 | /* Setup quirks for the controller */ | 319 | /* Setup quirks for the controller */ |
320 | 320 | host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; | |
321 | /* Currently with ADMA enabled we are getting some length | ||
322 | * interrupts that are not being dealt with, do disable | ||
323 | * ADMA until this is sorted out. */ | ||
324 | host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; | ||
325 | host->quirks |= SDHCI_QUIRK_32BIT_ADMA_SIZE; | ||
326 | 321 | ||
327 | #ifndef CONFIG_MMC_SDHCI_S3C_DMA | 322 | #ifndef CONFIG_MMC_SDHCI_S3C_DMA |
328 | 323 | ||
@@ -330,9 +325,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
330 | * support as well. */ | 325 | * support as well. */ |
331 | host->quirks |= SDHCI_QUIRK_BROKEN_DMA; | 326 | host->quirks |= SDHCI_QUIRK_BROKEN_DMA; |
332 | 327 | ||
333 | /* PIO currently has problems with multi-block IO */ | ||
334 | host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; | ||
335 | |||
336 | #endif /* CONFIG_MMC_SDHCI_S3C_DMA */ | 328 | #endif /* CONFIG_MMC_SDHCI_S3C_DMA */ |
337 | 329 | ||
338 | /* It seems we do not get an DATA transfer complete on non-busy | 330 | /* It seems we do not get an DATA transfer complete on non-busy |
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c new file mode 100644 index 000000000000..d70c54c7b70a --- /dev/null +++ b/drivers/mmc/host/sdhci-spear.c | |||
@@ -0,0 +1,298 @@ | |||
1 | /* | ||
2 | * drivers/mmc/host/sdhci-spear.c | ||
3 | * | ||
4 | * Support of SDHCI platform devices for spear soc family | ||
5 | * | ||
6 | * Copyright (C) 2010 ST Microelectronics | ||
7 | * Viresh Kumar<viresh.kumar@st.com> | ||
8 | * | ||
9 | * Inspired by sdhci-pltfm.c | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public | ||
12 | * License version 2. This program is licensed "as is" without any | ||
13 | * warranty of any kind, whether express or implied. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/gpio.h> | ||
19 | #include <linux/highmem.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/mmc/host.h> | ||
25 | #include <linux/mmc/sdhci-spear.h> | ||
26 | #include <linux/io.h> | ||
27 | #include "sdhci.h" | ||
28 | |||
29 | struct spear_sdhci { | ||
30 | struct clk *clk; | ||
31 | struct sdhci_plat_data *data; | ||
32 | }; | ||
33 | |||
34 | /* sdhci ops */ | ||
35 | static struct sdhci_ops sdhci_pltfm_ops = { | ||
36 | /* Nothing to do for now. */ | ||
37 | }; | ||
38 | |||
39 | /* gpio card detection interrupt handler */ | ||
40 | static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) | ||
41 | { | ||
42 | struct platform_device *pdev = dev_id; | ||
43 | struct sdhci_host *host = platform_get_drvdata(pdev); | ||
44 | struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); | ||
45 | unsigned long gpio_irq_type; | ||
46 | int val; | ||
47 | |||
48 | val = gpio_get_value(sdhci->data->card_int_gpio); | ||
49 | |||
50 | /* val == 1 -> card removed, val == 0 -> card inserted */ | ||
51 | /* if card removed - set irq for low level, else vice versa */ | ||
52 | gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; | ||
53 | set_irq_type(irq, gpio_irq_type); | ||
54 | |||
55 | if (sdhci->data->card_power_gpio >= 0) { | ||
56 | if (!sdhci->data->power_always_enb) { | ||
57 | /* if card inserted, give power, otherwise remove it */ | ||
58 | val = sdhci->data->power_active_high ? !val : val ; | ||
59 | gpio_set_value(sdhci->data->card_power_gpio, val); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | /* inform sdhci driver about card insertion/removal */ | ||
64 | tasklet_schedule(&host->card_tasklet); | ||
65 | |||
66 | return IRQ_HANDLED; | ||
67 | } | ||
68 | |||
69 | static int __devinit sdhci_probe(struct platform_device *pdev) | ||
70 | { | ||
71 | struct sdhci_host *host; | ||
72 | struct resource *iomem; | ||
73 | struct spear_sdhci *sdhci; | ||
74 | int ret; | ||
75 | |||
76 | BUG_ON(pdev == NULL); | ||
77 | |||
78 | iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
79 | if (!iomem) { | ||
80 | ret = -ENOMEM; | ||
81 | dev_dbg(&pdev->dev, "memory resource not defined\n"); | ||
82 | goto err; | ||
83 | } | ||
84 | |||
85 | if (!request_mem_region(iomem->start, resource_size(iomem), | ||
86 | "spear-sdhci")) { | ||
87 | ret = -EBUSY; | ||
88 | dev_dbg(&pdev->dev, "cannot request region\n"); | ||
89 | goto err; | ||
90 | } | ||
91 | |||
92 | sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL); | ||
93 | if (!sdhci) { | ||
94 | ret = -ENOMEM; | ||
95 | dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); | ||
96 | goto err_kzalloc; | ||
97 | } | ||
98 | |||
99 | /* clk enable */ | ||
100 | sdhci->clk = clk_get(&pdev->dev, NULL); | ||
101 | if (IS_ERR(sdhci->clk)) { | ||
102 | ret = PTR_ERR(sdhci->clk); | ||
103 | dev_dbg(&pdev->dev, "Error getting clock\n"); | ||
104 | goto err_clk_get; | ||
105 | } | ||
106 | |||
107 | ret = clk_enable(sdhci->clk); | ||
108 | if (ret) { | ||
109 | dev_dbg(&pdev->dev, "Error enabling clock\n"); | ||
110 | goto err_clk_enb; | ||
111 | } | ||
112 | |||
113 | /* overwrite platform_data */ | ||
114 | sdhci->data = dev_get_platdata(&pdev->dev); | ||
115 | pdev->dev.platform_data = sdhci; | ||
116 | |||
117 | if (pdev->dev.parent) | ||
118 | host = sdhci_alloc_host(pdev->dev.parent, 0); | ||
119 | else | ||
120 | host = sdhci_alloc_host(&pdev->dev, 0); | ||
121 | |||
122 | if (IS_ERR(host)) { | ||
123 | ret = PTR_ERR(host); | ||
124 | dev_dbg(&pdev->dev, "error allocating host\n"); | ||
125 | goto err_alloc_host; | ||
126 | } | ||
127 | |||
128 | host->hw_name = "sdhci"; | ||
129 | host->ops = &sdhci_pltfm_ops; | ||
130 | host->irq = platform_get_irq(pdev, 0); | ||
131 | host->quirks = SDHCI_QUIRK_BROKEN_ADMA; | ||
132 | |||
133 | host->ioaddr = ioremap(iomem->start, resource_size(iomem)); | ||
134 | if (!host->ioaddr) { | ||
135 | ret = -ENOMEM; | ||
136 | dev_dbg(&pdev->dev, "failed to remap registers\n"); | ||
137 | goto err_ioremap; | ||
138 | } | ||
139 | |||
140 | ret = sdhci_add_host(host); | ||
141 | if (ret) { | ||
142 | dev_dbg(&pdev->dev, "error adding host\n"); | ||
143 | goto err_add_host; | ||
144 | } | ||
145 | |||
146 | platform_set_drvdata(pdev, host); | ||
147 | |||
148 | /* | ||
149 | * It is optional to use GPIOs for sdhci Power control & sdhci card | ||
150 | * interrupt detection. If sdhci->data is NULL, then use original sdhci | ||
151 | * lines otherwise GPIO lines. | ||
152 | * If GPIO is selected for power control, then power should be disabled | ||
153 | * after card removal and should be enabled when card insertion | ||
154 | * interrupt occurs | ||
155 | */ | ||
156 | if (!sdhci->data) | ||
157 | return 0; | ||
158 | |||
159 | if (sdhci->data->card_power_gpio >= 0) { | ||
160 | int val = 0; | ||
161 | |||
162 | ret = gpio_request(sdhci->data->card_power_gpio, "sdhci"); | ||
163 | if (ret < 0) { | ||
164 | dev_dbg(&pdev->dev, "gpio request fail: %d\n", | ||
165 | sdhci->data->card_power_gpio); | ||
166 | goto err_pgpio_request; | ||
167 | } | ||
168 | |||
169 | if (sdhci->data->power_always_enb) | ||
170 | val = sdhci->data->power_active_high; | ||
171 | else | ||
172 | val = !sdhci->data->power_active_high; | ||
173 | |||
174 | ret = gpio_direction_output(sdhci->data->card_power_gpio, val); | ||
175 | if (ret) { | ||
176 | dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", | ||
177 | sdhci->data->card_power_gpio); | ||
178 | goto err_pgpio_direction; | ||
179 | } | ||
180 | |||
181 | gpio_set_value(sdhci->data->card_power_gpio, 1); | ||
182 | } | ||
183 | |||
184 | if (sdhci->data->card_int_gpio >= 0) { | ||
185 | ret = gpio_request(sdhci->data->card_int_gpio, "sdhci"); | ||
186 | if (ret < 0) { | ||
187 | dev_dbg(&pdev->dev, "gpio request fail: %d\n", | ||
188 | sdhci->data->card_int_gpio); | ||
189 | goto err_igpio_request; | ||
190 | } | ||
191 | |||
192 | ret = gpio_direction_input(sdhci->data->card_int_gpio); | ||
193 | if (ret) { | ||
194 | dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", | ||
195 | sdhci->data->card_int_gpio); | ||
196 | goto err_igpio_direction; | ||
197 | } | ||
198 | ret = request_irq(gpio_to_irq(sdhci->data->card_int_gpio), | ||
199 | sdhci_gpio_irq, IRQF_TRIGGER_LOW, | ||
200 | mmc_hostname(host->mmc), pdev); | ||
201 | if (ret) { | ||
202 | dev_dbg(&pdev->dev, "gpio request irq fail: %d\n", | ||
203 | sdhci->data->card_int_gpio); | ||
204 | goto err_igpio_request_irq; | ||
205 | } | ||
206 | |||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | |||
211 | err_igpio_request_irq: | ||
212 | err_igpio_direction: | ||
213 | if (sdhci->data->card_int_gpio >= 0) | ||
214 | gpio_free(sdhci->data->card_int_gpio); | ||
215 | err_igpio_request: | ||
216 | err_pgpio_direction: | ||
217 | if (sdhci->data->card_power_gpio >= 0) | ||
218 | gpio_free(sdhci->data->card_power_gpio); | ||
219 | err_pgpio_request: | ||
220 | platform_set_drvdata(pdev, NULL); | ||
221 | sdhci_remove_host(host, 1); | ||
222 | err_add_host: | ||
223 | iounmap(host->ioaddr); | ||
224 | err_ioremap: | ||
225 | sdhci_free_host(host); | ||
226 | err_alloc_host: | ||
227 | clk_disable(sdhci->clk); | ||
228 | err_clk_enb: | ||
229 | clk_put(sdhci->clk); | ||
230 | err_clk_get: | ||
231 | kfree(sdhci); | ||
232 | err_kzalloc: | ||
233 | release_mem_region(iomem->start, resource_size(iomem)); | ||
234 | err: | ||
235 | dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); | ||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | static int __devexit sdhci_remove(struct platform_device *pdev) | ||
240 | { | ||
241 | struct sdhci_host *host = platform_get_drvdata(pdev); | ||
242 | struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
243 | struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); | ||
244 | int dead; | ||
245 | u32 scratch; | ||
246 | |||
247 | if (sdhci->data) { | ||
248 | if (sdhci->data->card_int_gpio >= 0) { | ||
249 | free_irq(gpio_to_irq(sdhci->data->card_int_gpio), pdev); | ||
250 | gpio_free(sdhci->data->card_int_gpio); | ||
251 | } | ||
252 | |||
253 | if (sdhci->data->card_power_gpio >= 0) | ||
254 | gpio_free(sdhci->data->card_power_gpio); | ||
255 | } | ||
256 | |||
257 | platform_set_drvdata(pdev, NULL); | ||
258 | dead = 0; | ||
259 | scratch = readl(host->ioaddr + SDHCI_INT_STATUS); | ||
260 | if (scratch == (u32)-1) | ||
261 | dead = 1; | ||
262 | |||
263 | sdhci_remove_host(host, dead); | ||
264 | iounmap(host->ioaddr); | ||
265 | sdhci_free_host(host); | ||
266 | clk_disable(sdhci->clk); | ||
267 | clk_put(sdhci->clk); | ||
268 | kfree(sdhci); | ||
269 | if (iomem) | ||
270 | release_mem_region(iomem->start, resource_size(iomem)); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static struct platform_driver sdhci_driver = { | ||
276 | .driver = { | ||
277 | .name = "sdhci", | ||
278 | .owner = THIS_MODULE, | ||
279 | }, | ||
280 | .probe = sdhci_probe, | ||
281 | .remove = __devexit_p(sdhci_remove), | ||
282 | }; | ||
283 | |||
284 | static int __init sdhci_init(void) | ||
285 | { | ||
286 | return platform_driver_register(&sdhci_driver); | ||
287 | } | ||
288 | module_init(sdhci_init); | ||
289 | |||
290 | static void __exit sdhci_exit(void) | ||
291 | { | ||
292 | platform_driver_unregister(&sdhci_driver); | ||
293 | } | ||
294 | module_exit(sdhci_exit); | ||
295 | |||
296 | MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); | ||
297 | MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); | ||
298 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9d4fdfa685e5..c6d1bd8d4ac4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -496,12 +496,22 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, | |||
496 | WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4); | 496 | WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4); |
497 | } | 497 | } |
498 | 498 | ||
499 | /* | 499 | if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { |
500 | * Add a terminating entry. | 500 | /* |
501 | */ | 501 | * Mark the last descriptor as the terminating descriptor |
502 | */ | ||
503 | if (desc != host->adma_desc) { | ||
504 | desc -= 8; | ||
505 | desc[0] |= 0x2; /* end */ | ||
506 | } | ||
507 | } else { | ||
508 | /* | ||
509 | * Add a terminating entry. | ||
510 | */ | ||
502 | 511 | ||
503 | /* nop, end, valid */ | 512 | /* nop, end, valid */ |
504 | sdhci_set_adma_desc(desc, 0, 0, 0x3); | 513 | sdhci_set_adma_desc(desc, 0, 0, 0x3); |
514 | } | ||
505 | 515 | ||
506 | /* | 516 | /* |
507 | * Resync align buffer as we might have changed it. | 517 | * Resync align buffer as we might have changed it. |
@@ -1587,7 +1597,7 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) | |||
1587 | 1597 | ||
1588 | sdhci_disable_card_detection(host); | 1598 | sdhci_disable_card_detection(host); |
1589 | 1599 | ||
1590 | ret = mmc_suspend_host(host->mmc, state); | 1600 | ret = mmc_suspend_host(host->mmc); |
1591 | if (ret) | 1601 | if (ret) |
1592 | return ret; | 1602 | return ret; |
1593 | 1603 | ||
@@ -1744,7 +1754,8 @@ int sdhci_add_host(struct sdhci_host *host) | |||
1744 | host->max_clk = | 1754 | host->max_clk = |
1745 | (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; | 1755 | (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; |
1746 | host->max_clk *= 1000000; | 1756 | host->max_clk *= 1000000; |
1747 | if (host->max_clk == 0) { | 1757 | if (host->max_clk == 0 || host->quirks & |
1758 | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) { | ||
1748 | if (!host->ops->get_max_clock) { | 1759 | if (!host->ops->get_max_clock) { |
1749 | printk(KERN_ERR | 1760 | printk(KERN_ERR |
1750 | "%s: Hardware doesn't specify base clock " | 1761 | "%s: Hardware doesn't specify base clock " |
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 842f46f94284..c8468134adc9 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
@@ -127,7 +127,7 @@ | |||
127 | #define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ | 127 | #define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ |
128 | SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ | 128 | SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ |
129 | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ | 129 | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ |
130 | SDHCI_INT_DATA_END_BIT | SDHCI_ADMA_ERROR) | 130 | SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR) |
131 | #define SDHCI_INT_ALL_MASK ((unsigned int)-1) | 131 | #define SDHCI_INT_ALL_MASK ((unsigned int)-1) |
132 | 132 | ||
133 | #define SDHCI_ACMD12_ERR 0x3C | 133 | #define SDHCI_ACMD12_ERR 0x3C |
@@ -236,6 +236,10 @@ struct sdhci_host { | |||
236 | #define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23) | 236 | #define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23) |
237 | /* Controller uses SDCLK instead of TMCLK for data timeouts */ | 237 | /* Controller uses SDCLK instead of TMCLK for data timeouts */ |
238 | #define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24) | 238 | #define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24) |
239 | /* Controller reports wrong base clock capability */ | ||
240 | #define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25) | ||
241 | /* Controller cannot support End Attribute in NOP ADMA descriptor */ | ||
242 | #define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26) | ||
239 | 243 | ||
240 | int irq; /* Device IRQ */ | 244 | int irq; /* Device IRQ */ |
241 | void __iomem * ioaddr; /* Mapped address */ | 245 | void __iomem * ioaddr; /* Mapped address */ |
@@ -294,12 +298,12 @@ struct sdhci_host { | |||
294 | 298 | ||
295 | struct sdhci_ops { | 299 | struct sdhci_ops { |
296 | #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS | 300 | #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS |
297 | u32 (*readl)(struct sdhci_host *host, int reg); | 301 | u32 (*read_l)(struct sdhci_host *host, int reg); |
298 | u16 (*readw)(struct sdhci_host *host, int reg); | 302 | u16 (*read_w)(struct sdhci_host *host, int reg); |
299 | u8 (*readb)(struct sdhci_host *host, int reg); | 303 | u8 (*read_b)(struct sdhci_host *host, int reg); |
300 | void (*writel)(struct sdhci_host *host, u32 val, int reg); | 304 | void (*write_l)(struct sdhci_host *host, u32 val, int reg); |
301 | void (*writew)(struct sdhci_host *host, u16 val, int reg); | 305 | void (*write_w)(struct sdhci_host *host, u16 val, int reg); |
302 | void (*writeb)(struct sdhci_host *host, u8 val, int reg); | 306 | void (*write_b)(struct sdhci_host *host, u8 val, int reg); |
303 | #endif | 307 | #endif |
304 | 308 | ||
305 | void (*set_clock)(struct sdhci_host *host, unsigned int clock); | 309 | void (*set_clock)(struct sdhci_host *host, unsigned int clock); |
@@ -314,48 +318,48 @@ struct sdhci_ops { | |||
314 | 318 | ||
315 | static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) | 319 | static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) |
316 | { | 320 | { |
317 | if (unlikely(host->ops->writel)) | 321 | if (unlikely(host->ops->write_l)) |
318 | host->ops->writel(host, val, reg); | 322 | host->ops->write_l(host, val, reg); |
319 | else | 323 | else |
320 | writel(val, host->ioaddr + reg); | 324 | writel(val, host->ioaddr + reg); |
321 | } | 325 | } |
322 | 326 | ||
323 | static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) | 327 | static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) |
324 | { | 328 | { |
325 | if (unlikely(host->ops->writew)) | 329 | if (unlikely(host->ops->write_w)) |
326 | host->ops->writew(host, val, reg); | 330 | host->ops->write_w(host, val, reg); |
327 | else | 331 | else |
328 | writew(val, host->ioaddr + reg); | 332 | writew(val, host->ioaddr + reg); |
329 | } | 333 | } |
330 | 334 | ||
331 | static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) | 335 | static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) |
332 | { | 336 | { |
333 | if (unlikely(host->ops->writeb)) | 337 | if (unlikely(host->ops->write_b)) |
334 | host->ops->writeb(host, val, reg); | 338 | host->ops->write_b(host, val, reg); |
335 | else | 339 | else |
336 | writeb(val, host->ioaddr + reg); | 340 | writeb(val, host->ioaddr + reg); |
337 | } | 341 | } |
338 | 342 | ||
339 | static inline u32 sdhci_readl(struct sdhci_host *host, int reg) | 343 | static inline u32 sdhci_readl(struct sdhci_host *host, int reg) |
340 | { | 344 | { |
341 | if (unlikely(host->ops->readl)) | 345 | if (unlikely(host->ops->read_l)) |
342 | return host->ops->readl(host, reg); | 346 | return host->ops->read_l(host, reg); |
343 | else | 347 | else |
344 | return readl(host->ioaddr + reg); | 348 | return readl(host->ioaddr + reg); |
345 | } | 349 | } |
346 | 350 | ||
347 | static inline u16 sdhci_readw(struct sdhci_host *host, int reg) | 351 | static inline u16 sdhci_readw(struct sdhci_host *host, int reg) |
348 | { | 352 | { |
349 | if (unlikely(host->ops->readw)) | 353 | if (unlikely(host->ops->read_w)) |
350 | return host->ops->readw(host, reg); | 354 | return host->ops->read_w(host, reg); |
351 | else | 355 | else |
352 | return readw(host->ioaddr + reg); | 356 | return readw(host->ioaddr + reg); |
353 | } | 357 | } |
354 | 358 | ||
355 | static inline u8 sdhci_readb(struct sdhci_host *host, int reg) | 359 | static inline u8 sdhci_readb(struct sdhci_host *host, int reg) |
356 | { | 360 | { |
357 | if (unlikely(host->ops->readb)) | 361 | if (unlikely(host->ops->read_b)) |
358 | return host->ops->readb(host, reg); | 362 | return host->ops->read_b(host, reg); |
359 | else | 363 | else |
360 | return readb(host->ioaddr + reg); | 364 | return readb(host->ioaddr + reg); |
361 | } | 365 | } |
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index cb41e9c3ac07..e7507af3856e 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c | |||
@@ -519,7 +519,7 @@ static int sdricoh_pcmcia_suspend(struct pcmcia_device *link) | |||
519 | { | 519 | { |
520 | struct mmc_host *mmc = link->priv; | 520 | struct mmc_host *mmc = link->priv; |
521 | dev_dbg(&link->dev, "suspend\n"); | 521 | dev_dbg(&link->dev, "suspend\n"); |
522 | mmc_suspend_host(mmc, PMSG_SUSPEND); | 522 | mmc_suspend_host(mmc); |
523 | return 0; | 523 | return 0; |
524 | } | 524 | } |
525 | 525 | ||
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c new file mode 100644 index 000000000000..eb97830c0344 --- /dev/null +++ b/drivers/mmc/host/sh_mmcif.c | |||
@@ -0,0 +1,965 @@ | |||
1 | /* | ||
2 | * MMCIF eMMC driver. | ||
3 | * | ||
4 | * Copyright (C) 2010 Renesas Solutions Corp. | ||
5 | * Yusuke Goda <yusuke.goda.sx@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License. | ||
10 | * | ||
11 | * | ||
12 | * TODO | ||
13 | * 1. DMA | ||
14 | * 2. Power management | ||
15 | * 3. Handle MMC errors better | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/mmc/host.h> | ||
21 | #include <linux/mmc/card.h> | ||
22 | #include <linux/mmc/core.h> | ||
23 | #include <linux/mmc/mmc.h> | ||
24 | #include <linux/mmc/sdio.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/clk.h> | ||
28 | #include <linux/mmc/sh_mmcif.h> | ||
29 | |||
30 | #define DRIVER_NAME "sh_mmcif" | ||
31 | #define DRIVER_VERSION "2010-04-28" | ||
32 | |||
33 | #define MMCIF_CE_CMD_SET 0x00000000 | ||
34 | #define MMCIF_CE_ARG 0x00000008 | ||
35 | #define MMCIF_CE_ARG_CMD12 0x0000000C | ||
36 | #define MMCIF_CE_CMD_CTRL 0x00000010 | ||
37 | #define MMCIF_CE_BLOCK_SET 0x00000014 | ||
38 | #define MMCIF_CE_CLK_CTRL 0x00000018 | ||
39 | #define MMCIF_CE_BUF_ACC 0x0000001C | ||
40 | #define MMCIF_CE_RESP3 0x00000020 | ||
41 | #define MMCIF_CE_RESP2 0x00000024 | ||
42 | #define MMCIF_CE_RESP1 0x00000028 | ||
43 | #define MMCIF_CE_RESP0 0x0000002C | ||
44 | #define MMCIF_CE_RESP_CMD12 0x00000030 | ||
45 | #define MMCIF_CE_DATA 0x00000034 | ||
46 | #define MMCIF_CE_INT 0x00000040 | ||
47 | #define MMCIF_CE_INT_MASK 0x00000044 | ||
48 | #define MMCIF_CE_HOST_STS1 0x00000048 | ||
49 | #define MMCIF_CE_HOST_STS2 0x0000004C | ||
50 | #define MMCIF_CE_VERSION 0x0000007C | ||
51 | |||
52 | /* CE_CMD_SET */ | ||
53 | #define CMD_MASK 0x3f000000 | ||
54 | #define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22)) | ||
55 | #define CMD_SET_RTYP_6B ((0 << 23) | (1 << 22)) /* R1/R1b/R3/R4/R5 */ | ||
56 | #define CMD_SET_RTYP_17B ((1 << 23) | (0 << 22)) /* R2 */ | ||
57 | #define CMD_SET_RBSY (1 << 21) /* R1b */ | ||
58 | #define CMD_SET_CCSEN (1 << 20) | ||
59 | #define CMD_SET_WDAT (1 << 19) /* 1: on data, 0: no data */ | ||
60 | #define CMD_SET_DWEN (1 << 18) /* 1: write, 0: read */ | ||
61 | #define CMD_SET_CMLTE (1 << 17) /* 1: multi block trans, 0: single */ | ||
62 | #define CMD_SET_CMD12EN (1 << 16) /* 1: CMD12 auto issue */ | ||
63 | #define CMD_SET_RIDXC_INDEX ((0 << 15) | (0 << 14)) /* index check */ | ||
64 | #define CMD_SET_RIDXC_BITS ((0 << 15) | (1 << 14)) /* check bits check */ | ||
65 | #define CMD_SET_RIDXC_NO ((1 << 15) | (0 << 14)) /* no check */ | ||
66 | #define CMD_SET_CRC7C ((0 << 13) | (0 << 12)) /* CRC7 check*/ | ||
67 | #define CMD_SET_CRC7C_BITS ((0 << 13) | (1 << 12)) /* check bits check*/ | ||
68 | #define CMD_SET_CRC7C_INTERNAL ((1 << 13) | (0 << 12)) /* internal CRC7 check*/ | ||
69 | #define CMD_SET_CRC16C (1 << 10) /* 0: CRC16 check*/ | ||
70 | #define CMD_SET_CRCSTE (1 << 8) /* 1: not receive CRC status */ | ||
71 | #define CMD_SET_TBIT (1 << 7) /* 1: tran mission bit "Low" */ | ||
72 | #define CMD_SET_OPDM (1 << 6) /* 1: open/drain */ | ||
73 | #define CMD_SET_CCSH (1 << 5) | ||
74 | #define CMD_SET_DATW_1 ((0 << 1) | (0 << 0)) /* 1bit */ | ||
75 | #define CMD_SET_DATW_4 ((0 << 1) | (1 << 0)) /* 4bit */ | ||
76 | #define CMD_SET_DATW_8 ((1 << 1) | (0 << 0)) /* 8bit */ | ||
77 | |||
78 | /* CE_CMD_CTRL */ | ||
79 | #define CMD_CTRL_BREAK (1 << 0) | ||
80 | |||
81 | /* CE_BLOCK_SET */ | ||
82 | #define BLOCK_SIZE_MASK 0x0000ffff | ||
83 | |||
84 | /* CE_CLK_CTRL */ | ||
85 | #define CLK_ENABLE (1 << 24) /* 1: output mmc clock */ | ||
86 | #define CLK_CLEAR ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16)) | ||
87 | #define CLK_SUP_PCLK ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16)) | ||
88 | #define SRSPTO_256 ((1 << 13) | (0 << 12)) /* resp timeout */ | ||
89 | #define SRBSYTO_29 ((1 << 11) | (1 << 10) | \ | ||
90 | (1 << 9) | (1 << 8)) /* resp busy timeout */ | ||
91 | #define SRWDTO_29 ((1 << 7) | (1 << 6) | \ | ||
92 | (1 << 5) | (1 << 4)) /* read/write timeout */ | ||
93 | #define SCCSTO_29 ((1 << 3) | (1 << 2) | \ | ||
94 | (1 << 1) | (1 << 0)) /* ccs timeout */ | ||
95 | |||
96 | /* CE_BUF_ACC */ | ||
97 | #define BUF_ACC_DMAWEN (1 << 25) | ||
98 | #define BUF_ACC_DMAREN (1 << 24) | ||
99 | #define BUF_ACC_BUSW_32 (0 << 17) | ||
100 | #define BUF_ACC_BUSW_16 (1 << 17) | ||
101 | #define BUF_ACC_ATYP (1 << 16) | ||
102 | |||
103 | /* CE_INT */ | ||
104 | #define INT_CCSDE (1 << 29) | ||
105 | #define INT_CMD12DRE (1 << 26) | ||
106 | #define INT_CMD12RBE (1 << 25) | ||
107 | #define INT_CMD12CRE (1 << 24) | ||
108 | #define INT_DTRANE (1 << 23) | ||
109 | #define INT_BUFRE (1 << 22) | ||
110 | #define INT_BUFWEN (1 << 21) | ||
111 | #define INT_BUFREN (1 << 20) | ||
112 | #define INT_CCSRCV (1 << 19) | ||
113 | #define INT_RBSYE (1 << 17) | ||
114 | #define INT_CRSPE (1 << 16) | ||
115 | #define INT_CMDVIO (1 << 15) | ||
116 | #define INT_BUFVIO (1 << 14) | ||
117 | #define INT_WDATERR (1 << 11) | ||
118 | #define INT_RDATERR (1 << 10) | ||
119 | #define INT_RIDXERR (1 << 9) | ||
120 | #define INT_RSPERR (1 << 8) | ||
121 | #define INT_CCSTO (1 << 5) | ||
122 | #define INT_CRCSTO (1 << 4) | ||
123 | #define INT_WDATTO (1 << 3) | ||
124 | #define INT_RDATTO (1 << 2) | ||
125 | #define INT_RBSYTO (1 << 1) | ||
126 | #define INT_RSPTO (1 << 0) | ||
127 | #define INT_ERR_STS (INT_CMDVIO | INT_BUFVIO | INT_WDATERR | \ | ||
128 | INT_RDATERR | INT_RIDXERR | INT_RSPERR | \ | ||
129 | INT_CCSTO | INT_CRCSTO | INT_WDATTO | \ | ||
130 | INT_RDATTO | INT_RBSYTO | INT_RSPTO) | ||
131 | |||
132 | /* CE_INT_MASK */ | ||
133 | #define MASK_ALL 0x00000000 | ||
134 | #define MASK_MCCSDE (1 << 29) | ||
135 | #define MASK_MCMD12DRE (1 << 26) | ||
136 | #define MASK_MCMD12RBE (1 << 25) | ||
137 | #define MASK_MCMD12CRE (1 << 24) | ||
138 | #define MASK_MDTRANE (1 << 23) | ||
139 | #define MASK_MBUFRE (1 << 22) | ||
140 | #define MASK_MBUFWEN (1 << 21) | ||
141 | #define MASK_MBUFREN (1 << 20) | ||
142 | #define MASK_MCCSRCV (1 << 19) | ||
143 | #define MASK_MRBSYE (1 << 17) | ||
144 | #define MASK_MCRSPE (1 << 16) | ||
145 | #define MASK_MCMDVIO (1 << 15) | ||
146 | #define MASK_MBUFVIO (1 << 14) | ||
147 | #define MASK_MWDATERR (1 << 11) | ||
148 | #define MASK_MRDATERR (1 << 10) | ||
149 | #define MASK_MRIDXERR (1 << 9) | ||
150 | #define MASK_MRSPERR (1 << 8) | ||
151 | #define MASK_MCCSTO (1 << 5) | ||
152 | #define MASK_MCRCSTO (1 << 4) | ||
153 | #define MASK_MWDATTO (1 << 3) | ||
154 | #define MASK_MRDATTO (1 << 2) | ||
155 | #define MASK_MRBSYTO (1 << 1) | ||
156 | #define MASK_MRSPTO (1 << 0) | ||
157 | |||
158 | /* CE_HOST_STS1 */ | ||
159 | #define STS1_CMDSEQ (1 << 31) | ||
160 | |||
161 | /* CE_HOST_STS2 */ | ||
162 | #define STS2_CRCSTE (1 << 31) | ||
163 | #define STS2_CRC16E (1 << 30) | ||
164 | #define STS2_AC12CRCE (1 << 29) | ||
165 | #define STS2_RSPCRC7E (1 << 28) | ||
166 | #define STS2_CRCSTEBE (1 << 27) | ||
167 | #define STS2_RDATEBE (1 << 26) | ||
168 | #define STS2_AC12REBE (1 << 25) | ||
169 | #define STS2_RSPEBE (1 << 24) | ||
170 | #define STS2_AC12IDXE (1 << 23) | ||
171 | #define STS2_RSPIDXE (1 << 22) | ||
172 | #define STS2_CCSTO (1 << 15) | ||
173 | #define STS2_RDATTO (1 << 14) | ||
174 | #define STS2_DATBSYTO (1 << 13) | ||
175 | #define STS2_CRCSTTO (1 << 12) | ||
176 | #define STS2_AC12BSYTO (1 << 11) | ||
177 | #define STS2_RSPBSYTO (1 << 10) | ||
178 | #define STS2_AC12RSPTO (1 << 9) | ||
179 | #define STS2_RSPTO (1 << 8) | ||
180 | #define STS2_CRC_ERR (STS2_CRCSTE | STS2_CRC16E | \ | ||
181 | STS2_AC12CRCE | STS2_RSPCRC7E | STS2_CRCSTEBE) | ||
182 | #define STS2_TIMEOUT_ERR (STS2_CCSTO | STS2_RDATTO | \ | ||
183 | STS2_DATBSYTO | STS2_CRCSTTO | \ | ||
184 | STS2_AC12BSYTO | STS2_RSPBSYTO | \ | ||
185 | STS2_AC12RSPTO | STS2_RSPTO) | ||
186 | |||
187 | /* CE_VERSION */ | ||
188 | #define SOFT_RST_ON (1 << 31) | ||
189 | #define SOFT_RST_OFF (0 << 31) | ||
190 | |||
191 | #define CLKDEV_EMMC_DATA 52000000 /* 52MHz */ | ||
192 | #define CLKDEV_MMC_DATA 20000000 /* 20MHz */ | ||
193 | #define CLKDEV_INIT 400000 /* 400 KHz */ | ||
194 | |||
195 | struct sh_mmcif_host { | ||
196 | struct mmc_host *mmc; | ||
197 | struct mmc_data *data; | ||
198 | struct mmc_command *cmd; | ||
199 | struct platform_device *pd; | ||
200 | struct clk *hclk; | ||
201 | unsigned int clk; | ||
202 | int bus_width; | ||
203 | u16 wait_int; | ||
204 | u16 sd_error; | ||
205 | long timeout; | ||
206 | void __iomem *addr; | ||
207 | wait_queue_head_t intr_wait; | ||
208 | }; | ||
209 | |||
210 | static inline u32 sh_mmcif_readl(struct sh_mmcif_host *host, unsigned int reg) | ||
211 | { | ||
212 | return readl(host->addr + reg); | ||
213 | } | ||
214 | |||
215 | static inline void sh_mmcif_writel(struct sh_mmcif_host *host, | ||
216 | unsigned int reg, u32 val) | ||
217 | { | ||
218 | writel(val, host->addr + reg); | ||
219 | } | ||
220 | |||
221 | static inline void sh_mmcif_bitset(struct sh_mmcif_host *host, | ||
222 | unsigned int reg, u32 val) | ||
223 | { | ||
224 | writel(val | sh_mmcif_readl(host, reg), host->addr + reg); | ||
225 | } | ||
226 | |||
227 | static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, | ||
228 | unsigned int reg, u32 val) | ||
229 | { | ||
230 | writel(~val & sh_mmcif_readl(host, reg), host->addr + reg); | ||
231 | } | ||
232 | |||
233 | |||
234 | static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) | ||
235 | { | ||
236 | struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; | ||
237 | |||
238 | sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); | ||
239 | sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR); | ||
240 | |||
241 | if (!clk) | ||
242 | return; | ||
243 | if (p->sup_pclk && clk == host->clk) | ||
244 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); | ||
245 | else | ||
246 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & | ||
247 | (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16)); | ||
248 | |||
249 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); | ||
250 | } | ||
251 | |||
252 | static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) | ||
253 | { | ||
254 | u32 tmp; | ||
255 | |||
256 | tmp = 0x010f0000 & sh_mmcif_readl(host, MMCIF_CE_CLK_CTRL); | ||
257 | |||
258 | sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_ON); | ||
259 | sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_OFF); | ||
260 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp | | ||
261 | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29); | ||
262 | /* byte swap on */ | ||
263 | sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP); | ||
264 | } | ||
265 | |||
266 | static int sh_mmcif_error_manage(struct sh_mmcif_host *host) | ||
267 | { | ||
268 | u32 state1, state2; | ||
269 | int ret, timeout = 10000000; | ||
270 | |||
271 | host->sd_error = 0; | ||
272 | host->wait_int = 0; | ||
273 | |||
274 | state1 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS1); | ||
275 | state2 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS2); | ||
276 | pr_debug("%s: ERR HOST_STS1 = %08x\n", \ | ||
277 | DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS1)); | ||
278 | pr_debug("%s: ERR HOST_STS2 = %08x\n", \ | ||
279 | DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS2)); | ||
280 | |||
281 | if (state1 & STS1_CMDSEQ) { | ||
282 | sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); | ||
283 | sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); | ||
284 | while (1) { | ||
285 | timeout--; | ||
286 | if (timeout < 0) { | ||
287 | pr_err(DRIVER_NAME": Forceed end of " \ | ||
288 | "command sequence timeout err\n"); | ||
289 | return -EIO; | ||
290 | } | ||
291 | if (!(sh_mmcif_readl(host, MMCIF_CE_HOST_STS1) | ||
292 | & STS1_CMDSEQ)) | ||
293 | break; | ||
294 | mdelay(1); | ||
295 | } | ||
296 | sh_mmcif_sync_reset(host); | ||
297 | pr_debug(DRIVER_NAME": Forced end of command sequence\n"); | ||
298 | return -EIO; | ||
299 | } | ||
300 | |||
301 | if (state2 & STS2_CRC_ERR) { | ||
302 | pr_debug(DRIVER_NAME": Happened CRC error\n"); | ||
303 | ret = -EIO; | ||
304 | } else if (state2 & STS2_TIMEOUT_ERR) { | ||
305 | pr_debug(DRIVER_NAME": Happened Timeout error\n"); | ||
306 | ret = -ETIMEDOUT; | ||
307 | } else { | ||
308 | pr_debug(DRIVER_NAME": Happened End/Index error\n"); | ||
309 | ret = -EIO; | ||
310 | } | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | static int sh_mmcif_single_read(struct sh_mmcif_host *host, | ||
315 | struct mmc_request *mrq) | ||
316 | { | ||
317 | struct mmc_data *data = mrq->data; | ||
318 | long time; | ||
319 | u32 blocksize, i, *p = sg_virt(data->sg); | ||
320 | |||
321 | host->wait_int = 0; | ||
322 | |||
323 | /* buf read enable */ | ||
324 | sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); | ||
325 | time = wait_event_interruptible_timeout(host->intr_wait, | ||
326 | host->wait_int == 1 || | ||
327 | host->sd_error == 1, host->timeout); | ||
328 | if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) | ||
329 | return sh_mmcif_error_manage(host); | ||
330 | |||
331 | host->wait_int = 0; | ||
332 | blocksize = (BLOCK_SIZE_MASK & | ||
333 | sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3; | ||
334 | for (i = 0; i < blocksize / 4; i++) | ||
335 | *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA); | ||
336 | |||
337 | /* buffer read end */ | ||
338 | sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); | ||
339 | time = wait_event_interruptible_timeout(host->intr_wait, | ||
340 | host->wait_int == 1 || | ||
341 | host->sd_error == 1, host->timeout); | ||
342 | if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) | ||
343 | return sh_mmcif_error_manage(host); | ||
344 | |||
345 | host->wait_int = 0; | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int sh_mmcif_multi_read(struct sh_mmcif_host *host, | ||
350 | struct mmc_request *mrq) | ||
351 | { | ||
352 | struct mmc_data *data = mrq->data; | ||
353 | long time; | ||
354 | u32 blocksize, i, j, sec, *p; | ||
355 | |||
356 | blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET); | ||
357 | for (j = 0; j < data->sg_len; j++) { | ||
358 | p = sg_virt(data->sg); | ||
359 | host->wait_int = 0; | ||
360 | for (sec = 0; sec < data->sg->length / blocksize; sec++) { | ||
361 | sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); | ||
362 | /* buf read enable */ | ||
363 | time = wait_event_interruptible_timeout(host->intr_wait, | ||
364 | host->wait_int == 1 || | ||
365 | host->sd_error == 1, host->timeout); | ||
366 | |||
367 | if (host->wait_int != 1 && | ||
368 | (time == 0 || host->sd_error != 0)) | ||
369 | return sh_mmcif_error_manage(host); | ||
370 | |||
371 | host->wait_int = 0; | ||
372 | for (i = 0; i < blocksize / 4; i++) | ||
373 | *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA); | ||
374 | } | ||
375 | if (j < data->sg_len - 1) | ||
376 | data->sg++; | ||
377 | } | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int sh_mmcif_single_write(struct sh_mmcif_host *host, | ||
382 | struct mmc_request *mrq) | ||
383 | { | ||
384 | struct mmc_data *data = mrq->data; | ||
385 | long time; | ||
386 | u32 blocksize, i, *p = sg_virt(data->sg); | ||
387 | |||
388 | host->wait_int = 0; | ||
389 | sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); | ||
390 | |||
391 | /* buf write enable */ | ||
392 | time = wait_event_interruptible_timeout(host->intr_wait, | ||
393 | host->wait_int == 1 || | ||
394 | host->sd_error == 1, host->timeout); | ||
395 | if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) | ||
396 | return sh_mmcif_error_manage(host); | ||
397 | |||
398 | host->wait_int = 0; | ||
399 | blocksize = (BLOCK_SIZE_MASK & | ||
400 | sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3; | ||
401 | for (i = 0; i < blocksize / 4; i++) | ||
402 | sh_mmcif_writel(host, MMCIF_CE_DATA, *p++); | ||
403 | |||
404 | /* buffer write end */ | ||
405 | sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); | ||
406 | |||
407 | time = wait_event_interruptible_timeout(host->intr_wait, | ||
408 | host->wait_int == 1 || | ||
409 | host->sd_error == 1, host->timeout); | ||
410 | if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) | ||
411 | return sh_mmcif_error_manage(host); | ||
412 | |||
413 | host->wait_int = 0; | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int sh_mmcif_multi_write(struct sh_mmcif_host *host, | ||
418 | struct mmc_request *mrq) | ||
419 | { | ||
420 | struct mmc_data *data = mrq->data; | ||
421 | long time; | ||
422 | u32 i, sec, j, blocksize, *p; | ||
423 | |||
424 | blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET); | ||
425 | |||
426 | for (j = 0; j < data->sg_len; j++) { | ||
427 | p = sg_virt(data->sg); | ||
428 | host->wait_int = 0; | ||
429 | for (sec = 0; sec < data->sg->length / blocksize; sec++) { | ||
430 | sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); | ||
431 | /* buf write enable*/ | ||
432 | time = wait_event_interruptible_timeout(host->intr_wait, | ||
433 | host->wait_int == 1 || | ||
434 | host->sd_error == 1, host->timeout); | ||
435 | |||
436 | if (host->wait_int != 1 && | ||
437 | (time == 0 || host->sd_error != 0)) | ||
438 | return sh_mmcif_error_manage(host); | ||
439 | |||
440 | host->wait_int = 0; | ||
441 | for (i = 0; i < blocksize / 4; i++) | ||
442 | sh_mmcif_writel(host, MMCIF_CE_DATA, *p++); | ||
443 | } | ||
444 | if (j < data->sg_len - 1) | ||
445 | data->sg++; | ||
446 | } | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static void sh_mmcif_get_response(struct sh_mmcif_host *host, | ||
451 | struct mmc_command *cmd) | ||
452 | { | ||
453 | if (cmd->flags & MMC_RSP_136) { | ||
454 | cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP3); | ||
455 | cmd->resp[1] = sh_mmcif_readl(host, MMCIF_CE_RESP2); | ||
456 | cmd->resp[2] = sh_mmcif_readl(host, MMCIF_CE_RESP1); | ||
457 | cmd->resp[3] = sh_mmcif_readl(host, MMCIF_CE_RESP0); | ||
458 | } else | ||
459 | cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP0); | ||
460 | } | ||
461 | |||
462 | static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, | ||
463 | struct mmc_command *cmd) | ||
464 | { | ||
465 | cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP_CMD12); | ||
466 | } | ||
467 | |||
468 | static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, | ||
469 | struct mmc_request *mrq, struct mmc_command *cmd, u32 opc) | ||
470 | { | ||
471 | u32 tmp = 0; | ||
472 | |||
473 | /* Response Type check */ | ||
474 | switch (mmc_resp_type(cmd)) { | ||
475 | case MMC_RSP_NONE: | ||
476 | tmp |= CMD_SET_RTYP_NO; | ||
477 | break; | ||
478 | case MMC_RSP_R1: | ||
479 | case MMC_RSP_R1B: | ||
480 | case MMC_RSP_R3: | ||
481 | tmp |= CMD_SET_RTYP_6B; | ||
482 | break; | ||
483 | case MMC_RSP_R2: | ||
484 | tmp |= CMD_SET_RTYP_17B; | ||
485 | break; | ||
486 | default: | ||
487 | pr_err(DRIVER_NAME": Not support type response.\n"); | ||
488 | break; | ||
489 | } | ||
490 | switch (opc) { | ||
491 | /* RBSY */ | ||
492 | case MMC_SWITCH: | ||
493 | case MMC_STOP_TRANSMISSION: | ||
494 | case MMC_SET_WRITE_PROT: | ||
495 | case MMC_CLR_WRITE_PROT: | ||
496 | case MMC_ERASE: | ||
497 | case MMC_GEN_CMD: | ||
498 | tmp |= CMD_SET_RBSY; | ||
499 | break; | ||
500 | } | ||
501 | /* WDAT / DATW */ | ||
502 | if (host->data) { | ||
503 | tmp |= CMD_SET_WDAT; | ||
504 | switch (host->bus_width) { | ||
505 | case MMC_BUS_WIDTH_1: | ||
506 | tmp |= CMD_SET_DATW_1; | ||
507 | break; | ||
508 | case MMC_BUS_WIDTH_4: | ||
509 | tmp |= CMD_SET_DATW_4; | ||
510 | break; | ||
511 | case MMC_BUS_WIDTH_8: | ||
512 | tmp |= CMD_SET_DATW_8; | ||
513 | break; | ||
514 | default: | ||
515 | pr_err(DRIVER_NAME": Not support bus width.\n"); | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | /* DWEN */ | ||
520 | if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) | ||
521 | tmp |= CMD_SET_DWEN; | ||
522 | /* CMLTE/CMD12EN */ | ||
523 | if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { | ||
524 | tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; | ||
525 | sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, | ||
526 | mrq->data->blocks << 16); | ||
527 | } | ||
528 | /* RIDXC[1:0] check bits */ | ||
529 | if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID || | ||
530 | opc == MMC_SEND_CSD || opc == MMC_SEND_CID) | ||
531 | tmp |= CMD_SET_RIDXC_BITS; | ||
532 | /* RCRC7C[1:0] check bits */ | ||
533 | if (opc == MMC_SEND_OP_COND) | ||
534 | tmp |= CMD_SET_CRC7C_BITS; | ||
535 | /* RCRC7C[1:0] internal CRC7 */ | ||
536 | if (opc == MMC_ALL_SEND_CID || | ||
537 | opc == MMC_SEND_CSD || opc == MMC_SEND_CID) | ||
538 | tmp |= CMD_SET_CRC7C_INTERNAL; | ||
539 | |||
540 | return opc = ((opc << 24) | tmp); | ||
541 | } | ||
542 | |||
543 | static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host, | ||
544 | struct mmc_request *mrq, u32 opc) | ||
545 | { | ||
546 | u32 ret; | ||
547 | |||
548 | switch (opc) { | ||
549 | case MMC_READ_MULTIPLE_BLOCK: | ||
550 | ret = sh_mmcif_multi_read(host, mrq); | ||
551 | break; | ||
552 | case MMC_WRITE_MULTIPLE_BLOCK: | ||
553 | ret = sh_mmcif_multi_write(host, mrq); | ||
554 | break; | ||
555 | case MMC_WRITE_BLOCK: | ||
556 | ret = sh_mmcif_single_write(host, mrq); | ||
557 | break; | ||
558 | case MMC_READ_SINGLE_BLOCK: | ||
559 | case MMC_SEND_EXT_CSD: | ||
560 | ret = sh_mmcif_single_read(host, mrq); | ||
561 | break; | ||
562 | default: | ||
563 | pr_err(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc); | ||
564 | ret = -EINVAL; | ||
565 | break; | ||
566 | } | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, | ||
571 | struct mmc_request *mrq, struct mmc_command *cmd) | ||
572 | { | ||
573 | long time; | ||
574 | int ret = 0, mask = 0; | ||
575 | u32 opc = cmd->opcode; | ||
576 | |||
577 | host->cmd = cmd; | ||
578 | |||
579 | switch (opc) { | ||
580 | /* respons busy check */ | ||
581 | case MMC_SWITCH: | ||
582 | case MMC_STOP_TRANSMISSION: | ||
583 | case MMC_SET_WRITE_PROT: | ||
584 | case MMC_CLR_WRITE_PROT: | ||
585 | case MMC_ERASE: | ||
586 | case MMC_GEN_CMD: | ||
587 | mask = MASK_MRBSYE; | ||
588 | break; | ||
589 | default: | ||
590 | mask = MASK_MCRSPE; | ||
591 | break; | ||
592 | } | ||
593 | mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | | ||
594 | MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | | ||
595 | MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | | ||
596 | MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; | ||
597 | |||
598 | if (host->data) { | ||
599 | sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, 0); | ||
600 | sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, mrq->data->blksz); | ||
601 | } | ||
602 | opc = sh_mmcif_set_cmd(host, mrq, cmd, opc); | ||
603 | |||
604 | sh_mmcif_writel(host, MMCIF_CE_INT, 0xD80430C0); | ||
605 | sh_mmcif_writel(host, MMCIF_CE_INT_MASK, mask); | ||
606 | /* set arg */ | ||
607 | sh_mmcif_writel(host, MMCIF_CE_ARG, cmd->arg); | ||
608 | host->wait_int = 0; | ||
609 | /* set cmd */ | ||
610 | sh_mmcif_writel(host, MMCIF_CE_CMD_SET, opc); | ||
611 | |||
612 | time = wait_event_interruptible_timeout(host->intr_wait, | ||
613 | host->wait_int == 1 || host->sd_error == 1, host->timeout); | ||
614 | if (host->wait_int != 1 && time == 0) { | ||
615 | cmd->error = sh_mmcif_error_manage(host); | ||
616 | return; | ||
617 | } | ||
618 | if (host->sd_error) { | ||
619 | switch (cmd->opcode) { | ||
620 | case MMC_ALL_SEND_CID: | ||
621 | case MMC_SELECT_CARD: | ||
622 | case MMC_APP_CMD: | ||
623 | cmd->error = -ETIMEDOUT; | ||
624 | break; | ||
625 | default: | ||
626 | pr_debug("%s: Cmd(d'%d) err\n", | ||
627 | DRIVER_NAME, cmd->opcode); | ||
628 | cmd->error = sh_mmcif_error_manage(host); | ||
629 | break; | ||
630 | } | ||
631 | host->sd_error = 0; | ||
632 | host->wait_int = 0; | ||
633 | return; | ||
634 | } | ||
635 | if (!(cmd->flags & MMC_RSP_PRESENT)) { | ||
636 | cmd->error = ret; | ||
637 | host->wait_int = 0; | ||
638 | return; | ||
639 | } | ||
640 | if (host->wait_int == 1) { | ||
641 | sh_mmcif_get_response(host, cmd); | ||
642 | host->wait_int = 0; | ||
643 | } | ||
644 | if (host->data) { | ||
645 | ret = sh_mmcif_data_trans(host, mrq, cmd->opcode); | ||
646 | if (ret < 0) | ||
647 | mrq->data->bytes_xfered = 0; | ||
648 | else | ||
649 | mrq->data->bytes_xfered = | ||
650 | mrq->data->blocks * mrq->data->blksz; | ||
651 | } | ||
652 | cmd->error = ret; | ||
653 | } | ||
654 | |||
655 | static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, | ||
656 | struct mmc_request *mrq, struct mmc_command *cmd) | ||
657 | { | ||
658 | long time; | ||
659 | |||
660 | if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) | ||
661 | sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); | ||
662 | else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) | ||
663 | sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); | ||
664 | else { | ||
665 | pr_err(DRIVER_NAME": not support stop cmd\n"); | ||
666 | cmd->error = sh_mmcif_error_manage(host); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | time = wait_event_interruptible_timeout(host->intr_wait, | ||
671 | host->wait_int == 1 || | ||
672 | host->sd_error == 1, host->timeout); | ||
673 | if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) { | ||
674 | cmd->error = sh_mmcif_error_manage(host); | ||
675 | return; | ||
676 | } | ||
677 | sh_mmcif_get_cmd12response(host, cmd); | ||
678 | host->wait_int = 0; | ||
679 | cmd->error = 0; | ||
680 | } | ||
681 | |||
682 | static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) | ||
683 | { | ||
684 | struct sh_mmcif_host *host = mmc_priv(mmc); | ||
685 | |||
686 | switch (mrq->cmd->opcode) { | ||
687 | /* MMCIF does not support SD/SDIO command */ | ||
688 | case SD_IO_SEND_OP_COND: | ||
689 | case MMC_APP_CMD: | ||
690 | mrq->cmd->error = -ETIMEDOUT; | ||
691 | mmc_request_done(mmc, mrq); | ||
692 | return; | ||
693 | case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ | ||
694 | if (!mrq->data) { | ||
695 | /* send_if_cond cmd (not support) */ | ||
696 | mrq->cmd->error = -ETIMEDOUT; | ||
697 | mmc_request_done(mmc, mrq); | ||
698 | return; | ||
699 | } | ||
700 | break; | ||
701 | default: | ||
702 | break; | ||
703 | } | ||
704 | host->data = mrq->data; | ||
705 | sh_mmcif_start_cmd(host, mrq, mrq->cmd); | ||
706 | host->data = NULL; | ||
707 | |||
708 | if (mrq->cmd->error != 0) { | ||
709 | mmc_request_done(mmc, mrq); | ||
710 | return; | ||
711 | } | ||
712 | if (mrq->stop) | ||
713 | sh_mmcif_stop_cmd(host, mrq, mrq->stop); | ||
714 | mmc_request_done(mmc, mrq); | ||
715 | } | ||
716 | |||
717 | static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | ||
718 | { | ||
719 | struct sh_mmcif_host *host = mmc_priv(mmc); | ||
720 | struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; | ||
721 | |||
722 | if (ios->power_mode == MMC_POWER_OFF) { | ||
723 | /* clock stop */ | ||
724 | sh_mmcif_clock_control(host, 0); | ||
725 | if (p->down_pwr) | ||
726 | p->down_pwr(host->pd); | ||
727 | return; | ||
728 | } else if (ios->power_mode == MMC_POWER_UP) { | ||
729 | if (p->set_pwr) | ||
730 | p->set_pwr(host->pd, ios->power_mode); | ||
731 | } | ||
732 | |||
733 | if (ios->clock) | ||
734 | sh_mmcif_clock_control(host, ios->clock); | ||
735 | |||
736 | host->bus_width = ios->bus_width; | ||
737 | } | ||
738 | |||
739 | static struct mmc_host_ops sh_mmcif_ops = { | ||
740 | .request = sh_mmcif_request, | ||
741 | .set_ios = sh_mmcif_set_ios, | ||
742 | }; | ||
743 | |||
744 | static void sh_mmcif_detect(struct mmc_host *mmc) | ||
745 | { | ||
746 | mmc_detect_change(mmc, 0); | ||
747 | } | ||
748 | |||
749 | static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) | ||
750 | { | ||
751 | struct sh_mmcif_host *host = dev_id; | ||
752 | u32 state = 0; | ||
753 | int err = 0; | ||
754 | |||
755 | state = sh_mmcif_readl(host, MMCIF_CE_INT); | ||
756 | |||
757 | if (state & INT_RBSYE) { | ||
758 | sh_mmcif_writel(host, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE)); | ||
759 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); | ||
760 | } else if (state & INT_CRSPE) { | ||
761 | sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_CRSPE); | ||
762 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE); | ||
763 | } else if (state & INT_BUFREN) { | ||
764 | sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFREN); | ||
765 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); | ||
766 | } else if (state & INT_BUFWEN) { | ||
767 | sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFWEN); | ||
768 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); | ||
769 | } else if (state & INT_CMD12DRE) { | ||
770 | sh_mmcif_writel(host, MMCIF_CE_INT, | ||
771 | ~(INT_CMD12DRE | INT_CMD12RBE | | ||
772 | INT_CMD12CRE | INT_BUFRE)); | ||
773 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); | ||
774 | } else if (state & INT_BUFRE) { | ||
775 | sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFRE); | ||
776 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); | ||
777 | } else if (state & INT_DTRANE) { | ||
778 | sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_DTRANE); | ||
779 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); | ||
780 | } else if (state & INT_CMD12RBE) { | ||
781 | sh_mmcif_writel(host, MMCIF_CE_INT, | ||
782 | ~(INT_CMD12RBE | INT_CMD12CRE)); | ||
783 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); | ||
784 | } else if (state & INT_ERR_STS) { | ||
785 | /* err interrupts */ | ||
786 | sh_mmcif_writel(host, MMCIF_CE_INT, ~state); | ||
787 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); | ||
788 | err = 1; | ||
789 | } else { | ||
790 | pr_debug("%s: Not support int\n", DRIVER_NAME); | ||
791 | sh_mmcif_writel(host, MMCIF_CE_INT, ~state); | ||
792 | sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); | ||
793 | err = 1; | ||
794 | } | ||
795 | if (err) { | ||
796 | host->sd_error = 1; | ||
797 | pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state); | ||
798 | } | ||
799 | host->wait_int = 1; | ||
800 | wake_up(&host->intr_wait); | ||
801 | |||
802 | return IRQ_HANDLED; | ||
803 | } | ||
804 | |||
805 | static int __devinit sh_mmcif_probe(struct platform_device *pdev) | ||
806 | { | ||
807 | int ret = 0, irq[2]; | ||
808 | struct mmc_host *mmc; | ||
809 | struct sh_mmcif_host *host = NULL; | ||
810 | struct sh_mmcif_plat_data *pd = NULL; | ||
811 | struct resource *res; | ||
812 | void __iomem *reg; | ||
813 | char clk_name[8]; | ||
814 | |||
815 | irq[0] = platform_get_irq(pdev, 0); | ||
816 | irq[1] = platform_get_irq(pdev, 1); | ||
817 | if (irq[0] < 0 || irq[1] < 0) { | ||
818 | pr_err(DRIVER_NAME": Get irq error\n"); | ||
819 | return -ENXIO; | ||
820 | } | ||
821 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
822 | if (!res) { | ||
823 | dev_err(&pdev->dev, "platform_get_resource error.\n"); | ||
824 | return -ENXIO; | ||
825 | } | ||
826 | reg = ioremap(res->start, resource_size(res)); | ||
827 | if (!reg) { | ||
828 | dev_err(&pdev->dev, "ioremap error.\n"); | ||
829 | return -ENOMEM; | ||
830 | } | ||
831 | pd = (struct sh_mmcif_plat_data *)(pdev->dev.platform_data); | ||
832 | if (!pd) { | ||
833 | dev_err(&pdev->dev, "sh_mmcif plat data error.\n"); | ||
834 | ret = -ENXIO; | ||
835 | goto clean_up; | ||
836 | } | ||
837 | mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev); | ||
838 | if (!mmc) { | ||
839 | ret = -ENOMEM; | ||
840 | goto clean_up; | ||
841 | } | ||
842 | host = mmc_priv(mmc); | ||
843 | host->mmc = mmc; | ||
844 | host->addr = reg; | ||
845 | host->timeout = 1000; | ||
846 | |||
847 | snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); | ||
848 | host->hclk = clk_get(&pdev->dev, clk_name); | ||
849 | if (IS_ERR(host->hclk)) { | ||
850 | dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); | ||
851 | ret = PTR_ERR(host->hclk); | ||
852 | goto clean_up1; | ||
853 | } | ||
854 | clk_enable(host->hclk); | ||
855 | host->clk = clk_get_rate(host->hclk); | ||
856 | host->pd = pdev; | ||
857 | |||
858 | init_waitqueue_head(&host->intr_wait); | ||
859 | |||
860 | mmc->ops = &sh_mmcif_ops; | ||
861 | mmc->f_max = host->clk; | ||
862 | /* close to 400KHz */ | ||
863 | if (mmc->f_max < 51200000) | ||
864 | mmc->f_min = mmc->f_max / 128; | ||
865 | else if (mmc->f_max < 102400000) | ||
866 | mmc->f_min = mmc->f_max / 256; | ||
867 | else | ||
868 | mmc->f_min = mmc->f_max / 512; | ||
869 | if (pd->ocr) | ||
870 | mmc->ocr_avail = pd->ocr; | ||
871 | mmc->caps = MMC_CAP_MMC_HIGHSPEED; | ||
872 | if (pd->caps) | ||
873 | mmc->caps |= pd->caps; | ||
874 | mmc->max_phys_segs = 128; | ||
875 | mmc->max_hw_segs = 128; | ||
876 | mmc->max_blk_size = 512; | ||
877 | mmc->max_blk_count = 65535; | ||
878 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; | ||
879 | mmc->max_seg_size = mmc->max_req_size; | ||
880 | |||
881 | sh_mmcif_sync_reset(host); | ||
882 | platform_set_drvdata(pdev, host); | ||
883 | mmc_add_host(mmc); | ||
884 | |||
885 | ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host); | ||
886 | if (ret) { | ||
887 | pr_err(DRIVER_NAME": request_irq error (sh_mmc:error)\n"); | ||
888 | goto clean_up2; | ||
889 | } | ||
890 | ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host); | ||
891 | if (ret) { | ||
892 | free_irq(irq[0], host); | ||
893 | pr_err(DRIVER_NAME": request_irq error (sh_mmc:int)\n"); | ||
894 | goto clean_up2; | ||
895 | } | ||
896 | |||
897 | sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL); | ||
898 | sh_mmcif_detect(host->mmc); | ||
899 | |||
900 | pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION); | ||
901 | pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME, | ||
902 | sh_mmcif_readl(host, MMCIF_CE_VERSION) & 0x0000ffff); | ||
903 | return ret; | ||
904 | |||
905 | clean_up2: | ||
906 | clk_disable(host->hclk); | ||
907 | clean_up1: | ||
908 | mmc_free_host(mmc); | ||
909 | clean_up: | ||
910 | if (reg) | ||
911 | iounmap(reg); | ||
912 | return ret; | ||
913 | } | ||
914 | |||
915 | static int __devexit sh_mmcif_remove(struct platform_device *pdev) | ||
916 | { | ||
917 | struct sh_mmcif_host *host = platform_get_drvdata(pdev); | ||
918 | int irq[2]; | ||
919 | |||
920 | sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL); | ||
921 | |||
922 | irq[0] = platform_get_irq(pdev, 0); | ||
923 | irq[1] = platform_get_irq(pdev, 1); | ||
924 | |||
925 | if (host->addr) | ||
926 | iounmap(host->addr); | ||
927 | |||
928 | platform_set_drvdata(pdev, NULL); | ||
929 | mmc_remove_host(host->mmc); | ||
930 | |||
931 | free_irq(irq[0], host); | ||
932 | free_irq(irq[1], host); | ||
933 | |||
934 | clk_disable(host->hclk); | ||
935 | mmc_free_host(host->mmc); | ||
936 | |||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | static struct platform_driver sh_mmcif_driver = { | ||
941 | .probe = sh_mmcif_probe, | ||
942 | .remove = sh_mmcif_remove, | ||
943 | .driver = { | ||
944 | .name = DRIVER_NAME, | ||
945 | }, | ||
946 | }; | ||
947 | |||
948 | static int __init sh_mmcif_init(void) | ||
949 | { | ||
950 | return platform_driver_register(&sh_mmcif_driver); | ||
951 | } | ||
952 | |||
953 | static void __exit sh_mmcif_exit(void) | ||
954 | { | ||
955 | platform_driver_unregister(&sh_mmcif_driver); | ||
956 | } | ||
957 | |||
958 | module_init(sh_mmcif_init); | ||
959 | module_exit(sh_mmcif_exit); | ||
960 | |||
961 | |||
962 | MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver"); | ||
963 | MODULE_LICENSE("GPL"); | ||
964 | MODULE_ALIAS(DRIVER_NAME); | ||
965 | MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>"); | ||
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 82554ddec6b3..cec99958b652 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c | |||
@@ -1032,7 +1032,7 @@ static void tifm_sd_remove(struct tifm_dev *sock) | |||
1032 | 1032 | ||
1033 | static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) | 1033 | static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) |
1034 | { | 1034 | { |
1035 | return mmc_suspend_host(tifm_get_drvdata(sock), state); | 1035 | return mmc_suspend_host(tifm_get_drvdata(sock)); |
1036 | } | 1036 | } |
1037 | 1037 | ||
1038 | static int tifm_sd_resume(struct tifm_dev *sock) | 1038 | static int tifm_sd_resume(struct tifm_dev *sock) |
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 883fcac21004..ee7d0a5a51c4 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c | |||
@@ -768,7 +768,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) | |||
768 | struct mmc_host *mmc = platform_get_drvdata(dev); | 768 | struct mmc_host *mmc = platform_get_drvdata(dev); |
769 | int ret; | 769 | int ret; |
770 | 770 | ||
771 | ret = mmc_suspend_host(mmc, state); | 771 | ret = mmc_suspend_host(mmc); |
772 | 772 | ||
773 | /* Tell MFD core it can disable us now.*/ | 773 | /* Tell MFD core it can disable us now.*/ |
774 | if (!ret && cell->disable) | 774 | if (!ret && cell->disable) |
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 632858a94376..19f2d72dbca5 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c | |||
@@ -1280,7 +1280,7 @@ static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state) | |||
1280 | via_save_pcictrlreg(host); | 1280 | via_save_pcictrlreg(host); |
1281 | via_save_sdcreg(host); | 1281 | via_save_sdcreg(host); |
1282 | 1282 | ||
1283 | ret = mmc_suspend_host(host->mmc, state); | 1283 | ret = mmc_suspend_host(host->mmc); |
1284 | 1284 | ||
1285 | pci_save_state(pcidev); | 1285 | pci_save_state(pcidev); |
1286 | pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); | 1286 | pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); |
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 69efe01eece8..0012f5d13d28 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c | |||
@@ -1819,7 +1819,7 @@ static int wbsd_suspend(struct wbsd_host *host, pm_message_t state) | |||
1819 | { | 1819 | { |
1820 | BUG_ON(host == NULL); | 1820 | BUG_ON(host == NULL); |
1821 | 1821 | ||
1822 | return mmc_suspend_host(host->mmc, state); | 1822 | return mmc_suspend_host(host->mmc); |
1823 | } | 1823 | } |
1824 | 1824 | ||
1825 | static int wbsd_resume(struct wbsd_host *host) | 1825 | static int wbsd_resume(struct wbsd_host *host) |