diff options
author | Olof Johansson <olof@lixom.net> | 2012-05-13 01:33:24 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-05-13 01:33:24 -0400 |
commit | e29402edf848359d619ce06af86d61e62c292c87 (patch) | |
tree | 94451c1d400d478654e0d0e78564e882081b806c /drivers/mmc | |
parent | bf98a6eaa9964fef49f186834713bfc57d16ede1 (diff) | |
parent | 530f1d416091212243b341e0022b2967886b30e4 (diff) |
Merge branch 'mxs/dt/for-3.5' of git://git.linaro.org/people/shawnguo/linux-2.6 into next/dt2
* 'mxs/dt/for-3.5' of git://git.linaro.org/people/shawnguo/linux-2.6: (51 commits)
ARM: dts: enable audio support for imx28-evk
ARM: dts: enable i2c device for imx28-evk
i2c: mxs: add device tree probe support
ARM: dts: enable mmc for imx28-evk
ARM: dts: enable mmc for imx23-evk
mmc: mxs-mmc: add device tree support
mmc: mxs-mmc: copy wp_gpio in struct mxs_mmc_host
mmc: mxs-mmc: have dma_channel than dma_res in mxs_mmc_host
mmc: mxs-mmc: use devm_* helper to make cleanup simpler
mmc: mxs-mmc: move header from mach into linux folder
mmc: mxs-mmc: get rid of the use of cpu_is_xxx
mmc: mxs-mmc: let ssp_is_old take host as parameter
mmc: mxs-mmc: use global stmp_device functionality
ARM: mxs: add gpio support for device tree boot
gpio/mxs: add device tree probe
gpio/mxs: get rid of the use of cpu_is_xxx
gpio/mxs: use devm_* helpers to make error handling simple
ARM: mxs: add mxs-dma dt support
ARM: mxs: do not add dma device by default
dma: mxs-dma: add device tree probe support
...
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/mxs-mmc.c | 203 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 9 |
2 files changed, 127 insertions, 85 deletions
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index e3f5af96ab87..34a90266ab11 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c | |||
@@ -23,6 +23,9 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <linux/of.h> | ||
27 | #include <linux/of_device.h> | ||
28 | #include <linux/of_gpio.h> | ||
26 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
27 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
28 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
@@ -39,18 +42,16 @@ | |||
39 | #include <linux/regulator/consumer.h> | 42 | #include <linux/regulator/consumer.h> |
40 | #include <linux/module.h> | 43 | #include <linux/module.h> |
41 | #include <linux/fsl/mxs-dma.h> | 44 | #include <linux/fsl/mxs-dma.h> |
42 | 45 | #include <linux/pinctrl/consumer.h> | |
43 | #include <mach/mxs.h> | 46 | #include <linux/stmp_device.h> |
44 | #include <mach/common.h> | 47 | #include <linux/mmc/mxs-mmc.h> |
45 | #include <mach/mmc.h> | ||
46 | 48 | ||
47 | #define DRIVER_NAME "mxs-mmc" | 49 | #define DRIVER_NAME "mxs-mmc" |
48 | 50 | ||
49 | /* card detect polling timeout */ | 51 | /* card detect polling timeout */ |
50 | #define MXS_MMC_DETECT_TIMEOUT (HZ/2) | 52 | #define MXS_MMC_DETECT_TIMEOUT (HZ/2) |
51 | 53 | ||
52 | #define SSP_VERSION_LATEST 4 | 54 | #define ssp_is_old(host) ((host)->devid == IMX23_MMC) |
53 | #define ssp_is_old() (host->version < SSP_VERSION_LATEST) | ||
54 | 55 | ||
55 | /* SSP registers */ | 56 | /* SSP registers */ |
56 | #define HW_SSP_CTRL0 0x000 | 57 | #define HW_SSP_CTRL0 0x000 |
@@ -85,14 +86,14 @@ | |||
85 | #define BM_SSP_BLOCK_SIZE_BLOCK_COUNT (0xffffff << 4) | 86 | #define BM_SSP_BLOCK_SIZE_BLOCK_COUNT (0xffffff << 4) |
86 | #define BP_SSP_BLOCK_SIZE_BLOCK_SIZE (0) | 87 | #define BP_SSP_BLOCK_SIZE_BLOCK_SIZE (0) |
87 | #define BM_SSP_BLOCK_SIZE_BLOCK_SIZE (0xf) | 88 | #define BM_SSP_BLOCK_SIZE_BLOCK_SIZE (0xf) |
88 | #define HW_SSP_TIMING (ssp_is_old() ? 0x050 : 0x070) | 89 | #define HW_SSP_TIMING(h) (ssp_is_old(h) ? 0x050 : 0x070) |
89 | #define BP_SSP_TIMING_TIMEOUT (16) | 90 | #define BP_SSP_TIMING_TIMEOUT (16) |
90 | #define BM_SSP_TIMING_TIMEOUT (0xffff << 16) | 91 | #define BM_SSP_TIMING_TIMEOUT (0xffff << 16) |
91 | #define BP_SSP_TIMING_CLOCK_DIVIDE (8) | 92 | #define BP_SSP_TIMING_CLOCK_DIVIDE (8) |
92 | #define BM_SSP_TIMING_CLOCK_DIVIDE (0xff << 8) | 93 | #define BM_SSP_TIMING_CLOCK_DIVIDE (0xff << 8) |
93 | #define BP_SSP_TIMING_CLOCK_RATE (0) | 94 | #define BP_SSP_TIMING_CLOCK_RATE (0) |
94 | #define BM_SSP_TIMING_CLOCK_RATE (0xff) | 95 | #define BM_SSP_TIMING_CLOCK_RATE (0xff) |
95 | #define HW_SSP_CTRL1 (ssp_is_old() ? 0x060 : 0x080) | 96 | #define HW_SSP_CTRL1(h) (ssp_is_old(h) ? 0x060 : 0x080) |
96 | #define BM_SSP_CTRL1_SDIO_IRQ (1 << 31) | 97 | #define BM_SSP_CTRL1_SDIO_IRQ (1 << 31) |
97 | #define BM_SSP_CTRL1_SDIO_IRQ_EN (1 << 30) | 98 | #define BM_SSP_CTRL1_SDIO_IRQ_EN (1 << 30) |
98 | #define BM_SSP_CTRL1_RESP_ERR_IRQ (1 << 29) | 99 | #define BM_SSP_CTRL1_RESP_ERR_IRQ (1 << 29) |
@@ -115,15 +116,13 @@ | |||
115 | #define BM_SSP_CTRL1_WORD_LENGTH (0xf << 4) | 116 | #define BM_SSP_CTRL1_WORD_LENGTH (0xf << 4) |
116 | #define BP_SSP_CTRL1_SSP_MODE (0) | 117 | #define BP_SSP_CTRL1_SSP_MODE (0) |
117 | #define BM_SSP_CTRL1_SSP_MODE (0xf) | 118 | #define BM_SSP_CTRL1_SSP_MODE (0xf) |
118 | #define HW_SSP_SDRESP0 (ssp_is_old() ? 0x080 : 0x0a0) | 119 | #define HW_SSP_SDRESP0(h) (ssp_is_old(h) ? 0x080 : 0x0a0) |
119 | #define HW_SSP_SDRESP1 (ssp_is_old() ? 0x090 : 0x0b0) | 120 | #define HW_SSP_SDRESP1(h) (ssp_is_old(h) ? 0x090 : 0x0b0) |
120 | #define HW_SSP_SDRESP2 (ssp_is_old() ? 0x0a0 : 0x0c0) | 121 | #define HW_SSP_SDRESP2(h) (ssp_is_old(h) ? 0x0a0 : 0x0c0) |
121 | #define HW_SSP_SDRESP3 (ssp_is_old() ? 0x0b0 : 0x0d0) | 122 | #define HW_SSP_SDRESP3(h) (ssp_is_old(h) ? 0x0b0 : 0x0d0) |
122 | #define HW_SSP_STATUS (ssp_is_old() ? 0x0c0 : 0x100) | 123 | #define HW_SSP_STATUS(h) (ssp_is_old(h) ? 0x0c0 : 0x100) |
123 | #define BM_SSP_STATUS_CARD_DETECT (1 << 28) | 124 | #define BM_SSP_STATUS_CARD_DETECT (1 << 28) |
124 | #define BM_SSP_STATUS_SDIO_IRQ (1 << 17) | 125 | #define BM_SSP_STATUS_SDIO_IRQ (1 << 17) |
125 | #define HW_SSP_VERSION (cpu_is_mx23() ? 0x110 : 0x130) | ||
126 | #define BP_SSP_VERSION_MAJOR (24) | ||
127 | 126 | ||
128 | #define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field) | 127 | #define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field) |
129 | 128 | ||
@@ -138,6 +137,11 @@ | |||
138 | 137 | ||
139 | #define SSP_PIO_NUM 3 | 138 | #define SSP_PIO_NUM 3 |
140 | 139 | ||
140 | enum mxs_mmc_id { | ||
141 | IMX23_MMC, | ||
142 | IMX28_MMC, | ||
143 | }; | ||
144 | |||
141 | struct mxs_mmc_host { | 145 | struct mxs_mmc_host { |
142 | struct mmc_host *mmc; | 146 | struct mmc_host *mmc; |
143 | struct mmc_request *mrq; | 147 | struct mmc_request *mrq; |
@@ -145,9 +149,7 @@ struct mxs_mmc_host { | |||
145 | struct mmc_data *data; | 149 | struct mmc_data *data; |
146 | 150 | ||
147 | void __iomem *base; | 151 | void __iomem *base; |
148 | int irq; | 152 | int dma_channel; |
149 | struct resource *res; | ||
150 | struct resource *dma_res; | ||
151 | struct clk *clk; | 153 | struct clk *clk; |
152 | unsigned int clk_rate; | 154 | unsigned int clk_rate; |
153 | 155 | ||
@@ -157,32 +159,28 @@ struct mxs_mmc_host { | |||
157 | enum dma_transfer_direction slave_dirn; | 159 | enum dma_transfer_direction slave_dirn; |
158 | u32 ssp_pio_words[SSP_PIO_NUM]; | 160 | u32 ssp_pio_words[SSP_PIO_NUM]; |
159 | 161 | ||
160 | unsigned int version; | 162 | enum mxs_mmc_id devid; |
161 | unsigned char bus_width; | 163 | unsigned char bus_width; |
162 | spinlock_t lock; | 164 | spinlock_t lock; |
163 | int sdio_irq_en; | 165 | int sdio_irq_en; |
166 | int wp_gpio; | ||
164 | }; | 167 | }; |
165 | 168 | ||
166 | static int mxs_mmc_get_ro(struct mmc_host *mmc) | 169 | static int mxs_mmc_get_ro(struct mmc_host *mmc) |
167 | { | 170 | { |
168 | struct mxs_mmc_host *host = mmc_priv(mmc); | 171 | struct mxs_mmc_host *host = mmc_priv(mmc); |
169 | struct mxs_mmc_platform_data *pdata = | ||
170 | mmc_dev(host->mmc)->platform_data; | ||
171 | |||
172 | if (!pdata) | ||
173 | return -EFAULT; | ||
174 | 172 | ||
175 | if (!gpio_is_valid(pdata->wp_gpio)) | 173 | if (!gpio_is_valid(host->wp_gpio)) |
176 | return -EINVAL; | 174 | return -EINVAL; |
177 | 175 | ||
178 | return gpio_get_value(pdata->wp_gpio); | 176 | return gpio_get_value(host->wp_gpio); |
179 | } | 177 | } |
180 | 178 | ||
181 | static int mxs_mmc_get_cd(struct mmc_host *mmc) | 179 | static int mxs_mmc_get_cd(struct mmc_host *mmc) |
182 | { | 180 | { |
183 | struct mxs_mmc_host *host = mmc_priv(mmc); | 181 | struct mxs_mmc_host *host = mmc_priv(mmc); |
184 | 182 | ||
185 | return !(readl(host->base + HW_SSP_STATUS) & | 183 | return !(readl(host->base + HW_SSP_STATUS(host)) & |
186 | BM_SSP_STATUS_CARD_DETECT); | 184 | BM_SSP_STATUS_CARD_DETECT); |
187 | } | 185 | } |
188 | 186 | ||
@@ -190,7 +188,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) | |||
190 | { | 188 | { |
191 | u32 ctrl0, ctrl1; | 189 | u32 ctrl0, ctrl1; |
192 | 190 | ||
193 | mxs_reset_block(host->base); | 191 | stmp_reset_block(host->base); |
194 | 192 | ||
195 | ctrl0 = BM_SSP_CTRL0_IGNORE_CRC; | 193 | ctrl0 = BM_SSP_CTRL0_IGNORE_CRC; |
196 | ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) | | 194 | ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) | |
@@ -206,7 +204,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) | |||
206 | writel(BF_SSP(0xffff, TIMING_TIMEOUT) | | 204 | writel(BF_SSP(0xffff, TIMING_TIMEOUT) | |
207 | BF_SSP(2, TIMING_CLOCK_DIVIDE) | | 205 | BF_SSP(2, TIMING_CLOCK_DIVIDE) | |
208 | BF_SSP(0, TIMING_CLOCK_RATE), | 206 | BF_SSP(0, TIMING_CLOCK_RATE), |
209 | host->base + HW_SSP_TIMING); | 207 | host->base + HW_SSP_TIMING(host)); |
210 | 208 | ||
211 | if (host->sdio_irq_en) { | 209 | if (host->sdio_irq_en) { |
212 | ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; | 210 | ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; |
@@ -214,7 +212,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) | |||
214 | } | 212 | } |
215 | 213 | ||
216 | writel(ctrl0, host->base + HW_SSP_CTRL0); | 214 | writel(ctrl0, host->base + HW_SSP_CTRL0); |
217 | writel(ctrl1, host->base + HW_SSP_CTRL1); | 215 | writel(ctrl1, host->base + HW_SSP_CTRL1(host)); |
218 | } | 216 | } |
219 | 217 | ||
220 | static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, | 218 | static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, |
@@ -228,12 +226,12 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host) | |||
228 | 226 | ||
229 | if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) { | 227 | if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) { |
230 | if (mmc_resp_type(cmd) & MMC_RSP_136) { | 228 | if (mmc_resp_type(cmd) & MMC_RSP_136) { |
231 | cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0); | 229 | cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0(host)); |
232 | cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1); | 230 | cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1(host)); |
233 | cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2); | 231 | cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2(host)); |
234 | cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3); | 232 | cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3(host)); |
235 | } else { | 233 | } else { |
236 | cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0); | 234 | cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0(host)); |
237 | } | 235 | } |
238 | } | 236 | } |
239 | 237 | ||
@@ -276,9 +274,9 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) | |||
276 | 274 | ||
277 | spin_lock(&host->lock); | 275 | spin_lock(&host->lock); |
278 | 276 | ||
279 | stat = readl(host->base + HW_SSP_CTRL1); | 277 | stat = readl(host->base + HW_SSP_CTRL1(host)); |
280 | writel(stat & MXS_MMC_IRQ_BITS, | 278 | writel(stat & MXS_MMC_IRQ_BITS, |
281 | host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); | 279 | host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_CLR); |
282 | 280 | ||
283 | if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) | 281 | if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) |
284 | mmc_signal_sdio_irq(host->mmc); | 282 | mmc_signal_sdio_irq(host->mmc); |
@@ -484,7 +482,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) | |||
484 | blocks = 1; | 482 | blocks = 1; |
485 | 483 | ||
486 | /* xfer count, block size and count need to be set differently */ | 484 | /* xfer count, block size and count need to be set differently */ |
487 | if (ssp_is_old()) { | 485 | if (ssp_is_old(host)) { |
488 | ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT); | 486 | ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT); |
489 | cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) | | 487 | cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) | |
490 | BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); | 488 | BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); |
@@ -508,10 +506,10 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) | |||
508 | 506 | ||
509 | /* set the timeout count */ | 507 | /* set the timeout count */ |
510 | timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns); | 508 | timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns); |
511 | val = readl(host->base + HW_SSP_TIMING); | 509 | val = readl(host->base + HW_SSP_TIMING(host)); |
512 | val &= ~(BM_SSP_TIMING_TIMEOUT); | 510 | val &= ~(BM_SSP_TIMING_TIMEOUT); |
513 | val |= BF_SSP(timeout, TIMING_TIMEOUT); | 511 | val |= BF_SSP(timeout, TIMING_TIMEOUT); |
514 | writel(val, host->base + HW_SSP_TIMING); | 512 | writel(val, host->base + HW_SSP_TIMING(host)); |
515 | 513 | ||
516 | /* pio */ | 514 | /* pio */ |
517 | host->ssp_pio_words[0] = ctrl0; | 515 | host->ssp_pio_words[0] = ctrl0; |
@@ -597,11 +595,11 @@ static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate) | |||
597 | 595 | ||
598 | ssp_sck = ssp_clk / clock_divide / (1 + clock_rate); | 596 | ssp_sck = ssp_clk / clock_divide / (1 + clock_rate); |
599 | 597 | ||
600 | val = readl(host->base + HW_SSP_TIMING); | 598 | val = readl(host->base + HW_SSP_TIMING(host)); |
601 | val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); | 599 | val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); |
602 | val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE); | 600 | val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE); |
603 | val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE); | 601 | val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE); |
604 | writel(val, host->base + HW_SSP_TIMING); | 602 | writel(val, host->base + HW_SSP_TIMING(host)); |
605 | 603 | ||
606 | host->clk_rate = ssp_sck; | 604 | host->clk_rate = ssp_sck; |
607 | 605 | ||
@@ -636,18 +634,19 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) | |||
636 | 634 | ||
637 | if (enable) { | 635 | if (enable) { |
638 | writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, | 636 | writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, |
639 | host->base + HW_SSP_CTRL0 + MXS_SET_ADDR); | 637 | host->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); |
640 | writel(BM_SSP_CTRL1_SDIO_IRQ_EN, | 638 | writel(BM_SSP_CTRL1_SDIO_IRQ_EN, |
641 | host->base + HW_SSP_CTRL1 + MXS_SET_ADDR); | 639 | host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_SET); |
642 | 640 | ||
643 | if (readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ) | 641 | if (readl(host->base + HW_SSP_STATUS(host)) & |
642 | BM_SSP_STATUS_SDIO_IRQ) | ||
644 | mmc_signal_sdio_irq(host->mmc); | 643 | mmc_signal_sdio_irq(host->mmc); |
645 | 644 | ||
646 | } else { | 645 | } else { |
647 | writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, | 646 | writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, |
648 | host->base + HW_SSP_CTRL0 + MXS_CLR_ADDR); | 647 | host->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); |
649 | writel(BM_SSP_CTRL1_SDIO_IRQ_EN, | 648 | writel(BM_SSP_CTRL1_SDIO_IRQ_EN, |
650 | host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); | 649 | host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_CLR); |
651 | } | 650 | } |
652 | 651 | ||
653 | spin_unlock_irqrestore(&host->lock, flags); | 652 | spin_unlock_irqrestore(&host->lock, flags); |
@@ -668,7 +667,7 @@ static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param) | |||
668 | if (!mxs_dma_is_apbh(chan)) | 667 | if (!mxs_dma_is_apbh(chan)) |
669 | return false; | 668 | return false; |
670 | 669 | ||
671 | if (chan->chan_id != host->dma_res->start) | 670 | if (chan->chan_id != host->dma_channel) |
672 | return false; | 671 | return false; |
673 | 672 | ||
674 | chan->private = &host->dma_data; | 673 | chan->private = &host->dma_data; |
@@ -676,12 +675,36 @@ static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param) | |||
676 | return true; | 675 | return true; |
677 | } | 676 | } |
678 | 677 | ||
678 | static struct platform_device_id mxs_mmc_ids[] = { | ||
679 | { | ||
680 | .name = "imx23-mmc", | ||
681 | .driver_data = IMX23_MMC, | ||
682 | }, { | ||
683 | .name = "imx28-mmc", | ||
684 | .driver_data = IMX28_MMC, | ||
685 | }, { | ||
686 | /* sentinel */ | ||
687 | } | ||
688 | }; | ||
689 | MODULE_DEVICE_TABLE(platform, mxs_mmc_ids); | ||
690 | |||
691 | static const struct of_device_id mxs_mmc_dt_ids[] = { | ||
692 | { .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_MMC, }, | ||
693 | { .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_MMC, }, | ||
694 | { /* sentinel */ } | ||
695 | }; | ||
696 | MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids); | ||
697 | |||
679 | static int mxs_mmc_probe(struct platform_device *pdev) | 698 | static int mxs_mmc_probe(struct platform_device *pdev) |
680 | { | 699 | { |
700 | const struct of_device_id *of_id = | ||
701 | of_match_device(mxs_mmc_dt_ids, &pdev->dev); | ||
702 | struct device_node *np = pdev->dev.of_node; | ||
681 | struct mxs_mmc_host *host; | 703 | struct mxs_mmc_host *host; |
682 | struct mmc_host *mmc; | 704 | struct mmc_host *mmc; |
683 | struct resource *iores, *dmares, *r; | 705 | struct resource *iores, *dmares; |
684 | struct mxs_mmc_platform_data *pdata; | 706 | struct mxs_mmc_platform_data *pdata; |
707 | struct pinctrl *pinctrl; | ||
685 | int ret = 0, irq_err, irq_dma; | 708 | int ret = 0, irq_err, irq_dma; |
686 | dma_cap_mask_t mask; | 709 | dma_cap_mask_t mask; |
687 | 710 | ||
@@ -689,40 +712,51 @@ static int mxs_mmc_probe(struct platform_device *pdev) | |||
689 | dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 712 | dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
690 | irq_err = platform_get_irq(pdev, 0); | 713 | irq_err = platform_get_irq(pdev, 0); |
691 | irq_dma = platform_get_irq(pdev, 1); | 714 | irq_dma = platform_get_irq(pdev, 1); |
692 | if (!iores || !dmares || irq_err < 0 || irq_dma < 0) | 715 | if (!iores || irq_err < 0 || irq_dma < 0) |
693 | return -EINVAL; | 716 | return -EINVAL; |
694 | 717 | ||
695 | r = request_mem_region(iores->start, resource_size(iores), pdev->name); | ||
696 | if (!r) | ||
697 | return -EBUSY; | ||
698 | |||
699 | mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); | 718 | mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); |
700 | if (!mmc) { | 719 | if (!mmc) |
701 | ret = -ENOMEM; | 720 | return -ENOMEM; |
702 | goto out_release_mem; | ||
703 | } | ||
704 | 721 | ||
705 | host = mmc_priv(mmc); | 722 | host = mmc_priv(mmc); |
706 | host->base = ioremap(r->start, resource_size(r)); | 723 | host->base = devm_request_and_ioremap(&pdev->dev, iores); |
707 | if (!host->base) { | 724 | if (!host->base) { |
708 | ret = -ENOMEM; | 725 | ret = -EADDRNOTAVAIL; |
709 | goto out_mmc_free; | 726 | goto out_mmc_free; |
710 | } | 727 | } |
711 | 728 | ||
712 | /* only major verion does matter */ | 729 | if (np) { |
713 | host->version = readl(host->base + HW_SSP_VERSION) >> | 730 | host->devid = (enum mxs_mmc_id) of_id->data; |
714 | BP_SSP_VERSION_MAJOR; | 731 | /* |
732 | * TODO: This is a temporary solution and should be changed | ||
733 | * to use generic DMA binding later when the helpers get in. | ||
734 | */ | ||
735 | ret = of_property_read_u32(np, "fsl,ssp-dma-channel", | ||
736 | &host->dma_channel); | ||
737 | if (ret) { | ||
738 | dev_err(mmc_dev(host->mmc), | ||
739 | "failed to get dma channel\n"); | ||
740 | goto out_mmc_free; | ||
741 | } | ||
742 | } else { | ||
743 | host->devid = pdev->id_entry->driver_data; | ||
744 | host->dma_channel = dmares->start; | ||
745 | } | ||
715 | 746 | ||
716 | host->mmc = mmc; | 747 | host->mmc = mmc; |
717 | host->res = r; | ||
718 | host->dma_res = dmares; | ||
719 | host->irq = irq_err; | ||
720 | host->sdio_irq_en = 0; | 748 | host->sdio_irq_en = 0; |
721 | 749 | ||
750 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | ||
751 | if (IS_ERR(pinctrl)) { | ||
752 | ret = PTR_ERR(pinctrl); | ||
753 | goto out_mmc_free; | ||
754 | } | ||
755 | |||
722 | host->clk = clk_get(&pdev->dev, NULL); | 756 | host->clk = clk_get(&pdev->dev, NULL); |
723 | if (IS_ERR(host->clk)) { | 757 | if (IS_ERR(host->clk)) { |
724 | ret = PTR_ERR(host->clk); | 758 | ret = PTR_ERR(host->clk); |
725 | goto out_iounmap; | 759 | goto out_mmc_free; |
726 | } | 760 | } |
727 | clk_prepare_enable(host->clk); | 761 | clk_prepare_enable(host->clk); |
728 | 762 | ||
@@ -744,11 +778,20 @@ static int mxs_mmc_probe(struct platform_device *pdev) | |||
744 | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; | 778 | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; |
745 | 779 | ||
746 | pdata = mmc_dev(host->mmc)->platform_data; | 780 | pdata = mmc_dev(host->mmc)->platform_data; |
747 | if (pdata) { | 781 | if (!pdata) { |
782 | u32 bus_width = 0; | ||
783 | of_property_read_u32(np, "bus-width", &bus_width); | ||
784 | if (bus_width == 4) | ||
785 | mmc->caps |= MMC_CAP_4_BIT_DATA; | ||
786 | else if (bus_width == 8) | ||
787 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; | ||
788 | host->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); | ||
789 | } else { | ||
748 | if (pdata->flags & SLOTF_8_BIT_CAPABLE) | 790 | if (pdata->flags & SLOTF_8_BIT_CAPABLE) |
749 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; | 791 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; |
750 | if (pdata->flags & SLOTF_4_BIT_CAPABLE) | 792 | if (pdata->flags & SLOTF_4_BIT_CAPABLE) |
751 | mmc->caps |= MMC_CAP_4_BIT_DATA; | 793 | mmc->caps |= MMC_CAP_4_BIT_DATA; |
794 | host->wp_gpio = pdata->wp_gpio; | ||
752 | } | 795 | } |
753 | 796 | ||
754 | mmc->f_min = 400000; | 797 | mmc->f_min = 400000; |
@@ -757,13 +800,14 @@ static int mxs_mmc_probe(struct platform_device *pdev) | |||
757 | 800 | ||
758 | mmc->max_segs = 52; | 801 | mmc->max_segs = 52; |
759 | mmc->max_blk_size = 1 << 0xf; | 802 | mmc->max_blk_size = 1 << 0xf; |
760 | mmc->max_blk_count = (ssp_is_old()) ? 0xff : 0xffffff; | 803 | mmc->max_blk_count = (ssp_is_old(host)) ? 0xff : 0xffffff; |
761 | mmc->max_req_size = (ssp_is_old()) ? 0xffff : 0xffffffff; | 804 | mmc->max_req_size = (ssp_is_old(host)) ? 0xffff : 0xffffffff; |
762 | mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev); | 805 | mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev); |
763 | 806 | ||
764 | platform_set_drvdata(pdev, mmc); | 807 | platform_set_drvdata(pdev, mmc); |
765 | 808 | ||
766 | ret = request_irq(host->irq, mxs_mmc_irq_handler, 0, DRIVER_NAME, host); | 809 | ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0, |
810 | DRIVER_NAME, host); | ||
767 | if (ret) | 811 | if (ret) |
768 | goto out_free_dma; | 812 | goto out_free_dma; |
769 | 813 | ||
@@ -771,26 +815,20 @@ static int mxs_mmc_probe(struct platform_device *pdev) | |||
771 | 815 | ||
772 | ret = mmc_add_host(mmc); | 816 | ret = mmc_add_host(mmc); |
773 | if (ret) | 817 | if (ret) |
774 | goto out_free_irq; | 818 | goto out_free_dma; |
775 | 819 | ||
776 | dev_info(mmc_dev(host->mmc), "initialized\n"); | 820 | dev_info(mmc_dev(host->mmc), "initialized\n"); |
777 | 821 | ||
778 | return 0; | 822 | return 0; |
779 | 823 | ||
780 | out_free_irq: | ||
781 | free_irq(host->irq, host); | ||
782 | out_free_dma: | 824 | out_free_dma: |
783 | if (host->dmach) | 825 | if (host->dmach) |
784 | dma_release_channel(host->dmach); | 826 | dma_release_channel(host->dmach); |
785 | out_clk_put: | 827 | out_clk_put: |
786 | clk_disable_unprepare(host->clk); | 828 | clk_disable_unprepare(host->clk); |
787 | clk_put(host->clk); | 829 | clk_put(host->clk); |
788 | out_iounmap: | ||
789 | iounmap(host->base); | ||
790 | out_mmc_free: | 830 | out_mmc_free: |
791 | mmc_free_host(mmc); | 831 | mmc_free_host(mmc); |
792 | out_release_mem: | ||
793 | release_mem_region(iores->start, resource_size(iores)); | ||
794 | return ret; | 832 | return ret; |
795 | } | 833 | } |
796 | 834 | ||
@@ -798,12 +836,9 @@ static int mxs_mmc_remove(struct platform_device *pdev) | |||
798 | { | 836 | { |
799 | struct mmc_host *mmc = platform_get_drvdata(pdev); | 837 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
800 | struct mxs_mmc_host *host = mmc_priv(mmc); | 838 | struct mxs_mmc_host *host = mmc_priv(mmc); |
801 | struct resource *res = host->res; | ||
802 | 839 | ||
803 | mmc_remove_host(mmc); | 840 | mmc_remove_host(mmc); |
804 | 841 | ||
805 | free_irq(host->irq, host); | ||
806 | |||
807 | platform_set_drvdata(pdev, NULL); | 842 | platform_set_drvdata(pdev, NULL); |
808 | 843 | ||
809 | if (host->dmach) | 844 | if (host->dmach) |
@@ -812,12 +847,8 @@ static int mxs_mmc_remove(struct platform_device *pdev) | |||
812 | clk_disable_unprepare(host->clk); | 847 | clk_disable_unprepare(host->clk); |
813 | clk_put(host->clk); | 848 | clk_put(host->clk); |
814 | 849 | ||
815 | iounmap(host->base); | ||
816 | |||
817 | mmc_free_host(mmc); | 850 | mmc_free_host(mmc); |
818 | 851 | ||
819 | release_mem_region(res->start, resource_size(res)); | ||
820 | |||
821 | return 0; | 852 | return 0; |
822 | } | 853 | } |
823 | 854 | ||
@@ -857,11 +888,13 @@ static const struct dev_pm_ops mxs_mmc_pm_ops = { | |||
857 | static struct platform_driver mxs_mmc_driver = { | 888 | static struct platform_driver mxs_mmc_driver = { |
858 | .probe = mxs_mmc_probe, | 889 | .probe = mxs_mmc_probe, |
859 | .remove = mxs_mmc_remove, | 890 | .remove = mxs_mmc_remove, |
891 | .id_table = mxs_mmc_ids, | ||
860 | .driver = { | 892 | .driver = { |
861 | .name = DRIVER_NAME, | 893 | .name = DRIVER_NAME, |
862 | .owner = THIS_MODULE, | 894 | .owner = THIS_MODULE, |
863 | #ifdef CONFIG_PM | 895 | #ifdef CONFIG_PM |
864 | .pm = &mxs_mmc_pm_ops, | 896 | .pm = &mxs_mmc_pm_ops, |
897 | .of_match_table = mxs_mmc_dt_ids, | ||
865 | #endif | 898 | #endif |
866 | }, | 899 | }, |
867 | }; | 900 | }; |
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 8abdaf6697a8..d190d04636a7 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/of_device.h> | 25 | #include <linux/of_device.h> |
26 | #include <linux/of_gpio.h> | 26 | #include <linux/of_gpio.h> |
27 | #include <linux/pinctrl/consumer.h> | ||
27 | #include <mach/esdhc.h> | 28 | #include <mach/esdhc.h> |
28 | #include "sdhci-pltfm.h" | 29 | #include "sdhci-pltfm.h" |
29 | #include "sdhci-esdhc.h" | 30 | #include "sdhci-esdhc.h" |
@@ -68,6 +69,7 @@ struct pltfm_imx_data { | |||
68 | int flags; | 69 | int flags; |
69 | u32 scratchpad; | 70 | u32 scratchpad; |
70 | enum imx_esdhc_type devtype; | 71 | enum imx_esdhc_type devtype; |
72 | struct pinctrl *pinctrl; | ||
71 | struct esdhc_platform_data boarddata; | 73 | struct esdhc_platform_data boarddata; |
72 | }; | 74 | }; |
73 | 75 | ||
@@ -467,6 +469,12 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
467 | clk_prepare_enable(clk); | 469 | clk_prepare_enable(clk); |
468 | pltfm_host->clk = clk; | 470 | pltfm_host->clk = clk; |
469 | 471 | ||
472 | imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | ||
473 | if (IS_ERR(imx_data->pinctrl)) { | ||
474 | err = PTR_ERR(imx_data->pinctrl); | ||
475 | goto pin_err; | ||
476 | } | ||
477 | |||
470 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; | 478 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; |
471 | 479 | ||
472 | if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) | 480 | if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) |
@@ -558,6 +566,7 @@ no_card_detect_irq: | |||
558 | gpio_free(boarddata->wp_gpio); | 566 | gpio_free(boarddata->wp_gpio); |
559 | no_card_detect_pin: | 567 | no_card_detect_pin: |
560 | no_board_data: | 568 | no_board_data: |
569 | pin_err: | ||
561 | clk_disable_unprepare(pltfm_host->clk); | 570 | clk_disable_unprepare(pltfm_host->clk); |
562 | clk_put(pltfm_host->clk); | 571 | clk_put(pltfm_host->clk); |
563 | err_clk_get: | 572 | err_clk_get: |