diff options
Diffstat (limited to 'drivers/mmc/host/omap_hsmmc.c')
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 56d4499d4388..9a7a60aeb19e 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -85,12 +85,14 @@ | |||
85 | #define BRR_ENABLE (1 << 5) | 85 | #define BRR_ENABLE (1 << 5) |
86 | #define DTO_ENABLE (1 << 20) | 86 | #define DTO_ENABLE (1 << 20) |
87 | #define INIT_STREAM (1 << 1) | 87 | #define INIT_STREAM (1 << 1) |
88 | #define ACEN_ACMD12 (1 << 2) | ||
88 | #define DP_SELECT (1 << 21) | 89 | #define DP_SELECT (1 << 21) |
89 | #define DDIR (1 << 4) | 90 | #define DDIR (1 << 4) |
90 | #define DMA_EN 0x1 | 91 | #define DMA_EN 0x1 |
91 | #define MSBS (1 << 5) | 92 | #define MSBS (1 << 5) |
92 | #define BCE (1 << 1) | 93 | #define BCE (1 << 1) |
93 | #define FOUR_BIT (1 << 1) | 94 | #define FOUR_BIT (1 << 1) |
95 | #define DDR (1 << 19) | ||
94 | #define DW8 (1 << 5) | 96 | #define DW8 (1 << 5) |
95 | #define CC 0x1 | 97 | #define CC 0x1 |
96 | #define TC 0x02 | 98 | #define TC 0x02 |
@@ -115,6 +117,7 @@ | |||
115 | #define OMAP_MMC_MAX_CLOCK 52000000 | 117 | #define OMAP_MMC_MAX_CLOCK 52000000 |
116 | #define DRIVER_NAME "omap_hsmmc" | 118 | #define DRIVER_NAME "omap_hsmmc" |
117 | 119 | ||
120 | #define AUTO_CMD12 (1 << 0) /* Auto CMD12 support */ | ||
118 | /* | 121 | /* |
119 | * One controller can have multiple slots, like on some omap boards using | 122 | * One controller can have multiple slots, like on some omap boards using |
120 | * omap.c controller driver. Luckily this is not currently done on any known | 123 | * omap.c controller driver. Luckily this is not currently done on any known |
@@ -167,7 +170,6 @@ struct omap_hsmmc_host { | |||
167 | int use_dma, dma_ch; | 170 | int use_dma, dma_ch; |
168 | int dma_line_tx, dma_line_rx; | 171 | int dma_line_tx, dma_line_rx; |
169 | int slot_id; | 172 | int slot_id; |
170 | int got_dbclk; | ||
171 | int response_busy; | 173 | int response_busy; |
172 | int context_loss; | 174 | int context_loss; |
173 | int vdd; | 175 | int vdd; |
@@ -175,6 +177,7 @@ struct omap_hsmmc_host { | |||
175 | int reqs_blocked; | 177 | int reqs_blocked; |
176 | int use_reg; | 178 | int use_reg; |
177 | int req_in_progress; | 179 | int req_in_progress; |
180 | unsigned int flags; | ||
178 | struct omap_hsmmc_next next_data; | 181 | struct omap_hsmmc_next next_data; |
179 | 182 | ||
180 | struct omap_mmc_platform_data *pdata; | 183 | struct omap_mmc_platform_data *pdata; |
@@ -520,6 +523,10 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host) | |||
520 | u32 con; | 523 | u32 con; |
521 | 524 | ||
522 | con = OMAP_HSMMC_READ(host->base, CON); | 525 | con = OMAP_HSMMC_READ(host->base, CON); |
526 | if (ios->timing == MMC_TIMING_UHS_DDR50) | ||
527 | con |= DDR; /* configure in DDR mode */ | ||
528 | else | ||
529 | con &= ~DDR; | ||
523 | switch (ios->bus_width) { | 530 | switch (ios->bus_width) { |
524 | case MMC_BUS_WIDTH_8: | 531 | case MMC_BUS_WIDTH_8: |
525 | OMAP_HSMMC_WRITE(host->base, CON, con | DW8); | 532 | OMAP_HSMMC_WRITE(host->base, CON, con | DW8); |
@@ -766,6 +773,8 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, | |||
766 | cmdtype = 0x3; | 773 | cmdtype = 0x3; |
767 | 774 | ||
768 | cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22); | 775 | cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22); |
776 | if ((host->flags & AUTO_CMD12) && mmc_op_multi(cmd->opcode)) | ||
777 | cmdreg |= ACEN_ACMD12; | ||
769 | 778 | ||
770 | if (data) { | 779 | if (data) { |
771 | cmdreg |= DP_SELECT | MSBS | BCE; | 780 | cmdreg |= DP_SELECT | MSBS | BCE; |
@@ -796,11 +805,12 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data) | |||
796 | static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) | 805 | static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) |
797 | { | 806 | { |
798 | int dma_ch; | 807 | int dma_ch; |
808 | unsigned long flags; | ||
799 | 809 | ||
800 | spin_lock(&host->irq_lock); | 810 | spin_lock_irqsave(&host->irq_lock, flags); |
801 | host->req_in_progress = 0; | 811 | host->req_in_progress = 0; |
802 | dma_ch = host->dma_ch; | 812 | dma_ch = host->dma_ch; |
803 | spin_unlock(&host->irq_lock); | 813 | spin_unlock_irqrestore(&host->irq_lock, flags); |
804 | 814 | ||
805 | omap_hsmmc_disable_irq(host); | 815 | omap_hsmmc_disable_irq(host); |
806 | /* Do not complete the request if DMA is still in progress */ | 816 | /* Do not complete the request if DMA is still in progress */ |
@@ -837,11 +847,14 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data) | |||
837 | else | 847 | else |
838 | data->bytes_xfered = 0; | 848 | data->bytes_xfered = 0; |
839 | 849 | ||
840 | if (!data->stop) { | 850 | if (data->stop && ((!(host->flags & AUTO_CMD12)) || data->error)) { |
851 | omap_hsmmc_start_command(host, data->stop, NULL); | ||
852 | } else { | ||
853 | if (data->stop) | ||
854 | data->stop->resp[0] = OMAP_HSMMC_READ(host->base, | ||
855 | RSP76); | ||
841 | omap_hsmmc_request_done(host, data->mrq); | 856 | omap_hsmmc_request_done(host, data->mrq); |
842 | return; | ||
843 | } | 857 | } |
844 | omap_hsmmc_start_command(host, data->stop, NULL); | ||
845 | } | 858 | } |
846 | 859 | ||
847 | /* | 860 | /* |
@@ -874,13 +887,14 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) | |||
874 | static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) | 887 | static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) |
875 | { | 888 | { |
876 | int dma_ch; | 889 | int dma_ch; |
890 | unsigned long flags; | ||
877 | 891 | ||
878 | host->data->error = errno; | 892 | host->data->error = errno; |
879 | 893 | ||
880 | spin_lock(&host->irq_lock); | 894 | spin_lock_irqsave(&host->irq_lock, flags); |
881 | dma_ch = host->dma_ch; | 895 | dma_ch = host->dma_ch; |
882 | host->dma_ch = -1; | 896 | host->dma_ch = -1; |
883 | spin_unlock(&host->irq_lock); | 897 | spin_unlock_irqrestore(&host->irq_lock, flags); |
884 | 898 | ||
885 | if (host->use_dma && dma_ch != -1) { | 899 | if (host->use_dma && dma_ch != -1) { |
886 | dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, | 900 | dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, |
@@ -1082,7 +1096,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) | |||
1082 | 1096 | ||
1083 | /* Disable the clocks */ | 1097 | /* Disable the clocks */ |
1084 | pm_runtime_put_sync(host->dev); | 1098 | pm_runtime_put_sync(host->dev); |
1085 | if (host->got_dbclk) | 1099 | if (host->dbclk) |
1086 | clk_disable(host->dbclk); | 1100 | clk_disable(host->dbclk); |
1087 | 1101 | ||
1088 | /* Turn the power off */ | 1102 | /* Turn the power off */ |
@@ -1093,7 +1107,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) | |||
1093 | ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, | 1107 | ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, |
1094 | vdd); | 1108 | vdd); |
1095 | pm_runtime_get_sync(host->dev); | 1109 | pm_runtime_get_sync(host->dev); |
1096 | if (host->got_dbclk) | 1110 | if (host->dbclk) |
1097 | clk_enable(host->dbclk); | 1111 | clk_enable(host->dbclk); |
1098 | 1112 | ||
1099 | if (ret != 0) | 1113 | if (ret != 0) |
@@ -1234,6 +1248,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) | |||
1234 | struct omap_hsmmc_host *host = cb_data; | 1248 | struct omap_hsmmc_host *host = cb_data; |
1235 | struct mmc_data *data; | 1249 | struct mmc_data *data; |
1236 | int dma_ch, req_in_progress; | 1250 | int dma_ch, req_in_progress; |
1251 | unsigned long flags; | ||
1237 | 1252 | ||
1238 | if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { | 1253 | if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { |
1239 | dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n", | 1254 | dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n", |
@@ -1241,9 +1256,9 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) | |||
1241 | return; | 1256 | return; |
1242 | } | 1257 | } |
1243 | 1258 | ||
1244 | spin_lock(&host->irq_lock); | 1259 | spin_lock_irqsave(&host->irq_lock, flags); |
1245 | if (host->dma_ch < 0) { | 1260 | if (host->dma_ch < 0) { |
1246 | spin_unlock(&host->irq_lock); | 1261 | spin_unlock_irqrestore(&host->irq_lock, flags); |
1247 | return; | 1262 | return; |
1248 | } | 1263 | } |
1249 | 1264 | ||
@@ -1253,7 +1268,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) | |||
1253 | /* Fire up the next transfer. */ | 1268 | /* Fire up the next transfer. */ |
1254 | omap_hsmmc_config_dma_params(host, data, | 1269 | omap_hsmmc_config_dma_params(host, data, |
1255 | data->sg + host->dma_sg_idx); | 1270 | data->sg + host->dma_sg_idx); |
1256 | spin_unlock(&host->irq_lock); | 1271 | spin_unlock_irqrestore(&host->irq_lock, flags); |
1257 | return; | 1272 | return; |
1258 | } | 1273 | } |
1259 | 1274 | ||
@@ -1264,7 +1279,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) | |||
1264 | req_in_progress = host->req_in_progress; | 1279 | req_in_progress = host->req_in_progress; |
1265 | dma_ch = host->dma_ch; | 1280 | dma_ch = host->dma_ch; |
1266 | host->dma_ch = -1; | 1281 | host->dma_ch = -1; |
1267 | spin_unlock(&host->irq_lock); | 1282 | spin_unlock_irqrestore(&host->irq_lock, flags); |
1268 | 1283 | ||
1269 | omap_free_dma(dma_ch); | 1284 | omap_free_dma(dma_ch); |
1270 | 1285 | ||
@@ -1766,7 +1781,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) | |||
1766 | pdata->slots[0].nonremovable = true; | 1781 | pdata->slots[0].nonremovable = true; |
1767 | pdata->slots[0].no_regulator_off_init = true; | 1782 | pdata->slots[0].no_regulator_off_init = true; |
1768 | } | 1783 | } |
1769 | of_property_read_u32(np, "ti,bus-width", &bus_width); | 1784 | of_property_read_u32(np, "bus-width", &bus_width); |
1770 | if (bus_width == 4) | 1785 | if (bus_width == 4) |
1771 | pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA; | 1786 | pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA; |
1772 | else if (bus_width == 8) | 1787 | else if (bus_width == 8) |
@@ -1844,6 +1859,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) | |||
1844 | host->mapbase = res->start + pdata->reg_offset; | 1859 | host->mapbase = res->start + pdata->reg_offset; |
1845 | host->base = ioremap(host->mapbase, SZ_4K); | 1860 | host->base = ioremap(host->mapbase, SZ_4K); |
1846 | host->power_mode = MMC_POWER_OFF; | 1861 | host->power_mode = MMC_POWER_OFF; |
1862 | host->flags = AUTO_CMD12; | ||
1847 | host->next_data.cookie = 1; | 1863 | host->next_data.cookie = 1; |
1848 | 1864 | ||
1849 | platform_set_drvdata(pdev, host); | 1865 | platform_set_drvdata(pdev, host); |
@@ -1885,21 +1901,17 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) | |||
1885 | 1901 | ||
1886 | omap_hsmmc_context_save(host); | 1902 | omap_hsmmc_context_save(host); |
1887 | 1903 | ||
1888 | if (cpu_is_omap2430()) { | 1904 | host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); |
1889 | host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); | 1905 | /* |
1890 | /* | 1906 | * MMC can still work without debounce clock. |
1891 | * MMC can still work without debounce clock. | 1907 | */ |
1892 | */ | 1908 | if (IS_ERR(host->dbclk)) { |
1893 | if (IS_ERR(host->dbclk)) | 1909 | dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n"); |
1894 | dev_warn(mmc_dev(host->mmc), | 1910 | host->dbclk = NULL; |
1895 | "Failed to get debounce clock\n"); | 1911 | } else if (clk_enable(host->dbclk) != 0) { |
1896 | else | 1912 | dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n"); |
1897 | host->got_dbclk = 1; | 1913 | clk_put(host->dbclk); |
1898 | 1914 | host->dbclk = NULL; | |
1899 | if (host->got_dbclk) | ||
1900 | if (clk_enable(host->dbclk) != 0) | ||
1901 | dev_dbg(mmc_dev(host->mmc), "Enabling debounce" | ||
1902 | " clk failed\n"); | ||
1903 | } | 1915 | } |
1904 | 1916 | ||
1905 | /* Since we do only SG emulation, we can have as many segs | 1917 | /* Since we do only SG emulation, we can have as many segs |
@@ -1969,7 +1981,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) | |||
1969 | ret = request_threaded_irq(mmc_slot(host).card_detect_irq, | 1981 | ret = request_threaded_irq(mmc_slot(host).card_detect_irq, |
1970 | NULL, | 1982 | NULL, |
1971 | omap_hsmmc_detect, | 1983 | omap_hsmmc_detect, |
1972 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 1984 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
1973 | mmc_hostname(mmc), host); | 1985 | mmc_hostname(mmc), host); |
1974 | if (ret) { | 1986 | if (ret) { |
1975 | dev_dbg(mmc_dev(host->mmc), | 1987 | dev_dbg(mmc_dev(host->mmc), |
@@ -2019,7 +2031,7 @@ err_irq: | |||
2019 | pm_runtime_put_sync(host->dev); | 2031 | pm_runtime_put_sync(host->dev); |
2020 | pm_runtime_disable(host->dev); | 2032 | pm_runtime_disable(host->dev); |
2021 | clk_put(host->fclk); | 2033 | clk_put(host->fclk); |
2022 | if (host->got_dbclk) { | 2034 | if (host->dbclk) { |
2023 | clk_disable(host->dbclk); | 2035 | clk_disable(host->dbclk); |
2024 | clk_put(host->dbclk); | 2036 | clk_put(host->dbclk); |
2025 | } | 2037 | } |
@@ -2030,7 +2042,9 @@ err1: | |||
2030 | err_alloc: | 2042 | err_alloc: |
2031 | omap_hsmmc_gpio_free(pdata); | 2043 | omap_hsmmc_gpio_free(pdata); |
2032 | err: | 2044 | err: |
2033 | release_mem_region(res->start, resource_size(res)); | 2045 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
2046 | if (res) | ||
2047 | release_mem_region(res->start, resource_size(res)); | ||
2034 | return ret; | 2048 | return ret; |
2035 | } | 2049 | } |
2036 | 2050 | ||
@@ -2052,7 +2066,7 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev) | |||
2052 | pm_runtime_put_sync(host->dev); | 2066 | pm_runtime_put_sync(host->dev); |
2053 | pm_runtime_disable(host->dev); | 2067 | pm_runtime_disable(host->dev); |
2054 | clk_put(host->fclk); | 2068 | clk_put(host->fclk); |
2055 | if (host->got_dbclk) { | 2069 | if (host->dbclk) { |
2056 | clk_disable(host->dbclk); | 2070 | clk_disable(host->dbclk); |
2057 | clk_put(host->dbclk); | 2071 | clk_put(host->dbclk); |
2058 | } | 2072 | } |
@@ -2110,7 +2124,7 @@ static int omap_hsmmc_suspend(struct device *dev) | |||
2110 | OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); | 2124 | OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); |
2111 | } | 2125 | } |
2112 | 2126 | ||
2113 | if (host->got_dbclk) | 2127 | if (host->dbclk) |
2114 | clk_disable(host->dbclk); | 2128 | clk_disable(host->dbclk); |
2115 | err: | 2129 | err: |
2116 | pm_runtime_put_sync(host->dev); | 2130 | pm_runtime_put_sync(host->dev); |
@@ -2131,7 +2145,7 @@ static int omap_hsmmc_resume(struct device *dev) | |||
2131 | 2145 | ||
2132 | pm_runtime_get_sync(host->dev); | 2146 | pm_runtime_get_sync(host->dev); |
2133 | 2147 | ||
2134 | if (host->got_dbclk) | 2148 | if (host->dbclk) |
2135 | clk_enable(host->dbclk); | 2149 | clk_enable(host->dbclk); |
2136 | 2150 | ||
2137 | if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) | 2151 | if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) |