diff options
Diffstat (limited to 'drivers/mmc/host')
| -rw-r--r-- | drivers/mmc/host/atmel-mci-regs.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/atmel-mci.c | 55 | ||||
| -rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 181 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-dove.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-s3c.c | 159 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/host/sh_mmcif.c | 13 |
8 files changed, 250 insertions, 171 deletions
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index 000b3ad0f5ca..787aba1682bb 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | # define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ | 31 | # define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ |
| 32 | # define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ | 32 | # define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ |
| 33 | # define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ | 33 | # define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ |
| 34 | # define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ | ||
| 34 | #define ATMCI_DTOR 0x0008 /* Data Timeout */ | 35 | #define ATMCI_DTOR 0x0008 /* Data Timeout */ |
| 35 | # define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ | 36 | # define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ |
| 36 | # define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ | 37 | # define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ |
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 9819dc09ce08..e94476beca18 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
| @@ -77,6 +77,7 @@ struct atmel_mci_caps { | |||
| 77 | bool has_cstor_reg; | 77 | bool has_cstor_reg; |
| 78 | bool has_highspeed; | 78 | bool has_highspeed; |
| 79 | bool has_rwproof; | 79 | bool has_rwproof; |
| 80 | bool has_odd_clk_div; | ||
| 80 | }; | 81 | }; |
| 81 | 82 | ||
| 82 | struct atmel_mci_dma { | 83 | struct atmel_mci_dma { |
| @@ -482,7 +483,14 @@ err: | |||
| 482 | static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, | 483 | static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, |
| 483 | unsigned int ns) | 484 | unsigned int ns) |
| 484 | { | 485 | { |
| 485 | return (ns * (host->bus_hz / 1000000) + 999) / 1000; | 486 | /* |
| 487 | * It is easier here to use us instead of ns for the timeout, | ||
| 488 | * it prevents from overflows during calculation. | ||
| 489 | */ | ||
| 490 | unsigned int us = DIV_ROUND_UP(ns, 1000); | ||
| 491 | |||
| 492 | /* Maximum clock frequency is host->bus_hz/2 */ | ||
| 493 | return us * (DIV_ROUND_UP(host->bus_hz, 2000000)); | ||
| 486 | } | 494 | } |
| 487 | 495 | ||
| 488 | static void atmci_set_timeout(struct atmel_mci *host, | 496 | static void atmci_set_timeout(struct atmel_mci *host, |
| @@ -1127,16 +1135,27 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1127 | } | 1135 | } |
| 1128 | 1136 | ||
| 1129 | /* Calculate clock divider */ | 1137 | /* Calculate clock divider */ |
| 1130 | clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; | 1138 | if (host->caps.has_odd_clk_div) { |
| 1131 | if (clkdiv > 255) { | 1139 | clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; |
| 1132 | dev_warn(&mmc->class_dev, | 1140 | if (clkdiv > 511) { |
| 1133 | "clock %u too slow; using %lu\n", | 1141 | dev_warn(&mmc->class_dev, |
| 1134 | clock_min, host->bus_hz / (2 * 256)); | 1142 | "clock %u too slow; using %lu\n", |
| 1135 | clkdiv = 255; | 1143 | clock_min, host->bus_hz / (511 + 2)); |
| 1144 | clkdiv = 511; | ||
| 1145 | } | ||
| 1146 | host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1) | ||
| 1147 | | ATMCI_MR_CLKODD(clkdiv & 1); | ||
| 1148 | } else { | ||
| 1149 | clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; | ||
| 1150 | if (clkdiv > 255) { | ||
| 1151 | dev_warn(&mmc->class_dev, | ||
| 1152 | "clock %u too slow; using %lu\n", | ||
| 1153 | clock_min, host->bus_hz / (2 * 256)); | ||
| 1154 | clkdiv = 255; | ||
| 1155 | } | ||
| 1156 | host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); | ||
| 1136 | } | 1157 | } |
| 1137 | 1158 | ||
| 1138 | host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); | ||
| 1139 | |||
| 1140 | /* | 1159 | /* |
| 1141 | * WRPROOF and RDPROOF prevent overruns/underruns by | 1160 | * WRPROOF and RDPROOF prevent overruns/underruns by |
| 1142 | * stopping the clock when the FIFO is full/empty. | 1161 | * stopping the clock when the FIFO is full/empty. |
| @@ -2007,35 +2026,35 @@ static void __init atmci_get_cap(struct atmel_mci *host) | |||
| 2007 | "version: 0x%x\n", version); | 2026 | "version: 0x%x\n", version); |
| 2008 | 2027 | ||
| 2009 | host->caps.has_dma = 0; | 2028 | host->caps.has_dma = 0; |
| 2010 | host->caps.has_pdc = 0; | 2029 | host->caps.has_pdc = 1; |
| 2011 | host->caps.has_cfg_reg = 0; | 2030 | host->caps.has_cfg_reg = 0; |
| 2012 | host->caps.has_cstor_reg = 0; | 2031 | host->caps.has_cstor_reg = 0; |
| 2013 | host->caps.has_highspeed = 0; | 2032 | host->caps.has_highspeed = 0; |
| 2014 | host->caps.has_rwproof = 0; | 2033 | host->caps.has_rwproof = 0; |
| 2034 | host->caps.has_odd_clk_div = 0; | ||
| 2015 | 2035 | ||
| 2016 | /* keep only major version number */ | 2036 | /* keep only major version number */ |
| 2017 | switch (version & 0xf00) { | 2037 | switch (version & 0xf00) { |
| 2018 | case 0x100: | ||
| 2019 | case 0x200: | ||
| 2020 | host->caps.has_pdc = 1; | ||
| 2021 | host->caps.has_rwproof = 1; | ||
| 2022 | break; | ||
| 2023 | case 0x300: | ||
| 2024 | case 0x400: | ||
| 2025 | case 0x500: | 2038 | case 0x500: |
| 2039 | host->caps.has_odd_clk_div = 1; | ||
| 2040 | case 0x400: | ||
| 2041 | case 0x300: | ||
| 2026 | #ifdef CONFIG_AT_HDMAC | 2042 | #ifdef CONFIG_AT_HDMAC |
| 2027 | host->caps.has_dma = 1; | 2043 | host->caps.has_dma = 1; |
| 2028 | #else | 2044 | #else |
| 2029 | host->caps.has_dma = 0; | ||
| 2030 | dev_info(&host->pdev->dev, | 2045 | dev_info(&host->pdev->dev, |
| 2031 | "has dma capability but dma engine is not selected, then use pio\n"); | 2046 | "has dma capability but dma engine is not selected, then use pio\n"); |
| 2032 | #endif | 2047 | #endif |
| 2048 | host->caps.has_pdc = 0; | ||
| 2033 | host->caps.has_cfg_reg = 1; | 2049 | host->caps.has_cfg_reg = 1; |
| 2034 | host->caps.has_cstor_reg = 1; | 2050 | host->caps.has_cstor_reg = 1; |
| 2035 | host->caps.has_highspeed = 1; | 2051 | host->caps.has_highspeed = 1; |
| 2052 | case 0x200: | ||
| 2036 | host->caps.has_rwproof = 1; | 2053 | host->caps.has_rwproof = 1; |
| 2054 | case 0x100: | ||
| 2037 | break; | 2055 | break; |
| 2038 | default: | 2056 | default: |
| 2057 | host->caps.has_pdc = 0; | ||
| 2039 | dev_warn(&host->pdev->dev, | 2058 | dev_warn(&host->pdev->dev, |
| 2040 | "Unmanaged mci version, set minimum capabilities\n"); | 2059 | "Unmanaged mci version, set minimum capabilities\n"); |
| 2041 | break; | 2060 | break; |
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 47adb161d3ad..5c2b1c10af9c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
| @@ -1785,7 +1785,7 @@ static inline struct omap_mmc_platform_data | |||
| 1785 | } | 1785 | } |
| 1786 | #endif | 1786 | #endif |
| 1787 | 1787 | ||
| 1788 | static int __init omap_hsmmc_probe(struct platform_device *pdev) | 1788 | static int __devinit omap_hsmmc_probe(struct platform_device *pdev) |
| 1789 | { | 1789 | { |
| 1790 | struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; | 1790 | struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; |
| 1791 | struct mmc_host *mmc; | 1791 | struct mmc_host *mmc; |
| @@ -1818,8 +1818,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
| 1818 | if (res == NULL || irq < 0) | 1818 | if (res == NULL || irq < 0) |
| 1819 | return -ENXIO; | 1819 | return -ENXIO; |
| 1820 | 1820 | ||
| 1821 | res->start += pdata->reg_offset; | ||
| 1822 | res->end += pdata->reg_offset; | ||
| 1823 | res = request_mem_region(res->start, resource_size(res), pdev->name); | 1821 | res = request_mem_region(res->start, resource_size(res), pdev->name); |
| 1824 | if (res == NULL) | 1822 | if (res == NULL) |
| 1825 | return -EBUSY; | 1823 | return -EBUSY; |
| @@ -1843,7 +1841,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
| 1843 | host->dma_ch = -1; | 1841 | host->dma_ch = -1; |
| 1844 | host->irq = irq; | 1842 | host->irq = irq; |
| 1845 | host->slot_id = 0; | 1843 | host->slot_id = 0; |
| 1846 | host->mapbase = res->start; | 1844 | host->mapbase = res->start + pdata->reg_offset; |
| 1847 | host->base = ioremap(host->mapbase, SZ_4K); | 1845 | host->base = ioremap(host->mapbase, SZ_4K); |
| 1848 | host->power_mode = MMC_POWER_OFF; | 1846 | host->power_mode = MMC_POWER_OFF; |
| 1849 | host->next_data.cookie = 1; | 1847 | host->next_data.cookie = 1; |
| @@ -1875,8 +1873,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
| 1875 | goto err1; | 1873 | goto err1; |
| 1876 | } | 1874 | } |
| 1877 | 1875 | ||
| 1878 | omap_hsmmc_context_save(host); | ||
| 1879 | |||
| 1880 | if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { | 1876 | if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { |
| 1881 | dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); | 1877 | dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); |
| 1882 | mmc->caps2 |= MMC_CAP2_NO_MULTI_READ; | 1878 | mmc->caps2 |= MMC_CAP2_NO_MULTI_READ; |
| @@ -1887,6 +1883,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
| 1887 | pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY); | 1883 | pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY); |
| 1888 | pm_runtime_use_autosuspend(host->dev); | 1884 | pm_runtime_use_autosuspend(host->dev); |
| 1889 | 1885 | ||
| 1886 | omap_hsmmc_context_save(host); | ||
| 1887 | |||
| 1890 | if (cpu_is_omap2430()) { | 1888 | if (cpu_is_omap2430()) { |
| 1891 | host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); | 1889 | host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); |
| 1892 | /* | 1890 | /* |
| @@ -2018,8 +2016,7 @@ err_reg: | |||
| 2018 | err_irq_cd_init: | 2016 | err_irq_cd_init: |
| 2019 | free_irq(host->irq, host); | 2017 | free_irq(host->irq, host); |
| 2020 | err_irq: | 2018 | err_irq: |
| 2021 | pm_runtime_mark_last_busy(host->dev); | 2019 | pm_runtime_put_sync(host->dev); |
| 2022 | pm_runtime_put_autosuspend(host->dev); | ||
| 2023 | pm_runtime_disable(host->dev); | 2020 | pm_runtime_disable(host->dev); |
| 2024 | clk_put(host->fclk); | 2021 | clk_put(host->fclk); |
| 2025 | if (host->got_dbclk) { | 2022 | if (host->got_dbclk) { |
| @@ -2037,35 +2034,33 @@ err: | |||
| 2037 | return ret; | 2034 | return ret; |
| 2038 | } | 2035 | } |
| 2039 | 2036 | ||
| 2040 | static int omap_hsmmc_remove(struct platform_device *pdev) | 2037 | static int __devexit omap_hsmmc_remove(struct platform_device *pdev) |
| 2041 | { | 2038 | { |
| 2042 | struct omap_hsmmc_host *host = platform_get_drvdata(pdev); | 2039 | struct omap_hsmmc_host *host = platform_get_drvdata(pdev); |
| 2043 | struct resource *res; | 2040 | struct resource *res; |
| 2044 | 2041 | ||
| 2045 | if (host) { | 2042 | pm_runtime_get_sync(host->dev); |
| 2046 | pm_runtime_get_sync(host->dev); | 2043 | mmc_remove_host(host->mmc); |
| 2047 | mmc_remove_host(host->mmc); | 2044 | if (host->use_reg) |
| 2048 | if (host->use_reg) | 2045 | omap_hsmmc_reg_put(host); |
| 2049 | omap_hsmmc_reg_put(host); | 2046 | if (host->pdata->cleanup) |
| 2050 | if (host->pdata->cleanup) | 2047 | host->pdata->cleanup(&pdev->dev); |
| 2051 | host->pdata->cleanup(&pdev->dev); | 2048 | free_irq(host->irq, host); |
| 2052 | free_irq(host->irq, host); | 2049 | if (mmc_slot(host).card_detect_irq) |
| 2053 | if (mmc_slot(host).card_detect_irq) | 2050 | free_irq(mmc_slot(host).card_detect_irq, host); |
| 2054 | free_irq(mmc_slot(host).card_detect_irq, host); | ||
| 2055 | |||
| 2056 | pm_runtime_put_sync(host->dev); | ||
| 2057 | pm_runtime_disable(host->dev); | ||
| 2058 | clk_put(host->fclk); | ||
| 2059 | if (host->got_dbclk) { | ||
| 2060 | clk_disable(host->dbclk); | ||
| 2061 | clk_put(host->dbclk); | ||
| 2062 | } | ||
| 2063 | 2051 | ||
| 2064 | mmc_free_host(host->mmc); | 2052 | pm_runtime_put_sync(host->dev); |
| 2065 | iounmap(host->base); | 2053 | pm_runtime_disable(host->dev); |
| 2066 | omap_hsmmc_gpio_free(pdev->dev.platform_data); | 2054 | clk_put(host->fclk); |
| 2055 | if (host->got_dbclk) { | ||
| 2056 | clk_disable(host->dbclk); | ||
| 2057 | clk_put(host->dbclk); | ||
| 2067 | } | 2058 | } |
| 2068 | 2059 | ||
| 2060 | mmc_free_host(host->mmc); | ||
| 2061 | iounmap(host->base); | ||
| 2062 | omap_hsmmc_gpio_free(pdev->dev.platform_data); | ||
| 2063 | |||
| 2069 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2064 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 2070 | if (res) | 2065 | if (res) |
| 2071 | release_mem_region(res->start, resource_size(res)); | 2066 | release_mem_region(res->start, resource_size(res)); |
| @@ -2078,49 +2073,45 @@ static int omap_hsmmc_remove(struct platform_device *pdev) | |||
| 2078 | static int omap_hsmmc_suspend(struct device *dev) | 2073 | static int omap_hsmmc_suspend(struct device *dev) |
| 2079 | { | 2074 | { |
| 2080 | int ret = 0; | 2075 | int ret = 0; |
| 2081 | struct platform_device *pdev = to_platform_device(dev); | 2076 | struct omap_hsmmc_host *host = dev_get_drvdata(dev); |
| 2082 | struct omap_hsmmc_host *host = platform_get_drvdata(pdev); | ||
| 2083 | 2077 | ||
| 2084 | if (host && host->suspended) | 2078 | if (!host) |
| 2085 | return 0; | 2079 | return 0; |
| 2086 | 2080 | ||
| 2087 | if (host) { | 2081 | if (host && host->suspended) |
| 2088 | pm_runtime_get_sync(host->dev); | 2082 | return 0; |
| 2089 | host->suspended = 1; | ||
| 2090 | if (host->pdata->suspend) { | ||
| 2091 | ret = host->pdata->suspend(&pdev->dev, | ||
| 2092 | host->slot_id); | ||
| 2093 | if (ret) { | ||
| 2094 | dev_dbg(mmc_dev(host->mmc), | ||
| 2095 | "Unable to handle MMC board" | ||
| 2096 | " level suspend\n"); | ||
| 2097 | host->suspended = 0; | ||
| 2098 | return ret; | ||
| 2099 | } | ||
| 2100 | } | ||
| 2101 | ret = mmc_suspend_host(host->mmc); | ||
| 2102 | 2083 | ||
| 2084 | pm_runtime_get_sync(host->dev); | ||
| 2085 | host->suspended = 1; | ||
| 2086 | if (host->pdata->suspend) { | ||
| 2087 | ret = host->pdata->suspend(dev, host->slot_id); | ||
| 2103 | if (ret) { | 2088 | if (ret) { |
| 2089 | dev_dbg(dev, "Unable to handle MMC board" | ||
| 2090 | " level suspend\n"); | ||
| 2104 | host->suspended = 0; | 2091 | host->suspended = 0; |
| 2105 | if (host->pdata->resume) { | 2092 | return ret; |
| 2106 | ret = host->pdata->resume(&pdev->dev, | ||
| 2107 | host->slot_id); | ||
| 2108 | if (ret) | ||
| 2109 | dev_dbg(mmc_dev(host->mmc), | ||
| 2110 | "Unmask interrupt failed\n"); | ||
| 2111 | } | ||
| 2112 | goto err; | ||
| 2113 | } | 2093 | } |
| 2094 | } | ||
| 2095 | ret = mmc_suspend_host(host->mmc); | ||
| 2114 | 2096 | ||
| 2115 | if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { | 2097 | if (ret) { |
| 2116 | omap_hsmmc_disable_irq(host); | 2098 | host->suspended = 0; |
| 2117 | OMAP_HSMMC_WRITE(host->base, HCTL, | 2099 | if (host->pdata->resume) { |
| 2118 | OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); | 2100 | ret = host->pdata->resume(dev, host->slot_id); |
| 2101 | if (ret) | ||
| 2102 | dev_dbg(dev, "Unmask interrupt failed\n"); | ||
| 2119 | } | 2103 | } |
| 2120 | if (host->got_dbclk) | 2104 | goto err; |
| 2121 | clk_disable(host->dbclk); | 2105 | } |
| 2122 | 2106 | ||
| 2107 | if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { | ||
| 2108 | omap_hsmmc_disable_irq(host); | ||
| 2109 | OMAP_HSMMC_WRITE(host->base, HCTL, | ||
| 2110 | OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); | ||
| 2123 | } | 2111 | } |
| 2112 | |||
| 2113 | if (host->got_dbclk) | ||
| 2114 | clk_disable(host->dbclk); | ||
| 2124 | err: | 2115 | err: |
| 2125 | pm_runtime_put_sync(host->dev); | 2116 | pm_runtime_put_sync(host->dev); |
| 2126 | return ret; | 2117 | return ret; |
| @@ -2130,38 +2121,37 @@ err: | |||
| 2130 | static int omap_hsmmc_resume(struct device *dev) | 2121 | static int omap_hsmmc_resume(struct device *dev) |
| 2131 | { | 2122 | { |
| 2132 | int ret = 0; | 2123 | int ret = 0; |
| 2133 | struct platform_device *pdev = to_platform_device(dev); | 2124 | struct omap_hsmmc_host *host = dev_get_drvdata(dev); |
| 2134 | struct omap_hsmmc_host *host = platform_get_drvdata(pdev); | 2125 | |
| 2126 | if (!host) | ||
| 2127 | return 0; | ||
| 2135 | 2128 | ||
| 2136 | if (host && !host->suspended) | 2129 | if (host && !host->suspended) |
| 2137 | return 0; | 2130 | return 0; |
| 2138 | 2131 | ||
| 2139 | if (host) { | 2132 | pm_runtime_get_sync(host->dev); |
| 2140 | pm_runtime_get_sync(host->dev); | ||
| 2141 | 2133 | ||
| 2142 | if (host->got_dbclk) | 2134 | if (host->got_dbclk) |
| 2143 | clk_enable(host->dbclk); | 2135 | clk_enable(host->dbclk); |
| 2144 | 2136 | ||
| 2145 | if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) | 2137 | if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) |
| 2146 | omap_hsmmc_conf_bus_power(host); | 2138 | omap_hsmmc_conf_bus_power(host); |
| 2147 | 2139 | ||
| 2148 | if (host->pdata->resume) { | 2140 | if (host->pdata->resume) { |
| 2149 | ret = host->pdata->resume(&pdev->dev, host->slot_id); | 2141 | ret = host->pdata->resume(dev, host->slot_id); |
| 2150 | if (ret) | 2142 | if (ret) |
| 2151 | dev_dbg(mmc_dev(host->mmc), | 2143 | dev_dbg(dev, "Unmask interrupt failed\n"); |
| 2152 | "Unmask interrupt failed\n"); | 2144 | } |
| 2153 | } | ||
| 2154 | 2145 | ||
| 2155 | omap_hsmmc_protect_card(host); | 2146 | omap_hsmmc_protect_card(host); |
| 2156 | 2147 | ||
| 2157 | /* Notify the core to resume the host */ | 2148 | /* Notify the core to resume the host */ |
| 2158 | ret = mmc_resume_host(host->mmc); | 2149 | ret = mmc_resume_host(host->mmc); |
| 2159 | if (ret == 0) | 2150 | if (ret == 0) |
| 2160 | host->suspended = 0; | 2151 | host->suspended = 0; |
| 2161 | 2152 | ||
| 2162 | pm_runtime_mark_last_busy(host->dev); | 2153 | pm_runtime_mark_last_busy(host->dev); |
| 2163 | pm_runtime_put_autosuspend(host->dev); | 2154 | pm_runtime_put_autosuspend(host->dev); |
| 2164 | } | ||
| 2165 | 2155 | ||
| 2166 | return ret; | 2156 | return ret; |
| 2167 | 2157 | ||
| @@ -2178,7 +2168,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev) | |||
| 2178 | 2168 | ||
| 2179 | host = platform_get_drvdata(to_platform_device(dev)); | 2169 | host = platform_get_drvdata(to_platform_device(dev)); |
| 2180 | omap_hsmmc_context_save(host); | 2170 | omap_hsmmc_context_save(host); |
| 2181 | dev_dbg(mmc_dev(host->mmc), "disabled\n"); | 2171 | dev_dbg(dev, "disabled\n"); |
| 2182 | 2172 | ||
| 2183 | return 0; | 2173 | return 0; |
| 2184 | } | 2174 | } |
| @@ -2189,7 +2179,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev) | |||
| 2189 | 2179 | ||
| 2190 | host = platform_get_drvdata(to_platform_device(dev)); | 2180 | host = platform_get_drvdata(to_platform_device(dev)); |
| 2191 | omap_hsmmc_context_restore(host); | 2181 | omap_hsmmc_context_restore(host); |
| 2192 | dev_dbg(mmc_dev(host->mmc), "enabled\n"); | 2182 | dev_dbg(dev, "enabled\n"); |
| 2193 | 2183 | ||
| 2194 | return 0; | 2184 | return 0; |
| 2195 | } | 2185 | } |
| @@ -2202,7 +2192,8 @@ static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { | |||
| 2202 | }; | 2192 | }; |
| 2203 | 2193 | ||
| 2204 | static struct platform_driver omap_hsmmc_driver = { | 2194 | static struct platform_driver omap_hsmmc_driver = { |
| 2205 | .remove = omap_hsmmc_remove, | 2195 | .probe = omap_hsmmc_probe, |
| 2196 | .remove = __devexit_p(omap_hsmmc_remove), | ||
| 2206 | .driver = { | 2197 | .driver = { |
| 2207 | .name = DRIVER_NAME, | 2198 | .name = DRIVER_NAME, |
| 2208 | .owner = THIS_MODULE, | 2199 | .owner = THIS_MODULE, |
| @@ -2211,21 +2202,7 @@ static struct platform_driver omap_hsmmc_driver = { | |||
| 2211 | }, | 2202 | }, |
| 2212 | }; | 2203 | }; |
| 2213 | 2204 | ||
| 2214 | static int __init omap_hsmmc_init(void) | 2205 | module_platform_driver(omap_hsmmc_driver); |
| 2215 | { | ||
| 2216 | /* Register the MMC driver */ | ||
| 2217 | return platform_driver_probe(&omap_hsmmc_driver, omap_hsmmc_probe); | ||
| 2218 | } | ||
| 2219 | |||
| 2220 | static void __exit omap_hsmmc_cleanup(void) | ||
| 2221 | { | ||
| 2222 | /* Unregister MMC driver */ | ||
| 2223 | platform_driver_unregister(&omap_hsmmc_driver); | ||
| 2224 | } | ||
| 2225 | |||
| 2226 | module_init(omap_hsmmc_init); | ||
| 2227 | module_exit(omap_hsmmc_cleanup); | ||
| 2228 | |||
| 2229 | MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver"); | 2206 | MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver"); |
| 2230 | MODULE_LICENSE("GPL"); | 2207 | MODULE_LICENSE("GPL"); |
| 2231 | MODULE_ALIAS("platform:" DRIVER_NAME); | 2208 | MODULE_ALIAS("platform:" DRIVER_NAME); |
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 46fd1fd1b605..177f697b5835 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
| 23 | #include <linux/module.h> | ||
| 23 | #include <linux/mmc/host.h> | 24 | #include <linux/mmc/host.h> |
| 24 | 25 | ||
| 25 | #include "sdhci-pltfm.h" | 26 | #include "sdhci-pltfm.h" |
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index fbbebe251e01..69ef0beae104 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c | |||
| @@ -1418,8 +1418,6 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, | |||
| 1418 | 1418 | ||
| 1419 | slots = chip->num_slots; /* Quirk may have changed this */ | 1419 | slots = chip->num_slots; /* Quirk may have changed this */ |
| 1420 | 1420 | ||
| 1421 | pci_enable_msi(pdev); | ||
| 1422 | |||
| 1423 | for (i = 0; i < slots; i++) { | 1421 | for (i = 0; i < slots; i++) { |
| 1424 | slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); | 1422 | slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); |
| 1425 | if (IS_ERR(slot)) { | 1423 | if (IS_ERR(slot)) { |
| @@ -1438,8 +1436,6 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, | |||
| 1438 | return 0; | 1436 | return 0; |
| 1439 | 1437 | ||
| 1440 | free: | 1438 | free: |
| 1441 | pci_disable_msi(pdev); | ||
| 1442 | |||
| 1443 | pci_set_drvdata(pdev, NULL); | 1439 | pci_set_drvdata(pdev, NULL); |
| 1444 | kfree(chip); | 1440 | kfree(chip); |
| 1445 | 1441 | ||
| @@ -1462,8 +1458,6 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev) | |||
| 1462 | for (i = 0; i < chip->num_slots; i++) | 1458 | for (i = 0; i < chip->num_slots; i++) |
| 1463 | sdhci_pci_remove_slot(chip->slots[i]); | 1459 | sdhci_pci_remove_slot(chip->slots[i]); |
| 1464 | 1460 | ||
| 1465 | pci_disable_msi(pdev); | ||
| 1466 | |||
| 1467 | pci_set_drvdata(pdev, NULL); | 1461 | pci_set_drvdata(pdev, NULL); |
| 1468 | kfree(chip); | 1462 | kfree(chip); |
| 1469 | } | 1463 | } |
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index b19e7d435f8d..55a164fcaa15 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c | |||
| @@ -20,6 +20,10 @@ | |||
| 20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
| 21 | #include <linux/gpio.h> | 21 | #include <linux/gpio.h> |
| 22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 23 | #include <linux/of.h> | ||
| 24 | #include <linux/of_gpio.h> | ||
| 25 | #include <linux/pm.h> | ||
| 26 | #include <linux/pm_runtime.h> | ||
| 23 | 27 | ||
| 24 | #include <linux/mmc/host.h> | 28 | #include <linux/mmc/host.h> |
| 25 | 29 | ||
| @@ -53,6 +57,18 @@ struct sdhci_s3c { | |||
| 53 | struct clk *clk_bus[MAX_BUS_CLK]; | 57 | struct clk *clk_bus[MAX_BUS_CLK]; |
| 54 | }; | 58 | }; |
| 55 | 59 | ||
| 60 | /** | ||
| 61 | * struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data | ||
| 62 | * @sdhci_quirks: sdhci host specific quirks. | ||
| 63 | * | ||
| 64 | * Specifies platform specific configuration of sdhci controller. | ||
| 65 | * Note: A structure for driver specific platform data is used for future | ||
| 66 | * expansion of its usage. | ||
| 67 | */ | ||
| 68 | struct sdhci_s3c_drv_data { | ||
| 69 | unsigned int sdhci_quirks; | ||
| 70 | }; | ||
| 71 | |||
| 56 | static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) | 72 | static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) |
| 57 | { | 73 | { |
| 58 | return sdhci_priv(host); | 74 | return sdhci_priv(host); |
| @@ -132,10 +148,10 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, | |||
| 132 | return UINT_MAX; | 148 | return UINT_MAX; |
| 133 | 149 | ||
| 134 | /* | 150 | /* |
| 135 | * Clock divider's step is different as 1 from that of host controller | 151 | * If controller uses a non-standard clock division, find the best clock |
| 136 | * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL. | 152 | * speed possible with selected clock source and skip the division. |
| 137 | */ | 153 | */ |
| 138 | if (ourhost->pdata->clk_type) { | 154 | if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { |
| 139 | rate = clk_round_rate(clksrc, wanted); | 155 | rate = clk_round_rate(clksrc, wanted); |
| 140 | return wanted - rate; | 156 | return wanted - rate; |
| 141 | } | 157 | } |
| @@ -272,6 +288,8 @@ static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host) | |||
| 272 | static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) | 288 | static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) |
| 273 | { | 289 | { |
| 274 | struct sdhci_s3c *ourhost = to_s3c(host); | 290 | struct sdhci_s3c *ourhost = to_s3c(host); |
| 291 | unsigned long timeout; | ||
| 292 | u16 clk = 0; | ||
| 275 | 293 | ||
| 276 | /* don't bother if the clock is going off */ | 294 | /* don't bother if the clock is going off */ |
| 277 | if (clock == 0) | 295 | if (clock == 0) |
| @@ -282,6 +300,25 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) | |||
| 282 | clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); | 300 | clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); |
| 283 | 301 | ||
| 284 | host->clock = clock; | 302 | host->clock = clock; |
| 303 | |||
| 304 | clk = SDHCI_CLOCK_INT_EN; | ||
| 305 | sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); | ||
| 306 | |||
| 307 | /* Wait max 20 ms */ | ||
| 308 | timeout = 20; | ||
| 309 | while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) | ||
| 310 | & SDHCI_CLOCK_INT_STABLE)) { | ||
| 311 | if (timeout == 0) { | ||
| 312 | printk(KERN_ERR "%s: Internal clock never " | ||
| 313 | "stabilised.\n", mmc_hostname(host->mmc)); | ||
| 314 | return; | ||
| 315 | } | ||
| 316 | timeout--; | ||
| 317 | mdelay(1); | ||
| 318 | } | ||
| 319 | |||
| 320 | clk |= SDHCI_CLOCK_CARD_EN; | ||
| 321 | sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); | ||
| 285 | } | 322 | } |
| 286 | 323 | ||
| 287 | /** | 324 | /** |
| @@ -382,16 +419,24 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) | |||
| 382 | } | 419 | } |
| 383 | } | 420 | } |
| 384 | 421 | ||
| 422 | static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( | ||
| 423 | struct platform_device *pdev) | ||
| 424 | { | ||
| 425 | return (struct sdhci_s3c_drv_data *) | ||
| 426 | platform_get_device_id(pdev)->driver_data; | ||
| 427 | } | ||
| 428 | |||
| 385 | static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | 429 | static int __devinit sdhci_s3c_probe(struct platform_device *pdev) |
| 386 | { | 430 | { |
| 387 | struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; | 431 | struct s3c_sdhci_platdata *pdata; |
| 432 | struct sdhci_s3c_drv_data *drv_data; | ||
| 388 | struct device *dev = &pdev->dev; | 433 | struct device *dev = &pdev->dev; |
| 389 | struct sdhci_host *host; | 434 | struct sdhci_host *host; |
| 390 | struct sdhci_s3c *sc; | 435 | struct sdhci_s3c *sc; |
| 391 | struct resource *res; | 436 | struct resource *res; |
| 392 | int ret, irq, ptr, clks; | 437 | int ret, irq, ptr, clks; |
| 393 | 438 | ||
| 394 | if (!pdata) { | 439 | if (!pdev->dev.platform_data) { |
| 395 | dev_err(dev, "no device data specified\n"); | 440 | dev_err(dev, "no device data specified\n"); |
| 396 | return -ENOENT; | 441 | return -ENOENT; |
| 397 | } | 442 | } |
| @@ -402,18 +447,20 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
| 402 | return irq; | 447 | return irq; |
| 403 | } | 448 | } |
| 404 | 449 | ||
| 405 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 406 | if (!res) { | ||
| 407 | dev_err(dev, "no memory specified\n"); | ||
| 408 | return -ENOENT; | ||
| 409 | } | ||
| 410 | |||
| 411 | host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c)); | 450 | host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c)); |
| 412 | if (IS_ERR(host)) { | 451 | if (IS_ERR(host)) { |
| 413 | dev_err(dev, "sdhci_alloc_host() failed\n"); | 452 | dev_err(dev, "sdhci_alloc_host() failed\n"); |
| 414 | return PTR_ERR(host); | 453 | return PTR_ERR(host); |
| 415 | } | 454 | } |
| 416 | 455 | ||
| 456 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
| 457 | if (!pdata) { | ||
| 458 | ret = -ENOMEM; | ||
| 459 | goto err_io_clk; | ||
| 460 | } | ||
| 461 | memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); | ||
| 462 | |||
| 463 | drv_data = sdhci_s3c_get_driver_data(pdev); | ||
| 417 | sc = sdhci_priv(host); | 464 | sc = sdhci_priv(host); |
| 418 | 465 | ||
| 419 | sc->host = host; | 466 | sc->host = host; |
| @@ -464,15 +511,8 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
| 464 | goto err_no_busclks; | 511 | goto err_no_busclks; |
| 465 | } | 512 | } |
| 466 | 513 | ||
| 467 | sc->ioarea = request_mem_region(res->start, resource_size(res), | 514 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 468 | mmc_hostname(host->mmc)); | 515 | host->ioaddr = devm_request_and_ioremap(&pdev->dev, res); |
| 469 | if (!sc->ioarea) { | ||
| 470 | dev_err(dev, "failed to reserve register area\n"); | ||
| 471 | ret = -ENXIO; | ||
| 472 | goto err_req_regs; | ||
| 473 | } | ||
| 474 | |||
| 475 | host->ioaddr = ioremap_nocache(res->start, resource_size(res)); | ||
| 476 | if (!host->ioaddr) { | 516 | if (!host->ioaddr) { |
| 477 | dev_err(dev, "failed to map registers\n"); | 517 | dev_err(dev, "failed to map registers\n"); |
| 478 | ret = -ENXIO; | 518 | ret = -ENXIO; |
| @@ -491,6 +531,8 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
| 491 | /* Setup quirks for the controller */ | 531 | /* Setup quirks for the controller */ |
| 492 | host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; | 532 | host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; |
| 493 | host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; | 533 | host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; |
| 534 | if (drv_data) | ||
| 535 | host->quirks |= drv_data->sdhci_quirks; | ||
| 494 | 536 | ||
| 495 | #ifndef CONFIG_MMC_SDHCI_S3C_DMA | 537 | #ifndef CONFIG_MMC_SDHCI_S3C_DMA |
| 496 | 538 | ||
| @@ -518,6 +560,14 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
| 518 | if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT) | 560 | if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT) |
| 519 | host->mmc->caps = MMC_CAP_NONREMOVABLE; | 561 | host->mmc->caps = MMC_CAP_NONREMOVABLE; |
| 520 | 562 | ||
| 563 | switch (pdata->max_width) { | ||
| 564 | case 8: | ||
| 565 | host->mmc->caps |= MMC_CAP_8_BIT_DATA; | ||
| 566 | case 4: | ||
| 567 | host->mmc->caps |= MMC_CAP_4_BIT_DATA; | ||
| 568 | break; | ||
| 569 | } | ||
| 570 | |||
| 521 | if (pdata->pm_caps) | 571 | if (pdata->pm_caps) |
| 522 | host->mmc->pm_caps |= pdata->pm_caps; | 572 | host->mmc->pm_caps |= pdata->pm_caps; |
| 523 | 573 | ||
| @@ -531,7 +581,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
| 531 | * If controller does not have internal clock divider, | 581 | * If controller does not have internal clock divider, |
| 532 | * we can use overriding functions instead of default. | 582 | * we can use overriding functions instead of default. |
| 533 | */ | 583 | */ |
| 534 | if (pdata->clk_type) { | 584 | if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { |
| 535 | sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; | 585 | sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; |
| 536 | sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; | 586 | sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; |
| 537 | sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; | 587 | sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; |
| @@ -544,10 +594,17 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
| 544 | if (pdata->host_caps2) | 594 | if (pdata->host_caps2) |
| 545 | host->mmc->caps2 |= pdata->host_caps2; | 595 | host->mmc->caps2 |= pdata->host_caps2; |
| 546 | 596 | ||
| 597 | pm_runtime_enable(&pdev->dev); | ||
| 598 | pm_runtime_set_autosuspend_delay(&pdev->dev, 50); | ||
| 599 | pm_runtime_use_autosuspend(&pdev->dev); | ||
| 600 | pm_suspend_ignore_children(&pdev->dev, 1); | ||
| 601 | |||
| 547 | ret = sdhci_add_host(host); | 602 | ret = sdhci_add_host(host); |
| 548 | if (ret) { | 603 | if (ret) { |
| 549 | dev_err(dev, "sdhci_add_host() failed\n"); | 604 | dev_err(dev, "sdhci_add_host() failed\n"); |
| 550 | goto err_add_host; | 605 | pm_runtime_forbid(&pdev->dev); |
| 606 | pm_runtime_get_noresume(&pdev->dev); | ||
| 607 | goto err_req_regs; | ||
| 551 | } | 608 | } |
| 552 | 609 | ||
| 553 | /* The following two methods of card detection might call | 610 | /* The following two methods of card detection might call |
| @@ -561,10 +618,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
| 561 | 618 | ||
| 562 | return 0; | 619 | return 0; |
| 563 | 620 | ||
| 564 | err_add_host: | ||
| 565 | release_resource(sc->ioarea); | ||
| 566 | kfree(sc->ioarea); | ||
| 567 | |||
| 568 | err_req_regs: | 621 | err_req_regs: |
| 569 | for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { | 622 | for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { |
| 570 | if (sc->clk_bus[ptr]) { | 623 | if (sc->clk_bus[ptr]) { |
| @@ -601,6 +654,8 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) | |||
| 601 | 654 | ||
| 602 | sdhci_remove_host(host, 1); | 655 | sdhci_remove_host(host, 1); |
| 603 | 656 | ||
| 657 | pm_runtime_disable(&pdev->dev); | ||
| 658 | |||
| 604 | for (ptr = 0; ptr < 3; ptr++) { | 659 | for (ptr = 0; ptr < 3; ptr++) { |
| 605 | if (sc->clk_bus[ptr]) { | 660 | if (sc->clk_bus[ptr]) { |
| 606 | clk_disable(sc->clk_bus[ptr]); | 661 | clk_disable(sc->clk_bus[ptr]); |
| @@ -610,18 +665,13 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) | |||
| 610 | clk_disable(sc->clk_io); | 665 | clk_disable(sc->clk_io); |
| 611 | clk_put(sc->clk_io); | 666 | clk_put(sc->clk_io); |
| 612 | 667 | ||
| 613 | iounmap(host->ioaddr); | ||
| 614 | release_resource(sc->ioarea); | ||
| 615 | kfree(sc->ioarea); | ||
| 616 | |||
| 617 | sdhci_free_host(host); | 668 | sdhci_free_host(host); |
| 618 | platform_set_drvdata(pdev, NULL); | 669 | platform_set_drvdata(pdev, NULL); |
| 619 | 670 | ||
| 620 | return 0; | 671 | return 0; |
| 621 | } | 672 | } |
| 622 | 673 | ||
| 623 | #ifdef CONFIG_PM | 674 | #ifdef CONFIG_PM_SLEEP |
| 624 | |||
| 625 | static int sdhci_s3c_suspend(struct device *dev) | 675 | static int sdhci_s3c_suspend(struct device *dev) |
| 626 | { | 676 | { |
| 627 | struct sdhci_host *host = dev_get_drvdata(dev); | 677 | struct sdhci_host *host = dev_get_drvdata(dev); |
| @@ -635,10 +685,29 @@ static int sdhci_s3c_resume(struct device *dev) | |||
| 635 | 685 | ||
| 636 | return sdhci_resume_host(host); | 686 | return sdhci_resume_host(host); |
| 637 | } | 687 | } |
| 688 | #endif | ||
| 689 | |||
| 690 | #ifdef CONFIG_PM_RUNTIME | ||
| 691 | static int sdhci_s3c_runtime_suspend(struct device *dev) | ||
| 692 | { | ||
| 693 | struct sdhci_host *host = dev_get_drvdata(dev); | ||
| 694 | |||
| 695 | return sdhci_runtime_suspend_host(host); | ||
| 696 | } | ||
| 638 | 697 | ||
| 698 | static int sdhci_s3c_runtime_resume(struct device *dev) | ||
| 699 | { | ||
| 700 | struct sdhci_host *host = dev_get_drvdata(dev); | ||
| 701 | |||
| 702 | return sdhci_runtime_resume_host(host); | ||
| 703 | } | ||
| 704 | #endif | ||
| 705 | |||
| 706 | #ifdef CONFIG_PM | ||
| 639 | static const struct dev_pm_ops sdhci_s3c_pmops = { | 707 | static const struct dev_pm_ops sdhci_s3c_pmops = { |
| 640 | .suspend = sdhci_s3c_suspend, | 708 | SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume) |
| 641 | .resume = sdhci_s3c_resume, | 709 | SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume, |
| 710 | NULL) | ||
| 642 | }; | 711 | }; |
| 643 | 712 | ||
| 644 | #define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) | 713 | #define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) |
| @@ -647,9 +716,31 @@ static const struct dev_pm_ops sdhci_s3c_pmops = { | |||
| 647 | #define SDHCI_S3C_PMOPS NULL | 716 | #define SDHCI_S3C_PMOPS NULL |
| 648 | #endif | 717 | #endif |
| 649 | 718 | ||
| 719 | #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) | ||
| 720 | static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { | ||
| 721 | .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK, | ||
| 722 | }; | ||
| 723 | #define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data) | ||
| 724 | #else | ||
| 725 | #define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL) | ||
| 726 | #endif | ||
| 727 | |||
| 728 | static struct platform_device_id sdhci_s3c_driver_ids[] = { | ||
| 729 | { | ||
| 730 | .name = "s3c-sdhci", | ||
| 731 | .driver_data = (kernel_ulong_t)NULL, | ||
| 732 | }, { | ||
| 733 | .name = "exynos4-sdhci", | ||
| 734 | .driver_data = EXYNOS4_SDHCI_DRV_DATA, | ||
| 735 | }, | ||
| 736 | { } | ||
| 737 | }; | ||
| 738 | MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids); | ||
| 739 | |||
| 650 | static struct platform_driver sdhci_s3c_driver = { | 740 | static struct platform_driver sdhci_s3c_driver = { |
| 651 | .probe = sdhci_s3c_probe, | 741 | .probe = sdhci_s3c_probe, |
| 652 | .remove = __devexit_p(sdhci_s3c_remove), | 742 | .remove = __devexit_p(sdhci_s3c_remove), |
| 743 | .id_table = sdhci_s3c_driver_ids, | ||
| 653 | .driver = { | 744 | .driver = { |
| 654 | .owner = THIS_MODULE, | 745 | .owner = THIS_MODULE, |
| 655 | .name = "s3c-sdhci", | 746 | .name = "s3c-sdhci", |
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8262cadfdab7..9aa77f3f04a8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
| @@ -2782,8 +2782,9 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 2782 | mmc_card_is_removable(mmc)) | 2782 | mmc_card_is_removable(mmc)) |
| 2783 | mmc->caps |= MMC_CAP_NEEDS_POLL; | 2783 | mmc->caps |= MMC_CAP_NEEDS_POLL; |
| 2784 | 2784 | ||
| 2785 | /* UHS-I mode(s) supported by the host controller. */ | 2785 | /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ |
| 2786 | if (host->version >= SDHCI_SPEC_300) | 2786 | if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | |
| 2787 | SDHCI_SUPPORT_DDR50)) | ||
| 2787 | mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; | 2788 | mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; |
| 2788 | 2789 | ||
| 2789 | /* SDR104 supports also implies SDR50 support */ | 2790 | /* SDR104 supports also implies SDR50 support */ |
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index aafaf0b6eb1c..724b35e85a26 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c | |||
| @@ -454,7 +454,8 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) | |||
| 454 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); | 454 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); |
| 455 | else | 455 | else |
| 456 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & | 456 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & |
| 457 | ((fls(host->clk / clk) - 1) << 16)); | 457 | ((fls(DIV_ROUND_UP(host->clk, |
| 458 | clk) - 1) - 1) << 16)); | ||
| 458 | 459 | ||
| 459 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); | 460 | sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); |
| 460 | } | 461 | } |
| @@ -1297,14 +1298,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) | |||
| 1297 | spin_lock_init(&host->lock); | 1298 | spin_lock_init(&host->lock); |
| 1298 | 1299 | ||
| 1299 | mmc->ops = &sh_mmcif_ops; | 1300 | mmc->ops = &sh_mmcif_ops; |
| 1300 | mmc->f_max = host->clk; | 1301 | mmc->f_max = host->clk / 2; |
| 1301 | /* close to 400KHz */ | 1302 | mmc->f_min = host->clk / 512; |
| 1302 | if (mmc->f_max < 51200000) | ||
| 1303 | mmc->f_min = mmc->f_max / 128; | ||
| 1304 | else if (mmc->f_max < 102400000) | ||
| 1305 | mmc->f_min = mmc->f_max / 256; | ||
| 1306 | else | ||
| 1307 | mmc->f_min = mmc->f_max / 512; | ||
| 1308 | if (pd->ocr) | 1303 | if (pd->ocr) |
| 1309 | mmc->ocr_avail = pd->ocr; | 1304 | mmc->ocr_avail = pd->ocr; |
| 1310 | mmc->caps = MMC_CAP_MMC_HIGHSPEED; | 1305 | mmc->caps = MMC_CAP_MMC_HIGHSPEED; |
