diff options
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/Kconfig | 41 | ||||
-rw-r--r-- | drivers/mmc/host/s3cmci.c | 608 | ||||
-rw-r--r-- | drivers/mmc/host/s3cmci.h | 14 |
3 files changed, 538 insertions, 125 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 7cb057f3f883..432ae8358c86 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
@@ -276,6 +276,47 @@ config MMC_S3C | |||
276 | 276 | ||
277 | If unsure, say N. | 277 | If unsure, say N. |
278 | 278 | ||
279 | config MMC_S3C_HW_SDIO_IRQ | ||
280 | bool "Hardware support for SDIO IRQ" | ||
281 | depends on MMC_S3C | ||
282 | help | ||
283 | Enable the hardware support for SDIO interrupts instead of using | ||
284 | the generic polling code. | ||
285 | |||
286 | choice | ||
287 | prompt "Samsung S3C SD/MMC transfer code" | ||
288 | depends on MMC_S3C | ||
289 | |||
290 | config MMC_S3C_PIO | ||
291 | bool "Use PIO transfers only" | ||
292 | help | ||
293 | Use PIO to transfer data between memory and the hardware. | ||
294 | |||
295 | PIO is slower than DMA as it requires CPU instructions to | ||
296 | move the data. This has been the traditional default for | ||
297 | the S3C MCI driver. | ||
298 | |||
299 | config MMC_S3C_DMA | ||
300 | bool "Use DMA transfers only (EXPERIMENTAL)" | ||
301 | depends on EXPERIMENTAL | ||
302 | help | ||
303 | Use DMA to transfer data between memory and the hardare. | ||
304 | |||
305 | Currently, the DMA support in this driver seems to not be | ||
306 | working properly and needs to be debugged before this | ||
307 | option is useful. | ||
308 | |||
309 | config MMC_S3C_PIODMA | ||
310 | bool "Support for both PIO and DMA (EXPERIMENTAL)" | ||
311 | help | ||
312 | Compile both the PIO and DMA transfer routines into the | ||
313 | driver and let the platform select at run-time which one | ||
314 | is best. | ||
315 | |||
316 | See notes for the DMA option. | ||
317 | |||
318 | endchoice | ||
319 | |||
279 | config MMC_SDRICOH_CS | 320 | config MMC_SDRICOH_CS |
280 | tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)" | 321 | tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)" |
281 | depends on EXPERIMENTAL && PCI && PCMCIA | 322 | depends on EXPERIMENTAL && PCI && PCMCIA |
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 8c08cd7efa7f..99b74a351020 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/mmc/host.h> | 17 | #include <linux/mmc/host.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/cpufreq.h> | 19 | #include <linux/cpufreq.h> |
20 | #include <linux/debugfs.h> | ||
21 | #include <linux/seq_file.h> | ||
20 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
21 | #include <linux/irq.h> | 23 | #include <linux/irq.h> |
22 | #include <linux/io.h> | 24 | #include <linux/io.h> |
@@ -58,8 +60,6 @@ static const int dbgmap_debug = dbg_err | dbg_debug; | |||
58 | dev_dbg(&host->pdev->dev, args); \ | 60 | dev_dbg(&host->pdev->dev, args); \ |
59 | } while (0) | 61 | } while (0) |
60 | 62 | ||
61 | #define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1) | ||
62 | |||
63 | static struct s3c2410_dma_client s3cmci_dma_client = { | 63 | static struct s3c2410_dma_client s3cmci_dma_client = { |
64 | .name = "s3c-mci", | 64 | .name = "s3c-mci", |
65 | }; | 65 | }; |
@@ -164,6 +164,40 @@ static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) { } | |||
164 | 164 | ||
165 | #endif /* CONFIG_MMC_DEBUG */ | 165 | #endif /* CONFIG_MMC_DEBUG */ |
166 | 166 | ||
167 | /** | ||
168 | * s3cmci_host_usedma - return whether the host is using dma or pio | ||
169 | * @host: The host state | ||
170 | * | ||
171 | * Return true if the host is using DMA to transfer data, else false | ||
172 | * to use PIO mode. Will return static data depending on the driver | ||
173 | * configuration. | ||
174 | */ | ||
175 | static inline bool s3cmci_host_usedma(struct s3cmci_host *host) | ||
176 | { | ||
177 | #ifdef CONFIG_MMC_S3C_PIO | ||
178 | return false; | ||
179 | #elif defined(CONFIG_MMC_S3C_DMA) | ||
180 | return true; | ||
181 | #else | ||
182 | return host->dodma; | ||
183 | #endif | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * s3cmci_host_canpio - return true if host has pio code available | ||
188 | * | ||
189 | * Return true if the driver has been compiled with the PIO support code | ||
190 | * available. | ||
191 | */ | ||
192 | static inline bool s3cmci_host_canpio(void) | ||
193 | { | ||
194 | #ifdef CONFIG_MMC_S3C_PIO | ||
195 | return true; | ||
196 | #else | ||
197 | return false; | ||
198 | #endif | ||
199 | } | ||
200 | |||
167 | static inline u32 enable_imask(struct s3cmci_host *host, u32 imask) | 201 | static inline u32 enable_imask(struct s3cmci_host *host, u32 imask) |
168 | { | 202 | { |
169 | u32 newmask; | 203 | u32 newmask; |
@@ -190,7 +224,33 @@ static inline u32 disable_imask(struct s3cmci_host *host, u32 imask) | |||
190 | 224 | ||
191 | static inline void clear_imask(struct s3cmci_host *host) | 225 | static inline void clear_imask(struct s3cmci_host *host) |
192 | { | 226 | { |
193 | writel(0, host->base + host->sdiimsk); | 227 | u32 mask = readl(host->base + host->sdiimsk); |
228 | |||
229 | /* preserve the SDIO IRQ mask state */ | ||
230 | mask &= S3C2410_SDIIMSK_SDIOIRQ; | ||
231 | writel(mask, host->base + host->sdiimsk); | ||
232 | } | ||
233 | |||
234 | /** | ||
235 | * s3cmci_check_sdio_irq - test whether the SDIO IRQ is being signalled | ||
236 | * @host: The host to check. | ||
237 | * | ||
238 | * Test to see if the SDIO interrupt is being signalled in case the | ||
239 | * controller has failed to re-detect a card interrupt. Read GPE8 and | ||
240 | * see if it is low and if so, signal a SDIO interrupt. | ||
241 | * | ||
242 | * This is currently called if a request is finished (we assume that the | ||
243 | * bus is now idle) and when the SDIO IRQ is enabled in case the IRQ is | ||
244 | * already being indicated. | ||
245 | */ | ||
246 | static void s3cmci_check_sdio_irq(struct s3cmci_host *host) | ||
247 | { | ||
248 | if (host->sdio_irqen) { | ||
249 | if (gpio_get_value(S3C2410_GPE(8)) == 0) { | ||
250 | printk(KERN_DEBUG "%s: signalling irq\n", __func__); | ||
251 | mmc_signal_sdio_irq(host->mmc); | ||
252 | } | ||
253 | } | ||
194 | } | 254 | } |
195 | 255 | ||
196 | static inline int get_data_buffer(struct s3cmci_host *host, | 256 | static inline int get_data_buffer(struct s3cmci_host *host, |
@@ -238,6 +298,64 @@ static inline u32 fifo_free(struct s3cmci_host *host) | |||
238 | return 63 - fifostat; | 298 | return 63 - fifostat; |
239 | } | 299 | } |
240 | 300 | ||
301 | /** | ||
302 | * s3cmci_enable_irq - enable IRQ, after having disabled it. | ||
303 | * @host: The device state. | ||
304 | * @more: True if more IRQs are expected from transfer. | ||
305 | * | ||
306 | * Enable the main IRQ if needed after it has been disabled. | ||
307 | * | ||
308 | * The IRQ can be one of the following states: | ||
309 | * - disabled during IDLE | ||
310 | * - disabled whilst processing data | ||
311 | * - enabled during transfer | ||
312 | * - enabled whilst awaiting SDIO interrupt detection | ||
313 | */ | ||
314 | static void s3cmci_enable_irq(struct s3cmci_host *host, bool more) | ||
315 | { | ||
316 | unsigned long flags; | ||
317 | bool enable = false; | ||
318 | |||
319 | local_irq_save(flags); | ||
320 | |||
321 | host->irq_enabled = more; | ||
322 | host->irq_disabled = false; | ||
323 | |||
324 | enable = more | host->sdio_irqen; | ||
325 | |||
326 | if (host->irq_state != enable) { | ||
327 | host->irq_state = enable; | ||
328 | |||
329 | if (enable) | ||
330 | enable_irq(host->irq); | ||
331 | else | ||
332 | disable_irq(host->irq); | ||
333 | } | ||
334 | |||
335 | local_irq_restore(flags); | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * | ||
340 | */ | ||
341 | static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) | ||
342 | { | ||
343 | unsigned long flags; | ||
344 | |||
345 | local_irq_save(flags); | ||
346 | |||
347 | //printk(KERN_DEBUG "%s: transfer %d\n", __func__, transfer); | ||
348 | |||
349 | host->irq_disabled = transfer; | ||
350 | |||
351 | if (transfer && host->irq_state) { | ||
352 | host->irq_state = false; | ||
353 | disable_irq(host->irq); | ||
354 | } | ||
355 | |||
356 | local_irq_restore(flags); | ||
357 | } | ||
358 | |||
241 | static void do_pio_read(struct s3cmci_host *host) | 359 | static void do_pio_read(struct s3cmci_host *host) |
242 | { | 360 | { |
243 | int res; | 361 | int res; |
@@ -374,8 +492,7 @@ static void pio_tasklet(unsigned long data) | |||
374 | { | 492 | { |
375 | struct s3cmci_host *host = (struct s3cmci_host *) data; | 493 | struct s3cmci_host *host = (struct s3cmci_host *) data; |
376 | 494 | ||
377 | 495 | s3cmci_disable_irq(host, true); | |
378 | disable_irq(host->irq); | ||
379 | 496 | ||
380 | if (host->pio_active == XFER_WRITE) | 497 | if (host->pio_active == XFER_WRITE) |
381 | do_pio_write(host); | 498 | do_pio_write(host); |
@@ -395,9 +512,10 @@ static void pio_tasklet(unsigned long data) | |||
395 | host->mrq->data->error = -EINVAL; | 512 | host->mrq->data->error = -EINVAL; |
396 | } | 513 | } |
397 | 514 | ||
515 | s3cmci_enable_irq(host, false); | ||
398 | finalize_request(host); | 516 | finalize_request(host); |
399 | } else | 517 | } else |
400 | enable_irq(host->irq); | 518 | s3cmci_enable_irq(host, true); |
401 | } | 519 | } |
402 | 520 | ||
403 | /* | 521 | /* |
@@ -432,17 +550,27 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id) | |||
432 | struct s3cmci_host *host = dev_id; | 550 | struct s3cmci_host *host = dev_id; |
433 | struct mmc_command *cmd; | 551 | struct mmc_command *cmd; |
434 | u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; | 552 | u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; |
435 | u32 mci_cclear, mci_dclear; | 553 | u32 mci_cclear = 0, mci_dclear; |
436 | unsigned long iflags; | 554 | unsigned long iflags; |
437 | 555 | ||
556 | mci_dsta = readl(host->base + S3C2410_SDIDSTA); | ||
557 | mci_imsk = readl(host->base + host->sdiimsk); | ||
558 | |||
559 | if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) { | ||
560 | if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) { | ||
561 | mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT; | ||
562 | writel(mci_dclear, host->base + S3C2410_SDIDSTA); | ||
563 | |||
564 | mmc_signal_sdio_irq(host->mmc); | ||
565 | return IRQ_HANDLED; | ||
566 | } | ||
567 | } | ||
568 | |||
438 | spin_lock_irqsave(&host->complete_lock, iflags); | 569 | spin_lock_irqsave(&host->complete_lock, iflags); |
439 | 570 | ||
440 | mci_csta = readl(host->base + S3C2410_SDICMDSTAT); | 571 | mci_csta = readl(host->base + S3C2410_SDICMDSTAT); |
441 | mci_dsta = readl(host->base + S3C2410_SDIDSTA); | ||
442 | mci_dcnt = readl(host->base + S3C2410_SDIDCNT); | 572 | mci_dcnt = readl(host->base + S3C2410_SDIDCNT); |
443 | mci_fsta = readl(host->base + S3C2410_SDIFSTA); | 573 | mci_fsta = readl(host->base + S3C2410_SDIFSTA); |
444 | mci_imsk = readl(host->base + host->sdiimsk); | ||
445 | mci_cclear = 0; | ||
446 | mci_dclear = 0; | 574 | mci_dclear = 0; |
447 | 575 | ||
448 | if ((host->complete_what == COMPLETION_NONE) || | 576 | if ((host->complete_what == COMPLETION_NONE) || |
@@ -466,7 +594,7 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id) | |||
466 | goto irq_out; | 594 | goto irq_out; |
467 | } | 595 | } |
468 | 596 | ||
469 | if (!host->dodma) { | 597 | if (!s3cmci_host_usedma(host)) { |
470 | if ((host->pio_active == XFER_WRITE) && | 598 | if ((host->pio_active == XFER_WRITE) && |
471 | (mci_fsta & S3C2410_SDIFSTA_TFDET)) { | 599 | (mci_fsta & S3C2410_SDIFSTA_TFDET)) { |
472 | 600 | ||
@@ -673,6 +801,7 @@ static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, | |||
673 | dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n", | 801 | dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n", |
674 | size, mci_dsta, mci_dcnt); | 802 | size, mci_dsta, mci_dcnt); |
675 | 803 | ||
804 | host->dma_complete = 1; | ||
676 | host->complete_what = COMPLETION_FINALIZE; | 805 | host->complete_what = COMPLETION_FINALIZE; |
677 | 806 | ||
678 | out: | 807 | out: |
@@ -683,9 +812,9 @@ out: | |||
683 | fail_request: | 812 | fail_request: |
684 | host->mrq->data->error = -EINVAL; | 813 | host->mrq->data->error = -EINVAL; |
685 | host->complete_what = COMPLETION_FINALIZE; | 814 | host->complete_what = COMPLETION_FINALIZE; |
686 | writel(0, host->base + host->sdiimsk); | 815 | clear_imask(host); |
687 | goto out; | ||
688 | 816 | ||
817 | goto out; | ||
689 | } | 818 | } |
690 | 819 | ||
691 | static void finalize_request(struct s3cmci_host *host) | 820 | static void finalize_request(struct s3cmci_host *host) |
@@ -702,8 +831,9 @@ static void finalize_request(struct s3cmci_host *host) | |||
702 | 831 | ||
703 | if (cmd->data && (cmd->error == 0) && | 832 | if (cmd->data && (cmd->error == 0) && |
704 | (cmd->data->error == 0)) { | 833 | (cmd->data->error == 0)) { |
705 | if (host->dodma && (!host->dma_complete)) { | 834 | if (s3cmci_host_usedma(host) && (!host->dma_complete)) { |
706 | dbg(host, dbg_dma, "DMA Missing!\n"); | 835 | dbg(host, dbg_dma, "DMA Missing (%d)!\n", |
836 | host->dma_complete); | ||
707 | return; | 837 | return; |
708 | } | 838 | } |
709 | } | 839 | } |
@@ -728,7 +858,7 @@ static void finalize_request(struct s3cmci_host *host) | |||
728 | writel(0, host->base + S3C2410_SDICMDARG); | 858 | writel(0, host->base + S3C2410_SDICMDARG); |
729 | writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); | 859 | writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); |
730 | writel(0, host->base + S3C2410_SDICMDCON); | 860 | writel(0, host->base + S3C2410_SDICMDCON); |
731 | writel(0, host->base + host->sdiimsk); | 861 | clear_imask(host); |
732 | 862 | ||
733 | if (cmd->data && cmd->error) | 863 | if (cmd->data && cmd->error) |
734 | cmd->data->error = cmd->error; | 864 | cmd->data->error = cmd->error; |
@@ -754,7 +884,7 @@ static void finalize_request(struct s3cmci_host *host) | |||
754 | /* If we had an error while transfering data we flush the | 884 | /* If we had an error while transfering data we flush the |
755 | * DMA channel and the fifo to clear out any garbage. */ | 885 | * DMA channel and the fifo to clear out any garbage. */ |
756 | if (mrq->data->error != 0) { | 886 | if (mrq->data->error != 0) { |
757 | if (host->dodma) | 887 | if (s3cmci_host_usedma(host)) |
758 | s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); | 888 | s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); |
759 | 889 | ||
760 | if (host->is2440) { | 890 | if (host->is2440) { |
@@ -776,6 +906,8 @@ static void finalize_request(struct s3cmci_host *host) | |||
776 | request_done: | 906 | request_done: |
777 | host->complete_what = COMPLETION_NONE; | 907 | host->complete_what = COMPLETION_NONE; |
778 | host->mrq = NULL; | 908 | host->mrq = NULL; |
909 | |||
910 | s3cmci_check_sdio_irq(host); | ||
779 | mmc_request_done(host->mmc, mrq); | 911 | mmc_request_done(host->mmc, mrq); |
780 | } | 912 | } |
781 | 913 | ||
@@ -872,7 +1004,7 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) | |||
872 | 1004 | ||
873 | dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK; | 1005 | dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK; |
874 | 1006 | ||
875 | if (host->dodma) | 1007 | if (s3cmci_host_usedma(host)) |
876 | dcon |= S3C2410_SDIDCON_DMAEN; | 1008 | dcon |= S3C2410_SDIDCON_DMAEN; |
877 | 1009 | ||
878 | if (host->bus_width == MMC_BUS_WIDTH_4) | 1010 | if (host->bus_width == MMC_BUS_WIDTH_4) |
@@ -950,7 +1082,7 @@ static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data) | |||
950 | static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) | 1082 | static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) |
951 | { | 1083 | { |
952 | int dma_len, i; | 1084 | int dma_len, i; |
953 | int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; | 1085 | int rw = data->flags & MMC_DATA_WRITE; |
954 | 1086 | ||
955 | BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); | 1087 | BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); |
956 | 1088 | ||
@@ -958,7 +1090,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) | |||
958 | s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); | 1090 | s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); |
959 | 1091 | ||
960 | dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, | 1092 | dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, |
961 | (rw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); | 1093 | rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); |
962 | 1094 | ||
963 | if (dma_len == 0) | 1095 | if (dma_len == 0) |
964 | return -ENOMEM; | 1096 | return -ENOMEM; |
@@ -969,11 +1101,11 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) | |||
969 | for (i = 0; i < dma_len; i++) { | 1101 | for (i = 0; i < dma_len; i++) { |
970 | int res; | 1102 | int res; |
971 | 1103 | ||
972 | dbg(host, dbg_dma, "enqueue %i:%u@%u\n", i, | 1104 | dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i, |
973 | sg_dma_address(&data->sg[i]), | 1105 | sg_dma_address(&data->sg[i]), |
974 | sg_dma_len(&data->sg[i])); | 1106 | sg_dma_len(&data->sg[i])); |
975 | 1107 | ||
976 | res = s3c2410_dma_enqueue(host->dma, (void *) host, | 1108 | res = s3c2410_dma_enqueue(host->dma, host, |
977 | sg_dma_address(&data->sg[i]), | 1109 | sg_dma_address(&data->sg[i]), |
978 | sg_dma_len(&data->sg[i])); | 1110 | sg_dma_len(&data->sg[i])); |
979 | 1111 | ||
@@ -1018,7 +1150,7 @@ static void s3cmci_send_request(struct mmc_host *mmc) | |||
1018 | return; | 1150 | return; |
1019 | } | 1151 | } |
1020 | 1152 | ||
1021 | if (host->dodma) | 1153 | if (s3cmci_host_usedma(host)) |
1022 | res = s3cmci_prepare_dma(host, cmd->data); | 1154 | res = s3cmci_prepare_dma(host, cmd->data); |
1023 | else | 1155 | else |
1024 | res = s3cmci_prepare_pio(host, cmd->data); | 1156 | res = s3cmci_prepare_pio(host, cmd->data); |
@@ -1037,7 +1169,7 @@ static void s3cmci_send_request(struct mmc_host *mmc) | |||
1037 | s3cmci_send_command(host, cmd); | 1169 | s3cmci_send_command(host, cmd); |
1038 | 1170 | ||
1039 | /* Enable Interrupt */ | 1171 | /* Enable Interrupt */ |
1040 | enable_irq(host->irq); | 1172 | s3cmci_enable_irq(host, true); |
1041 | } | 1173 | } |
1042 | 1174 | ||
1043 | static int s3cmci_card_present(struct mmc_host *mmc) | 1175 | static int s3cmci_card_present(struct mmc_host *mmc) |
@@ -1049,7 +1181,7 @@ static int s3cmci_card_present(struct mmc_host *mmc) | |||
1049 | if (pdata->gpio_detect == 0) | 1181 | if (pdata->gpio_detect == 0) |
1050 | return -ENOSYS; | 1182 | return -ENOSYS; |
1051 | 1183 | ||
1052 | ret = s3c2410_gpio_getpin(pdata->gpio_detect) ? 0 : 1; | 1184 | ret = gpio_get_value(pdata->gpio_detect) ? 0 : 1; |
1053 | return ret ^ pdata->detect_invert; | 1185 | return ret ^ pdata->detect_invert; |
1054 | } | 1186 | } |
1055 | 1187 | ||
@@ -1104,12 +1236,12 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
1104 | switch (ios->power_mode) { | 1236 | switch (ios->power_mode) { |
1105 | case MMC_POWER_ON: | 1237 | case MMC_POWER_ON: |
1106 | case MMC_POWER_UP: | 1238 | case MMC_POWER_UP: |
1107 | s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK); | 1239 | s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK); |
1108 | s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD); | 1240 | s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD); |
1109 | s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0); | 1241 | s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0); |
1110 | s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1); | 1242 | s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); |
1111 | s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2); | 1243 | s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2); |
1112 | s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3); | 1244 | s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3); |
1113 | 1245 | ||
1114 | if (host->pdata->set_power) | 1246 | if (host->pdata->set_power) |
1115 | host->pdata->set_power(ios->power_mode, ios->vdd); | 1247 | host->pdata->set_power(ios->power_mode, ios->vdd); |
@@ -1121,8 +1253,7 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
1121 | 1253 | ||
1122 | case MMC_POWER_OFF: | 1254 | case MMC_POWER_OFF: |
1123 | default: | 1255 | default: |
1124 | s3c2410_gpio_setpin(S3C2410_GPE5, 0); | 1256 | gpio_direction_output(S3C2410_GPE(5), 0); |
1125 | s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPIO_OUTPUT); | ||
1126 | 1257 | ||
1127 | if (host->is2440) | 1258 | if (host->is2440) |
1128 | mci_con |= S3C2440_SDICON_SDRESET; | 1259 | mci_con |= S3C2440_SDICON_SDRESET; |
@@ -1168,7 +1299,7 @@ static int s3cmci_get_ro(struct mmc_host *mmc) | |||
1168 | struct s3c24xx_mci_pdata *pdata = host->pdata; | 1299 | struct s3c24xx_mci_pdata *pdata = host->pdata; |
1169 | int ret; | 1300 | int ret; |
1170 | 1301 | ||
1171 | if (pdata->gpio_wprotect == 0) | 1302 | if (pdata->no_wprotect) |
1172 | return 0; | 1303 | return 0; |
1173 | 1304 | ||
1174 | ret = s3c2410_gpio_getpin(pdata->gpio_wprotect); | 1305 | ret = s3c2410_gpio_getpin(pdata->gpio_wprotect); |
@@ -1179,11 +1310,52 @@ static int s3cmci_get_ro(struct mmc_host *mmc) | |||
1179 | return ret; | 1310 | return ret; |
1180 | } | 1311 | } |
1181 | 1312 | ||
1313 | static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
1314 | { | ||
1315 | struct s3cmci_host *host = mmc_priv(mmc); | ||
1316 | unsigned long flags; | ||
1317 | u32 con; | ||
1318 | |||
1319 | local_irq_save(flags); | ||
1320 | |||
1321 | con = readl(host->base + S3C2410_SDICON); | ||
1322 | host->sdio_irqen = enable; | ||
1323 | |||
1324 | if (enable == host->sdio_irqen) | ||
1325 | goto same_state; | ||
1326 | |||
1327 | if (enable) { | ||
1328 | con |= S3C2410_SDICON_SDIOIRQ; | ||
1329 | enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); | ||
1330 | |||
1331 | if (!host->irq_state && !host->irq_disabled) { | ||
1332 | host->irq_state = true; | ||
1333 | enable_irq(host->irq); | ||
1334 | } | ||
1335 | } else { | ||
1336 | disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); | ||
1337 | con &= ~S3C2410_SDICON_SDIOIRQ; | ||
1338 | |||
1339 | if (!host->irq_enabled && host->irq_state) { | ||
1340 | disable_irq_nosync(host->irq); | ||
1341 | host->irq_state = false; | ||
1342 | } | ||
1343 | } | ||
1344 | |||
1345 | writel(con, host->base + S3C2410_SDICON); | ||
1346 | |||
1347 | same_state: | ||
1348 | local_irq_restore(flags); | ||
1349 | |||
1350 | s3cmci_check_sdio_irq(host); | ||
1351 | } | ||
1352 | |||
1182 | static struct mmc_host_ops s3cmci_ops = { | 1353 | static struct mmc_host_ops s3cmci_ops = { |
1183 | .request = s3cmci_request, | 1354 | .request = s3cmci_request, |
1184 | .set_ios = s3cmci_set_ios, | 1355 | .set_ios = s3cmci_set_ios, |
1185 | .get_ro = s3cmci_get_ro, | 1356 | .get_ro = s3cmci_get_ro, |
1186 | .get_cd = s3cmci_card_present, | 1357 | .get_cd = s3cmci_card_present, |
1358 | .enable_sdio_irq = s3cmci_enable_sdio_irq, | ||
1187 | }; | 1359 | }; |
1188 | 1360 | ||
1189 | static struct s3c24xx_mci_pdata s3cmci_def_pdata = { | 1361 | static struct s3c24xx_mci_pdata s3cmci_def_pdata = { |
@@ -1246,11 +1418,140 @@ static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) | |||
1246 | } | 1418 | } |
1247 | #endif | 1419 | #endif |
1248 | 1420 | ||
1249 | static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | 1421 | |
1422 | #ifdef CONFIG_DEBUG_FS | ||
1423 | |||
1424 | static int s3cmci_state_show(struct seq_file *seq, void *v) | ||
1425 | { | ||
1426 | struct s3cmci_host *host = seq->private; | ||
1427 | |||
1428 | seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base); | ||
1429 | seq_printf(seq, "Clock rate = %ld\n", host->clk_rate); | ||
1430 | seq_printf(seq, "Prescale = %d\n", host->prescaler); | ||
1431 | seq_printf(seq, "is2440 = %d\n", host->is2440); | ||
1432 | seq_printf(seq, "IRQ = %d\n", host->irq); | ||
1433 | seq_printf(seq, "IRQ enabled = %d\n", host->irq_enabled); | ||
1434 | seq_printf(seq, "IRQ disabled = %d\n", host->irq_disabled); | ||
1435 | seq_printf(seq, "IRQ state = %d\n", host->irq_state); | ||
1436 | seq_printf(seq, "CD IRQ = %d\n", host->irq_cd); | ||
1437 | seq_printf(seq, "Do DMA = %d\n", s3cmci_host_usedma(host)); | ||
1438 | seq_printf(seq, "SDIIMSK at %d\n", host->sdiimsk); | ||
1439 | seq_printf(seq, "SDIDATA at %d\n", host->sdidata); | ||
1440 | |||
1441 | return 0; | ||
1442 | } | ||
1443 | |||
1444 | static int s3cmci_state_open(struct inode *inode, struct file *file) | ||
1445 | { | ||
1446 | return single_open(file, s3cmci_state_show, inode->i_private); | ||
1447 | } | ||
1448 | |||
1449 | static const struct file_operations s3cmci_fops_state = { | ||
1450 | .owner = THIS_MODULE, | ||
1451 | .open = s3cmci_state_open, | ||
1452 | .read = seq_read, | ||
1453 | .llseek = seq_lseek, | ||
1454 | .release = single_release, | ||
1455 | }; | ||
1456 | |||
1457 | #define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r } | ||
1458 | |||
1459 | struct s3cmci_reg { | ||
1460 | unsigned short addr; | ||
1461 | unsigned char *name; | ||
1462 | } debug_regs[] = { | ||
1463 | DBG_REG(CON), | ||
1464 | DBG_REG(PRE), | ||
1465 | DBG_REG(CMDARG), | ||
1466 | DBG_REG(CMDCON), | ||
1467 | DBG_REG(CMDSTAT), | ||
1468 | DBG_REG(RSP0), | ||
1469 | DBG_REG(RSP1), | ||
1470 | DBG_REG(RSP2), | ||
1471 | DBG_REG(RSP3), | ||
1472 | DBG_REG(TIMER), | ||
1473 | DBG_REG(BSIZE), | ||
1474 | DBG_REG(DCON), | ||
1475 | DBG_REG(DCNT), | ||
1476 | DBG_REG(DSTA), | ||
1477 | DBG_REG(FSTA), | ||
1478 | {} | ||
1479 | }; | ||
1480 | |||
1481 | static int s3cmci_regs_show(struct seq_file *seq, void *v) | ||
1482 | { | ||
1483 | struct s3cmci_host *host = seq->private; | ||
1484 | struct s3cmci_reg *rptr = debug_regs; | ||
1485 | |||
1486 | for (; rptr->name; rptr++) | ||
1487 | seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name, | ||
1488 | readl(host->base + rptr->addr)); | ||
1489 | |||
1490 | seq_printf(seq, "SDIIMSK\t=0x%08x\n", readl(host->base + host->sdiimsk)); | ||
1491 | |||
1492 | return 0; | ||
1493 | } | ||
1494 | |||
1495 | static int s3cmci_regs_open(struct inode *inode, struct file *file) | ||
1496 | { | ||
1497 | return single_open(file, s3cmci_regs_show, inode->i_private); | ||
1498 | } | ||
1499 | |||
1500 | static const struct file_operations s3cmci_fops_regs = { | ||
1501 | .owner = THIS_MODULE, | ||
1502 | .open = s3cmci_regs_open, | ||
1503 | .read = seq_read, | ||
1504 | .llseek = seq_lseek, | ||
1505 | .release = single_release, | ||
1506 | }; | ||
1507 | |||
1508 | static void s3cmci_debugfs_attach(struct s3cmci_host *host) | ||
1509 | { | ||
1510 | struct device *dev = &host->pdev->dev; | ||
1511 | |||
1512 | host->debug_root = debugfs_create_dir(dev_name(dev), NULL); | ||
1513 | if (IS_ERR(host->debug_root)) { | ||
1514 | dev_err(dev, "failed to create debugfs root\n"); | ||
1515 | return; | ||
1516 | } | ||
1517 | |||
1518 | host->debug_state = debugfs_create_file("state", 0444, | ||
1519 | host->debug_root, host, | ||
1520 | &s3cmci_fops_state); | ||
1521 | |||
1522 | if (IS_ERR(host->debug_state)) | ||
1523 | dev_err(dev, "failed to create debug state file\n"); | ||
1524 | |||
1525 | host->debug_regs = debugfs_create_file("regs", 0444, | ||
1526 | host->debug_root, host, | ||
1527 | &s3cmci_fops_regs); | ||
1528 | |||
1529 | if (IS_ERR(host->debug_regs)) | ||
1530 | dev_err(dev, "failed to create debug regs file\n"); | ||
1531 | } | ||
1532 | |||
1533 | static void s3cmci_debugfs_remove(struct s3cmci_host *host) | ||
1534 | { | ||
1535 | debugfs_remove(host->debug_regs); | ||
1536 | debugfs_remove(host->debug_state); | ||
1537 | debugfs_remove(host->debug_root); | ||
1538 | } | ||
1539 | |||
1540 | #else | ||
1541 | static inline void s3cmci_debugfs_attach(struct s3cmci_host *host) { } | ||
1542 | static inline void s3cmci_debugfs_remove(struct s3cmci_host *host) { } | ||
1543 | |||
1544 | #endif /* CONFIG_DEBUG_FS */ | ||
1545 | |||
1546 | static int __devinit s3cmci_probe(struct platform_device *pdev) | ||
1250 | { | 1547 | { |
1251 | struct s3cmci_host *host; | 1548 | struct s3cmci_host *host; |
1252 | struct mmc_host *mmc; | 1549 | struct mmc_host *mmc; |
1253 | int ret; | 1550 | int ret; |
1551 | int is2440; | ||
1552 | int i; | ||
1553 | |||
1554 | is2440 = platform_get_device_id(pdev)->driver_data; | ||
1254 | 1555 | ||
1255 | mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); | 1556 | mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); |
1256 | if (!mmc) { | 1557 | if (!mmc) { |
@@ -1258,6 +1559,18 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1258 | goto probe_out; | 1559 | goto probe_out; |
1259 | } | 1560 | } |
1260 | 1561 | ||
1562 | for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) { | ||
1563 | ret = gpio_request(i, dev_name(&pdev->dev)); | ||
1564 | if (ret) { | ||
1565 | dev_err(&pdev->dev, "failed to get gpio %d\n", i); | ||
1566 | |||
1567 | for (i--; i >= S3C2410_GPE(5); i--) | ||
1568 | gpio_free(i); | ||
1569 | |||
1570 | goto probe_free_host; | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1261 | host = mmc_priv(mmc); | 1574 | host = mmc_priv(mmc); |
1262 | host->mmc = mmc; | 1575 | host->mmc = mmc; |
1263 | host->pdev = pdev; | 1576 | host->pdev = pdev; |
@@ -1282,11 +1595,12 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1282 | host->clk_div = 2; | 1595 | host->clk_div = 2; |
1283 | } | 1596 | } |
1284 | 1597 | ||
1285 | host->dodma = 0; | ||
1286 | host->complete_what = COMPLETION_NONE; | 1598 | host->complete_what = COMPLETION_NONE; |
1287 | host->pio_active = XFER_NONE; | 1599 | host->pio_active = XFER_NONE; |
1288 | 1600 | ||
1289 | host->dma = S3CMCI_DMA; | 1601 | #ifdef CONFIG_MMC_S3C_PIODMA |
1602 | host->dodma = host->pdata->dma; | ||
1603 | #endif | ||
1290 | 1604 | ||
1291 | host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1605 | host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1292 | if (!host->mem) { | 1606 | if (!host->mem) { |
@@ -1294,19 +1608,19 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1294 | "failed to get io memory region resouce.\n"); | 1608 | "failed to get io memory region resouce.\n"); |
1295 | 1609 | ||
1296 | ret = -ENOENT; | 1610 | ret = -ENOENT; |
1297 | goto probe_free_host; | 1611 | goto probe_free_gpio; |
1298 | } | 1612 | } |
1299 | 1613 | ||
1300 | host->mem = request_mem_region(host->mem->start, | 1614 | host->mem = request_mem_region(host->mem->start, |
1301 | RESSIZE(host->mem), pdev->name); | 1615 | resource_size(host->mem), pdev->name); |
1302 | 1616 | ||
1303 | if (!host->mem) { | 1617 | if (!host->mem) { |
1304 | dev_err(&pdev->dev, "failed to request io memory region.\n"); | 1618 | dev_err(&pdev->dev, "failed to request io memory region.\n"); |
1305 | ret = -ENOENT; | 1619 | ret = -ENOENT; |
1306 | goto probe_free_host; | 1620 | goto probe_free_gpio; |
1307 | } | 1621 | } |
1308 | 1622 | ||
1309 | host->base = ioremap(host->mem->start, RESSIZE(host->mem)); | 1623 | host->base = ioremap(host->mem->start, resource_size(host->mem)); |
1310 | if (!host->base) { | 1624 | if (!host->base) { |
1311 | dev_err(&pdev->dev, "failed to ioremap() io memory region.\n"); | 1625 | dev_err(&pdev->dev, "failed to ioremap() io memory region.\n"); |
1312 | ret = -EINVAL; | 1626 | ret = -EINVAL; |
@@ -1331,31 +1645,60 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1331 | * ensure we don't lock the system with un-serviceable requests. */ | 1645 | * ensure we don't lock the system with un-serviceable requests. */ |
1332 | 1646 | ||
1333 | disable_irq(host->irq); | 1647 | disable_irq(host->irq); |
1648 | host->irq_state = false; | ||
1334 | 1649 | ||
1335 | host->irq_cd = s3c2410_gpio_getirq(host->pdata->gpio_detect); | 1650 | if (!host->pdata->no_detect) { |
1336 | 1651 | ret = gpio_request(host->pdata->gpio_detect, "s3cmci detect"); | |
1337 | if (host->irq_cd >= 0) { | 1652 | if (ret) { |
1338 | if (request_irq(host->irq_cd, s3cmci_irq_cd, | 1653 | dev_err(&pdev->dev, "failed to get detect gpio\n"); |
1339 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
1340 | DRIVER_NAME, host)) { | ||
1341 | dev_err(&pdev->dev, "can't get card detect irq.\n"); | ||
1342 | ret = -ENOENT; | ||
1343 | goto probe_free_irq; | 1654 | goto probe_free_irq; |
1344 | } | 1655 | } |
1345 | } else { | 1656 | |
1346 | dev_warn(&pdev->dev, "host detect has no irq available\n"); | 1657 | host->irq_cd = s3c2410_gpio_getirq(host->pdata->gpio_detect); |
1347 | s3c2410_gpio_cfgpin(host->pdata->gpio_detect, | 1658 | |
1348 | S3C2410_GPIO_INPUT); | 1659 | if (host->irq_cd >= 0) { |
1660 | if (request_irq(host->irq_cd, s3cmci_irq_cd, | ||
1661 | IRQF_TRIGGER_RISING | | ||
1662 | IRQF_TRIGGER_FALLING, | ||
1663 | DRIVER_NAME, host)) { | ||
1664 | dev_err(&pdev->dev, | ||
1665 | "can't get card detect irq.\n"); | ||
1666 | ret = -ENOENT; | ||
1667 | goto probe_free_gpio_cd; | ||
1668 | } | ||
1669 | } else { | ||
1670 | dev_warn(&pdev->dev, | ||
1671 | "host detect has no irq available\n"); | ||
1672 | gpio_direction_input(host->pdata->gpio_detect); | ||
1673 | } | ||
1674 | } else | ||
1675 | host->irq_cd = -1; | ||
1676 | |||
1677 | if (!host->pdata->no_wprotect) { | ||
1678 | ret = gpio_request(host->pdata->gpio_wprotect, "s3cmci wp"); | ||
1679 | if (ret) { | ||
1680 | dev_err(&pdev->dev, "failed to get writeprotect\n"); | ||
1681 | goto probe_free_irq_cd; | ||
1682 | } | ||
1683 | |||
1684 | gpio_direction_input(host->pdata->gpio_wprotect); | ||
1349 | } | 1685 | } |
1350 | 1686 | ||
1351 | if (host->pdata->gpio_wprotect) | 1687 | /* depending on the dma state, get a dma channel to use. */ |
1352 | s3c2410_gpio_cfgpin(host->pdata->gpio_wprotect, | ||
1353 | S3C2410_GPIO_INPUT); | ||
1354 | 1688 | ||
1355 | if (s3c2410_dma_request(S3CMCI_DMA, &s3cmci_dma_client, NULL) < 0) { | 1689 | if (s3cmci_host_usedma(host)) { |
1356 | dev_err(&pdev->dev, "unable to get DMA channel.\n"); | 1690 | host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client, |
1357 | ret = -EBUSY; | 1691 | host); |
1358 | goto probe_free_irq_cd; | 1692 | if (host->dma < 0) { |
1693 | dev_err(&pdev->dev, "cannot get DMA channel.\n"); | ||
1694 | if (!s3cmci_host_canpio()) { | ||
1695 | ret = -EBUSY; | ||
1696 | goto probe_free_gpio_wp; | ||
1697 | } else { | ||
1698 | dev_warn(&pdev->dev, "falling back to PIO.\n"); | ||
1699 | host->dodma = 0; | ||
1700 | } | ||
1701 | } | ||
1359 | } | 1702 | } |
1360 | 1703 | ||
1361 | host->clk = clk_get(&pdev->dev, "sdi"); | 1704 | host->clk = clk_get(&pdev->dev, "sdi"); |
@@ -1363,7 +1706,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1363 | dev_err(&pdev->dev, "failed to find clock source.\n"); | 1706 | dev_err(&pdev->dev, "failed to find clock source.\n"); |
1364 | ret = PTR_ERR(host->clk); | 1707 | ret = PTR_ERR(host->clk); |
1365 | host->clk = NULL; | 1708 | host->clk = NULL; |
1366 | goto probe_free_host; | 1709 | goto probe_free_dma; |
1367 | } | 1710 | } |
1368 | 1711 | ||
1369 | ret = clk_enable(host->clk); | 1712 | ret = clk_enable(host->clk); |
@@ -1376,7 +1719,11 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1376 | 1719 | ||
1377 | mmc->ops = &s3cmci_ops; | 1720 | mmc->ops = &s3cmci_ops; |
1378 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | 1721 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; |
1722 | #ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ | ||
1723 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; | ||
1724 | #else | ||
1379 | mmc->caps = MMC_CAP_4_BIT_DATA; | 1725 | mmc->caps = MMC_CAP_4_BIT_DATA; |
1726 | #endif | ||
1380 | mmc->f_min = host->clk_rate / (host->clk_div * 256); | 1727 | mmc->f_min = host->clk_rate / (host->clk_div * 256); |
1381 | mmc->f_max = host->clk_rate / host->clk_div; | 1728 | mmc->f_max = host->clk_rate / host->clk_div; |
1382 | 1729 | ||
@@ -1408,8 +1755,12 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1408 | goto free_cpufreq; | 1755 | goto free_cpufreq; |
1409 | } | 1756 | } |
1410 | 1757 | ||
1758 | s3cmci_debugfs_attach(host); | ||
1759 | |||
1411 | platform_set_drvdata(pdev, mmc); | 1760 | platform_set_drvdata(pdev, mmc); |
1412 | dev_info(&pdev->dev, "initialisation done.\n"); | 1761 | dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n", mmc_hostname(mmc), |
1762 | s3cmci_host_usedma(host) ? "dma" : "pio", | ||
1763 | mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw"); | ||
1413 | 1764 | ||
1414 | return 0; | 1765 | return 0; |
1415 | 1766 | ||
@@ -1422,6 +1773,18 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1422 | clk_free: | 1773 | clk_free: |
1423 | clk_put(host->clk); | 1774 | clk_put(host->clk); |
1424 | 1775 | ||
1776 | probe_free_dma: | ||
1777 | if (s3cmci_host_usedma(host)) | ||
1778 | s3c2410_dma_free(host->dma, &s3cmci_dma_client); | ||
1779 | |||
1780 | probe_free_gpio_wp: | ||
1781 | if (!host->pdata->no_wprotect) | ||
1782 | gpio_free(host->pdata->gpio_wprotect); | ||
1783 | |||
1784 | probe_free_gpio_cd: | ||
1785 | if (!host->pdata->no_detect) | ||
1786 | gpio_free(host->pdata->gpio_detect); | ||
1787 | |||
1425 | probe_free_irq_cd: | 1788 | probe_free_irq_cd: |
1426 | if (host->irq_cd >= 0) | 1789 | if (host->irq_cd >= 0) |
1427 | free_irq(host->irq_cd, host); | 1790 | free_irq(host->irq_cd, host); |
@@ -1433,10 +1796,15 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) | |||
1433 | iounmap(host->base); | 1796 | iounmap(host->base); |
1434 | 1797 | ||
1435 | probe_free_mem_region: | 1798 | probe_free_mem_region: |
1436 | release_mem_region(host->mem->start, RESSIZE(host->mem)); | 1799 | release_mem_region(host->mem->start, resource_size(host->mem)); |
1800 | |||
1801 | probe_free_gpio: | ||
1802 | for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) | ||
1803 | gpio_free(i); | ||
1437 | 1804 | ||
1438 | probe_free_host: | 1805 | probe_free_host: |
1439 | mmc_free_host(mmc); | 1806 | mmc_free_host(mmc); |
1807 | |||
1440 | probe_out: | 1808 | probe_out: |
1441 | return ret; | 1809 | return ret; |
1442 | } | 1810 | } |
@@ -1449,6 +1817,7 @@ static void s3cmci_shutdown(struct platform_device *pdev) | |||
1449 | if (host->irq_cd >= 0) | 1817 | if (host->irq_cd >= 0) |
1450 | free_irq(host->irq_cd, host); | 1818 | free_irq(host->irq_cd, host); |
1451 | 1819 | ||
1820 | s3cmci_debugfs_remove(host); | ||
1452 | s3cmci_cpufreq_deregister(host); | 1821 | s3cmci_cpufreq_deregister(host); |
1453 | mmc_remove_host(mmc); | 1822 | mmc_remove_host(mmc); |
1454 | clk_disable(host->clk); | 1823 | clk_disable(host->clk); |
@@ -1458,104 +1827,102 @@ static int __devexit s3cmci_remove(struct platform_device *pdev) | |||
1458 | { | 1827 | { |
1459 | struct mmc_host *mmc = platform_get_drvdata(pdev); | 1828 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
1460 | struct s3cmci_host *host = mmc_priv(mmc); | 1829 | struct s3cmci_host *host = mmc_priv(mmc); |
1830 | struct s3c24xx_mci_pdata *pd = host->pdata; | ||
1831 | int i; | ||
1461 | 1832 | ||
1462 | s3cmci_shutdown(pdev); | 1833 | s3cmci_shutdown(pdev); |
1463 | 1834 | ||
1464 | clk_put(host->clk); | 1835 | clk_put(host->clk); |
1465 | 1836 | ||
1466 | tasklet_disable(&host->pio_tasklet); | 1837 | tasklet_disable(&host->pio_tasklet); |
1467 | s3c2410_dma_free(S3CMCI_DMA, &s3cmci_dma_client); | 1838 | |
1839 | if (s3cmci_host_usedma(host)) | ||
1840 | s3c2410_dma_free(host->dma, &s3cmci_dma_client); | ||
1468 | 1841 | ||
1469 | free_irq(host->irq, host); | 1842 | free_irq(host->irq, host); |
1470 | 1843 | ||
1844 | if (!pd->no_wprotect) | ||
1845 | gpio_free(pd->gpio_wprotect); | ||
1846 | |||
1847 | if (!pd->no_detect) | ||
1848 | gpio_free(pd->gpio_detect); | ||
1849 | |||
1850 | for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) | ||
1851 | gpio_free(i); | ||
1852 | |||
1853 | |||
1471 | iounmap(host->base); | 1854 | iounmap(host->base); |
1472 | release_mem_region(host->mem->start, RESSIZE(host->mem)); | 1855 | release_mem_region(host->mem->start, resource_size(host->mem)); |
1473 | 1856 | ||
1474 | mmc_free_host(mmc); | 1857 | mmc_free_host(mmc); |
1475 | return 0; | 1858 | return 0; |
1476 | } | 1859 | } |
1477 | 1860 | ||
1478 | static int __devinit s3cmci_2410_probe(struct platform_device *dev) | 1861 | static struct platform_device_id s3cmci_driver_ids[] = { |
1479 | { | 1862 | { |
1480 | return s3cmci_probe(dev, 0); | 1863 | .name = "s3c2410-sdi", |
1481 | } | 1864 | .driver_data = 0, |
1865 | }, { | ||
1866 | .name = "s3c2412-sdi", | ||
1867 | .driver_data = 1, | ||
1868 | }, { | ||
1869 | .name = "s3c2440-sdi", | ||
1870 | .driver_data = 1, | ||
1871 | }, | ||
1872 | { } | ||
1873 | }; | ||
1482 | 1874 | ||
1483 | static int __devinit s3cmci_2412_probe(struct platform_device *dev) | 1875 | MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); |
1484 | { | ||
1485 | return s3cmci_probe(dev, 1); | ||
1486 | } | ||
1487 | 1876 | ||
1488 | static int __devinit s3cmci_2440_probe(struct platform_device *dev) | ||
1489 | { | ||
1490 | return s3cmci_probe(dev, 1); | ||
1491 | } | ||
1492 | 1877 | ||
1493 | #ifdef CONFIG_PM | 1878 | #ifdef CONFIG_PM |
1494 | 1879 | ||
1495 | static int s3cmci_suspend(struct platform_device *dev, pm_message_t state) | 1880 | static int s3cmci_suspend(struct device *dev) |
1496 | { | 1881 | { |
1497 | struct mmc_host *mmc = platform_get_drvdata(dev); | 1882 | struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); |
1883 | struct pm_message event = { PM_EVENT_SUSPEND }; | ||
1498 | 1884 | ||
1499 | return mmc_suspend_host(mmc, state); | 1885 | return mmc_suspend_host(mmc, event); |
1500 | } | 1886 | } |
1501 | 1887 | ||
1502 | static int s3cmci_resume(struct platform_device *dev) | 1888 | static int s3cmci_resume(struct device *dev) |
1503 | { | 1889 | { |
1504 | struct mmc_host *mmc = platform_get_drvdata(dev); | 1890 | struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); |
1505 | 1891 | ||
1506 | return mmc_resume_host(mmc); | 1892 | return mmc_resume_host(mmc); |
1507 | } | 1893 | } |
1508 | 1894 | ||
1509 | #else /* CONFIG_PM */ | 1895 | static struct dev_pm_ops s3cmci_pm = { |
1510 | #define s3cmci_suspend NULL | ||
1511 | #define s3cmci_resume NULL | ||
1512 | #endif /* CONFIG_PM */ | ||
1513 | |||
1514 | |||
1515 | static struct platform_driver s3cmci_2410_driver = { | ||
1516 | .driver.name = "s3c2410-sdi", | ||
1517 | .driver.owner = THIS_MODULE, | ||
1518 | .probe = s3cmci_2410_probe, | ||
1519 | .remove = __devexit_p(s3cmci_remove), | ||
1520 | .shutdown = s3cmci_shutdown, | ||
1521 | .suspend = s3cmci_suspend, | 1896 | .suspend = s3cmci_suspend, |
1522 | .resume = s3cmci_resume, | 1897 | .resume = s3cmci_resume, |
1523 | }; | 1898 | }; |
1524 | 1899 | ||
1525 | static struct platform_driver s3cmci_2412_driver = { | 1900 | #define s3cmci_pm_ops &s3cmci_pm |
1526 | .driver.name = "s3c2412-sdi", | 1901 | #else /* CONFIG_PM */ |
1527 | .driver.owner = THIS_MODULE, | 1902 | #define s3cmci_pm_ops NULL |
1528 | .probe = s3cmci_2412_probe, | 1903 | #endif /* CONFIG_PM */ |
1529 | .remove = __devexit_p(s3cmci_remove), | ||
1530 | .shutdown = s3cmci_shutdown, | ||
1531 | .suspend = s3cmci_suspend, | ||
1532 | .resume = s3cmci_resume, | ||
1533 | }; | ||
1534 | 1904 | ||
1535 | static struct platform_driver s3cmci_2440_driver = { | 1905 | |
1536 | .driver.name = "s3c2440-sdi", | 1906 | static struct platform_driver s3cmci_driver = { |
1537 | .driver.owner = THIS_MODULE, | 1907 | .driver = { |
1538 | .probe = s3cmci_2440_probe, | 1908 | .name = "s3c-sdi", |
1909 | .owner = THIS_MODULE, | ||
1910 | .pm = s3cmci_pm_ops, | ||
1911 | }, | ||
1912 | .id_table = s3cmci_driver_ids, | ||
1913 | .probe = s3cmci_probe, | ||
1539 | .remove = __devexit_p(s3cmci_remove), | 1914 | .remove = __devexit_p(s3cmci_remove), |
1540 | .shutdown = s3cmci_shutdown, | 1915 | .shutdown = s3cmci_shutdown, |
1541 | .suspend = s3cmci_suspend, | ||
1542 | .resume = s3cmci_resume, | ||
1543 | }; | 1916 | }; |
1544 | 1917 | ||
1545 | |||
1546 | static int __init s3cmci_init(void) | 1918 | static int __init s3cmci_init(void) |
1547 | { | 1919 | { |
1548 | platform_driver_register(&s3cmci_2410_driver); | 1920 | return platform_driver_register(&s3cmci_driver); |
1549 | platform_driver_register(&s3cmci_2412_driver); | ||
1550 | platform_driver_register(&s3cmci_2440_driver); | ||
1551 | return 0; | ||
1552 | } | 1921 | } |
1553 | 1922 | ||
1554 | static void __exit s3cmci_exit(void) | 1923 | static void __exit s3cmci_exit(void) |
1555 | { | 1924 | { |
1556 | platform_driver_unregister(&s3cmci_2410_driver); | 1925 | platform_driver_unregister(&s3cmci_driver); |
1557 | platform_driver_unregister(&s3cmci_2412_driver); | ||
1558 | platform_driver_unregister(&s3cmci_2440_driver); | ||
1559 | } | 1926 | } |
1560 | 1927 | ||
1561 | module_init(s3cmci_init); | 1928 | module_init(s3cmci_init); |
@@ -1564,6 +1931,3 @@ module_exit(s3cmci_exit); | |||
1564 | MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); | 1931 | MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); |
1565 | MODULE_LICENSE("GPL v2"); | 1932 | MODULE_LICENSE("GPL v2"); |
1566 | MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>"); | 1933 | MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>"); |
1567 | MODULE_ALIAS("platform:s3c2410-sdi"); | ||
1568 | MODULE_ALIAS("platform:s3c2412-sdi"); | ||
1569 | MODULE_ALIAS("platform:s3c2440-sdi"); | ||
diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h index ca1ba3d58cfd..c76b53dbeb61 100644 --- a/drivers/mmc/host/s3cmci.h +++ b/drivers/mmc/host/s3cmci.h | |||
@@ -8,9 +8,6 @@ | |||
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* FIXME: DMA Resource management ?! */ | ||
12 | #define S3CMCI_DMA 0 | ||
13 | |||
14 | enum s3cmci_waitfor { | 11 | enum s3cmci_waitfor { |
15 | COMPLETION_NONE, | 12 | COMPLETION_NONE, |
16 | COMPLETION_FINALIZE, | 13 | COMPLETION_FINALIZE, |
@@ -42,6 +39,11 @@ struct s3cmci_host { | |||
42 | int dodma; | 39 | int dodma; |
43 | int dmatogo; | 40 | int dmatogo; |
44 | 41 | ||
42 | bool irq_disabled; | ||
43 | bool irq_enabled; | ||
44 | bool irq_state; | ||
45 | int sdio_irqen; | ||
46 | |||
45 | struct mmc_request *mrq; | 47 | struct mmc_request *mrq; |
46 | int cmd_is_stop; | 48 | int cmd_is_stop; |
47 | 49 | ||
@@ -68,6 +70,12 @@ struct s3cmci_host { | |||
68 | unsigned int ccnt, dcnt; | 70 | unsigned int ccnt, dcnt; |
69 | struct tasklet_struct pio_tasklet; | 71 | struct tasklet_struct pio_tasklet; |
70 | 72 | ||
73 | #ifdef CONFIG_DEBUG_FS | ||
74 | struct dentry *debug_root; | ||
75 | struct dentry *debug_state; | ||
76 | struct dentry *debug_regs; | ||
77 | #endif | ||
78 | |||
71 | #ifdef CONFIG_CPU_FREQ | 79 | #ifdef CONFIG_CPU_FREQ |
72 | struct notifier_block freq_transition; | 80 | struct notifier_block freq_transition; |
73 | #endif | 81 | #endif |