diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/card/sdio_uart.c | 95 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 13 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 64 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_io.c | 56 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_ops.c | 36 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_ops.h | 1 | ||||
-rw-r--r-- | drivers/mmc/host/Kconfig | 15 | ||||
-rw-r--r-- | drivers/mmc/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/host/at91_mci.c | 224 | ||||
-rw-r--r-- | drivers/mmc/host/bfin_sdh.c | 10 | ||||
-rw-r--r-- | drivers/mmc/host/davinci_mmc.c | 45 | ||||
-rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/ricoh_mmc.c | 262 | ||||
-rw-r--r-- | drivers/mmc/host/s3cmci.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 24 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 76 | ||||
-rw-r--r-- | drivers/mmc/host/tmio_mmc.c | 13 | ||||
-rw-r--r-- | drivers/mmc/host/tmio_mmc.h | 6 |
19 files changed, 395 insertions, 558 deletions
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index f537555..723e508 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -37,6 +37,7 @@ #include <linux/gfp.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/kfifo.h> #include <linux/mmc/core.h> #include <linux/mmc/card.h> @@ -47,19 +48,9 @@ #define UART_NR 8 /* Number of UARTs this driver can handle */ -#define UART_XMIT_SIZE PAGE_SIZE +#define FIFO_SIZE PAGE_SIZE #define WAKEUP_CHARS 256 -#define circ_empty(circ) ((circ)->head == (circ)->tail) -#define circ_clear(circ) ((circ)->head = (circ)->tail = 0) - -#define circ_chars_pending(circ) \ - (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) - -#define circ_chars_free(circ) \ - (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) - - struct uart_icount { __u32 cts; __u32 dsr; @@ -82,7 +73,7 @@ struct sdio_uart_port { struct mutex func_lock; struct task_struct *in_sdio_uart_irq; unsigned int regs_offset; - struct circ_buf xmit; + struct kfifo xmit_fifo; spinlock_t write_lock; struct uart_icount icount; unsigned int uartclk; @@ -105,6 +96,8 @@ static int sdio_uart_add_port(struct sdio_uart_port *port) kref_init(&port->kref); mutex_init(&port->func_lock); spin_lock_init(&port->write_lock); + if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL)) + return -ENOMEM; spin_lock(&sdio_uart_table_lock); for (index = 0; index < UART_NR; index++) { @@ -140,6 +133,7 @@ static void sdio_uart_port_destroy(struct kref *kref) { struct sdio_uart_port *port = container_of(kref, struct sdio_uart_port, kref); + kfifo_free(&port->xmit_fifo); kfree(port); } @@ -456,9 +450,11 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, static void sdio_uart_transmit_chars(struct sdio_uart_port *port) { - struct circ_buf *xmit = &port->xmit; + struct kfifo *xmit = &port->xmit_fifo; int count; struct tty_struct *tty; + u8 iobuf[16]; + int len; if (port->x_char) { sdio_out(port, UART_TX, port->x_char); @@ -469,27 +465,25 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) tty = tty_port_tty_get(&port->port); - if (tty == NULL || circ_empty(xmit) || + if (tty == NULL || !kfifo_len(xmit) || tty->stopped || tty->hw_stopped) { sdio_uart_stop_tx(port); tty_kref_put(tty); return; } - count = 16; - do { - sdio_out(port, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + len = kfifo_out_locked(xmit, iobuf, 16, &port->write_lock); + for (count = 0; count < len; count++) { + sdio_out(port, UART_TX, iobuf[count]); port->icount.tx++; - if (circ_empty(xmit)) - break; - } while (--count > 0); + } - if (circ_chars_pending(xmit) < WAKEUP_CHARS) + len = kfifo_len(xmit); + if (len < WAKEUP_CHARS) { tty_wakeup(tty); - - if (circ_empty(xmit)) - sdio_uart_stop_tx(port); + if (len == 0) + sdio_uart_stop_tx(port); + } tty_kref_put(tty); } @@ -581,7 +575,7 @@ static int uart_carrier_raised(struct tty_port *tport) struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); unsigned int ret = sdio_uart_claim_func(port); - if (ret) /* Missing hardware shoudn't block for carrier */ + if (ret) /* Missing hardware shouldn't block for carrier */ return 1; ret = sdio_uart_get_mctrl(port); sdio_uart_release_func(port); @@ -632,7 +626,6 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) { struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); - unsigned long page; int ret; /* @@ -641,22 +634,17 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) */ set_bit(TTY_IO_ERROR, &tty->flags); - /* Initialise and allocate the transmit buffer. */ - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - port->xmit.buf = (unsigned char *)page; - circ_clear(&port->xmit); + kfifo_reset(&port->xmit_fifo); ret = sdio_uart_claim_func(port); if (ret) - goto err1; + return ret; ret = sdio_enable_func(port->func); if (ret) - goto err2; + goto err1; ret = sdio_claim_irq(port->func, sdio_uart_irq); if (ret) - goto err3; + goto err2; /* * Clear the FIFO buffers and disable them. @@ -700,12 +688,10 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) sdio_uart_release_func(port); return 0; -err3: - sdio_disable_func(port->func); err2: - sdio_uart_release_func(port); + sdio_disable_func(port->func); err1: - free_page((unsigned long)port->xmit.buf); + sdio_uart_release_func(port); return ret; } @@ -727,7 +713,7 @@ static void sdio_uart_shutdown(struct tty_port *tport) ret = sdio_uart_claim_func(port); if (ret) - goto skip; + return; sdio_uart_stop_rx(port); @@ -749,10 +735,6 @@ static void sdio_uart_shutdown(struct tty_port *tport) sdio_disable_func(port->func); sdio_uart_release_func(port); - -skip: - /* Free the transmit buffer page. */ - free_page((unsigned long)port->xmit.buf); } /** @@ -822,27 +804,12 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct sdio_uart_port *port = tty->driver_data; - struct circ_buf *circ = &port->xmit; - int c, ret = 0; + int ret; if (!port->func) return -ENODEV; - spin_lock(&port->write_lock); - while (1) { - c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(circ->buf + circ->head, buf, c); - circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); - buf += c; - count -= c; - ret += c; - } - spin_unlock(&port->write_lock); - + ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock); if (!(port->ier & UART_IER_THRI)) { int err = sdio_uart_claim_func(port); if (!err) { @@ -859,13 +826,13 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf, static int sdio_uart_write_room(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - return port ? circ_chars_free(&port->xmit) : 0; + return FIFO_SIZE - kfifo_len(&port->xmit_fifo); } static int sdio_uart_chars_in_buffer(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - return port ? circ_chars_pending(&port->xmit) : 0; + return kfifo_len(&port->xmit_fifo); } static void sdio_uart_send_xchar(struct tty_struct *tty, char ch) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 30acd52..3168ebd 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1089,6 +1089,7 @@ void mmc_rescan(struct work_struct *work) mmc_claim_host(host); mmc_power_up(host); + sdio_reset(host); mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); @@ -1151,6 +1152,9 @@ void mmc_stop_host(struct mmc_host *host) cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); + /* clear pm flags now and let card drivers set them as needed */ + host->pm_flags = 0; + mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { if (host->bus_ops->remove) @@ -1273,12 +1277,13 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state) mmc_claim_host(host); mmc_detach_bus(host); mmc_release_host(host); + host->pm_flags = 0; err = 0; } } mmc_bus_put(host); - if (!err) + if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER)) mmc_power_off(host); return err; @@ -1296,8 +1301,10 @@ int mmc_resume_host(struct mmc_host *host) mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { - mmc_power_up(host); - mmc_select_voltage(host, host->ocr); + if (!(host->pm_flags & MMC_PM_KEEP_POWER)) { + mmc_power_up(host); + mmc_select_voltage(host, host->ocr); + } BUG_ON(!host->bus_ops->resume); err = host->bus_ops->resume(host); if (err) { diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 06b6408..2dd4cfe 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -188,6 +188,40 @@ static int sdio_disable_cd(struct mmc_card *card) } /* + * Devices that remain active during a system suspend are + * put back into 1-bit mode. + */ +static int sdio_disable_wide(struct mmc_card *card) +{ + int ret; + u8 ctrl; + + if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) + return 0; + + if (card->cccr.low_speed && !card->cccr.wide_bus) + return 0; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl); + if (ret) + return ret; + + if (!(ctrl & SDIO_BUS_WIDTH_4BIT)) + return 0; + + ctrl &= ~SDIO_BUS_WIDTH_4BIT; + ctrl |= SDIO_BUS_ASYNC_INT; + + ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); + if (ret) + return ret; + + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_1); + + return 0; +} + +/* * Test if the card supports high-speed mode and, if so, switch to it. */ static int sdio_enable_hs(struct mmc_card *card) @@ -224,7 +258,7 @@ static int sdio_enable_hs(struct mmc_card *card) * we're trying to reinitialise. */ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, - struct mmc_card *oldcard) + struct mmc_card *oldcard, int powered_resume) { struct mmc_card *card; int err; @@ -235,9 +269,11 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, /* * Inform the card of the voltage */ - err = mmc_send_io_op_cond(host, host->ocr, &ocr); - if (err) - goto err; + if (!powered_resume) { + err = mmc_send_io_op_cond(host, host->ocr, &ocr); + if (err) + goto err; + } /* * For SPI, enable CRC as appropriate. @@ -262,7 +298,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, /* * For native busses: set card RCA and quit open drain mode. */ - if (!mmc_host_is_spi(host)) { + if (!powered_resume && !mmc_host_is_spi(host)) { err = mmc_send_relative_addr(host, &card->rca); if (err) goto remove; @@ -273,7 +309,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, /* * Select card, as all following commands rely on that. */ - if (!mmc_host_is_spi(host)) { + if (!powered_resume && !mmc_host_is_spi(host)) { err = mmc_select_card(card); if (err) goto remove; @@ -425,6 +461,12 @@ static int mmc_sdio_suspend(struct mmc_host *host) } } + if (!err && host->pm_flags & MMC_PM_KEEP_POWER) { + mmc_claim_host(host); + sdio_disable_wide(host->card); + mmc_release_host(host); + } + return err; } @@ -437,7 +479,13 @@ static int mmc_sdio_resume(struct mmc_host *host) /* Basic card reinitialization. */ mmc_claim_host(host); - err = mmc_sdio_init_card(host, host->ocr, host->card); + err = mmc_sdio_init_card(host, host->ocr, host->card, + (host->pm_flags & MMC_PM_KEEP_POWER)); + if (!err) + /* We may have switched to 1-bit mode during suspend. */ + err = sdio_enable_wide(host->card); + if (!err && host->sdio_irqs) + mmc_signal_sdio_irq(host); mmc_release_host(host); /* @@ -507,7 +555,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) /* * Detect and init the card. */ - err = mmc_sdio_init_card(host, host->ocr, NULL); + err = mmc_sdio_init_card(host, host->ocr, NULL, 0); if (err) goto err; card = host->card; diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index f9aa8a7..ff27c8c 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -189,7 +189,12 @@ static inline unsigned int sdio_max_byte_size(struct sdio_func *func) { unsigned mval = min(func->card->host->max_seg_size, func->card->host->max_blk_size); - mval = min(mval, func->max_blksize); + + if (mmc_blksz_for_byte_mode(func->card)) + mval = min(mval, func->cur_blksize); + else + mval = min(mval, func->max_blksize); + return min(mval, 512u); /* maximum size for byte mode */ } @@ -635,3 +640,52 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, *err_ret = ret; } EXPORT_SYMBOL_GPL(sdio_f0_writeb); + +/** + * sdio_get_host_pm_caps - get host power management capabilities + * @func: SDIO function attached to host + * + * Returns a capability bitmask corresponding to power management + * features supported by the host controller that the card function + * might rely upon during a system suspend. The host doesn't need + * to be claimed, nor the function active, for this information to be + * obtained. + */ +mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func) +{ + BUG_ON(!func); + BUG_ON(!func->card); + + return func->card->host->pm_caps; +} +EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps); + +/** + * sdio_set_host_pm_flags - set wanted host power management capabilities + * @func: SDIO function attached to host + * + * Set a capability bitmask corresponding to wanted host controller + * power management features for the upcoming suspend state. + * This must be called, if needed, each time the suspend method of + * the function driver is called, and must contain only bits that + * were returned by sdio_get_host_pm_caps(). + * The host doesn't need to be claimed, nor the function active, + * for this information to be set. + */ +int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags) +{ + struct mmc_host *host; + + BUG_ON(!func); + BUG_ON(!func->card); + + host = func->card->host; + + if (flags & ~host->pm_caps) + return -EINVAL; + + /* function suspend methods are serialized, hence no lock needed */ + host->pm_flags |= flags; + return 0; +} +EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags); diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 4eb7825..dea36d9 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -67,13 +67,13 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) return err; } -int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, - unsigned addr, u8 in, u8* out) +static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn, + unsigned addr, u8 in, u8 *out) { struct mmc_command cmd; int err; - BUG_ON(!card); + BUG_ON(!host); BUG_ON(fn > 7); /* sanity check */ @@ -90,11 +90,11 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, cmd.arg |= in; cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, 0); + err = mmc_wait_for_cmd(host, &cmd, 0); if (err) return err; - if (mmc_host_is_spi(card->host)) { + if (mmc_host_is_spi(host)) { /* host driver already reported errors */ } else { if (cmd.resp[0] & R5_ERROR) @@ -106,7 +106,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, } if (out) { - if (mmc_host_is_spi(card->host)) + if (mmc_host_is_spi(host)) *out = (cmd.resp[0] >> 8) & 0xFF; else *out = cmd.resp[0] & 0xFF; @@ -115,6 +115,13 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, return 0; } +int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8 *out) +{ + BUG_ON(!card); + return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out); +} + int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { @@ -182,3 +189,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, return 0; } +int sdio_reset(struct mmc_host *host) +{ + int ret; + u8 abort; + + /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */ + + ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort); + if (ret) + abort = 0x08; + else + abort |= 0x08; + + ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL); + return ret; +} + diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index e2e74b0..12a4d3a 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -17,6 +17,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out); int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); +int sdio_reset(struct mmc_host *host); #endif diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index ce1d288..2e13b94 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -69,20 +69,16 @@ config MMC_SDHCI_PCI If unsure, say N. config MMC_RICOH_MMC - tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)" + bool "Ricoh MMC Controller Disabler (EXPERIMENTAL)" depends on MMC_SDHCI_PCI help - This selects the disabler for the Ricoh MMC Controller. This + This adds a pci quirk to disable Ricoh MMC Controller. This proprietary controller is unnecessary because the SDHCI driver supports MMC cards on the SD controller, but if it is not disabled, it will steal the MMC cards away - rendering them - useless. It is safe to select this driver even if you don't + useless. It is safe to select this even if you don't have a Ricoh based card reader. - - To compile this driver as a module, choose M here: - the module will be called ricoh_mmc. - If unsure, say Y. config MMC_SDHCI_OF @@ -193,6 +189,7 @@ config MMC_AU1X choice prompt "Atmel SD/MMC Driver" + depends on AVR32 || ARCH_AT91 default MMC_ATMELMCI if AVR32 help Choose which driver to use for the Atmel MCI Silicon @@ -368,7 +365,7 @@ config MMC_SDRICOH_CS config MMC_TMIO tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" - depends on MFD_TMIO || MFD_ASIC3 || SUPERH + depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI help This provides support for the SD/MMC cell found in TC6393XB, T7L66XB and also HTC ASIC3 @@ -399,7 +396,7 @@ config MMC_VIA_SDMMC config SDH_BFIN tristate "Blackfin Secure Digital Host support" - depends on MMC && ((BF54x && !BF544) || (BF51x && !BF512)) + depends on (BF54x && !BF544) || (BF51x && !BF512) help If you say yes here you will get support for the Blackfin on-chip Secure Digital Host interface. This includes support for MMC and diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 3d253dd..f480397 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o -obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o obj-$(CONFIG_MMC_WBSD) += wbsd.o diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 63924e0..91dc60c 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -78,6 +78,17 @@ #define DRIVER_NAME "at91_mci" +static inline int at91mci_is_mci1rev2xx(void) +{ + return ( cpu_is_at91sam9260() + || cpu_is_at91sam9263() + || cpu_is_at91cap9() + || cpu_is_at91sam9rl() + || cpu_is_at91sam9g10() + || cpu_is_at91sam9g20() + ); +} + #define FL_SENT_COMMAND (1 << 0) #define FL_SENT_STOP (1 << 1) @@ -88,6 +99,10 @@ #define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg)) #define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg)) +#define MCI_BLKSIZE 512 +#define MCI_MAXBLKSIZE 4095 +#define MCI_BLKATONCE 256 +#define MCI_BUFSIZE (MCI_BLKSIZE * MCI_BLKATONCE) /* * Low level type for this driver @@ -200,8 +215,8 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data size = data->blksz * data->blocks; len = data->sg_len; - /* AT91SAM926[0/3] Data Write Operation and number of bytes erratum */ - if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) + /* MCI1 rev2xx Data Write Operation and number of bytes erratum */ + if (at91mci_is_mci1rev2xx()) if (host->total_length == 12) memset(dmabuf, 0, 12); @@ -227,8 +242,10 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data for (index = 0; index < (amount / 4); index++) *dmabuf++ = swab32(sgbuffer[index]); } else { - memcpy(dmabuf, sgbuffer, amount); - dmabuf += amount; + char *tmpv = (char *)dmabuf; + memcpy(tmpv, sgbuffer, amount); + tmpv += amount; + dmabuf = (unsigned *)tmpv; } kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); @@ -245,80 +262,14 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data } /* - * Prepare a dma read - */ -static void at91_mci_pre_dma_read(struct at91mci_host *host) -{ - int i; - struct scatterlist *sg; - struct mmc_command *cmd; - struct mmc_data *data; - - pr_debug("pre dma read\n"); - - cmd = host->cmd; - if (!cmd) { - pr_debug("no command\n"); - return; - } - - data = cmd->data; - if (!data) { - pr_debug("no data\n"); - return; - } - - for (i = 0; i < 2; i++) { - /* nothing left to transfer */ - if (host->transfer_index >= data->sg_len) { - pr_debug("Nothing left to transfer (index = %d)\n", host->transfer_index); - break; - } - - /* Check to see if this needs filling */ - if (i == 0) { - if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) { - pr_debug("Transfer active in current\n"); - continue; - } - } - else { - if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) { - pr_debug("Transfer active in next\n"); - continue; - } - } - - /* Setup the next transfer */ - pr_debug("Using transfer index %d\n", host->transfer_index); - - sg = &data->sg[host->transfer_index++]; - pr_debug("sg = %p\n", sg); - - sg->dma_address = dma_map_page(NULL, sg_page(sg), sg->offset, sg->length, DMA_FROM_DEVICE); - - pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length); - - if (i == 0) { - at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address); - at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ? sg->length : sg->length / 4); - } - else { - at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address); - at91_mci_write(host, ATMEL_PDC_RNCR, (data->blksz & 0x3) ? sg->length : sg->length / 4); - } - } - - pr_debug("pre dma read done\n"); -} - -/* * Handle after a dma read */ static void at91_mci_post_dma_read(struct at91mci_host *host) { struct mmc_command *cmd; struct mmc_data *data; + unsigned int len, i, size; + unsigned *dmabuf = host->buffer; pr_debug("post dma read\n"); @@ -334,42 +285,39 @@ static void at91_mci_post_dma_read(struct at91mci_host *host) return; } - while (host->in_use_index < host->transfer_index) { - struct scatterlist *sg; + size = data->blksz * data->blocks; + len = data->sg_len; - pr_debug("finishing index %d\n", host->in_use_index); + at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); - sg = &data->sg[host->in_use_index++]; + for (i = 0; i < len; i++) { + struct scatterlist *sg; + int amount; + unsigned int *sgbuffer; - pr_debug("Unmapping page %08X\n", sg->dma_address); + sg = &data->sg[i]; - dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE); + sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + amount = min(size, sg->length); + size -= amount; if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */ - unsigned int *buffer; int index; - - /* Swap the contents of the buffer */ - buffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; - pr_debug("buffer = %p, length = %d\n", buffer, sg->length); - - for (index = 0; index < (sg->length / 4); index++) - buffer[index] = swab32(buffer[index]); - - kunmap_atomic(buffer, KM_BIO_SRC_IRQ); + for (index = 0; index < (amount / 4); index++) + sgbuffer[index] = swab32(*dmabuf++); + } else { + char *tmpv = (char *)dmabuf; + memcpy(sgbuffer, tmpv, amount); + tmpv += amount; + dmabuf = (unsigned *)tmpv; } - flush_dcache_page(sg_page(sg)); - - data->bytes_xfered += sg->length; - } - - /* Is there another transfer to trigger? */ - if (host->transfer_index < data->sg_len) - at91_mci_pre_dma_read(host); - else { - at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX); - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); + kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); + dmac_flush_range((void *)sgbuffer, ((void *)sgbuffer) + amount); + data->bytes_xfered += amount; + if (size == 0) + break; } pr_debug("post dma read done\n"); @@ -461,7 +409,7 @@ static void at91_mci_enable(struct at91mci_host *host) at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); mr = AT91_MCI_PDCMODE | 0x34a; - if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) + if (at91mci_is_mci1rev2xx()) mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF; at91_mci_write(host, AT91_MCI_MR, mr); @@ -602,10 +550,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command /* * Handle a read */ - host->buffer = NULL; host->total_length = 0; - at91_mci_pre_dma_read(host); + at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address); + at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ? + (blocks * block_length) : (blocks * block_length) / 4); + at91_mci_write(host, ATMEL_PDC_RNPR, 0); + at91_mci_write(host, ATMEL_PDC_RNCR, 0); + ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; } else { @@ -614,27 +566,15 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command */ host->total_length = block_length * blocks; /* - * AT91SAM926[0/3] Data Write Operation and + * MCI1 rev2xx Data Write Operation and * number of bytes erratum */ - if (cpu_is_at91sam9260 () || cpu_is_at91sam9263()) + if (at91mci_is_mci1rev2xx()) if (host->total_length < 12) host->total_length = 12; - host->buffer = kmalloc(host->total_length, GFP_KERNEL); - if (!host->buffer) { - pr_debug("Can't alloc tx buffer\n"); - cmd->error = -ENOMEM; - mmc_request_done(host->mmc, host->request); - return; - } - at91_mci_sg_to_dma(host, data); - host->physical_address = dma_map_single(NULL, - host->buffer, host->total_length, - DMA_TO_DEVICE); - pr_debug("Transmitting %d bytes\n", host->total_length); at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); @@ -701,14 +641,6 @@ static void at91_mci_completed_command(struct at91mci_host *host, unsigned int s cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2)); cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3)); - if (host->buffer) { - dma_unmap_single(NULL, - host->physical_address, host->total_length, - DMA_TO_DEVICE); - kfree(host->buffer); - host->buffer = NULL; - } - pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n", status, at91_mci_read(host, AT91_MCI_SR), cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); @@ -754,7 +686,8 @@ static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->request = mrq; host->flags = 0; - mod_timer(&host->timer, jiffies + HZ); + /* more than 1s timeout needed with slow SD cards */ + mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); at91_mci_process_next(host); } @@ -942,7 +875,8 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host) pr_debug("****** Resetting SD-card bus width ******\n"); at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); } - mmc_detect_change(host->mmc, msecs_to_jiffies(100)); + /* 0.5s needed because of early card detect switch firing */ + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); } return IRQ_HANDLED; } @@ -1006,24 +940,42 @@ static int __init at91_mci_probe(struct platform_device *pdev) mmc->f_min = 375000; mmc->f_max = 25000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_SDIO_IRQ; + mmc->caps = 0; - mmc->max_blk_size = 4095; - mmc->max_blk_count = mmc->max_req_size; + mmc->max_blk_size = MCI_MAXBLKSIZE; + mmc->max_blk_count = MCI_BLKATONCE; + mmc->max_req_size = MCI_BUFSIZE; + mmc->max_phys_segs = MCI_BLKATONCE; + mmc->max_hw_segs = MCI_BLKATONCE; + mmc->max_seg_size = MCI_BUFSIZE; host = mmc_priv(mmc); host->mmc = mmc; - host->buffer = NULL; host->bus_mode = 0; host->board = pdev->dev.platform_data; if (host->board->wire4) { - if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) + if (at91mci_is_mci1rev2xx()) mmc->caps |= MMC_CAP_4_BIT_DATA; else dev_warn(&pdev->dev, "4 wire bus mode not supported" " - using 1 wire\n"); } + host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE, + &host->physical_address, GFP_KERNEL); + if (!host->buffer) { + ret = -ENOMEM; + dev_err(&pdev->dev, "Can't allocate transmit buffer\n"); + goto fail5; + } + + /* Add SDIO capability when available */ + if (at91mci_is_mci1rev2xx()) { + /* at91mci MCI1 rev2xx sdio interrupt erratum */ + if (host->board->wire4 || !host->board->slot_b) + mmc->caps |= MMC_CAP_SDIO_IRQ; + } + /* * Reserve GPIOs ... board init code makes sure these pins are set * up as GPIOs with the right direction (input, except for vcc) @@ -1032,7 +984,7 @@ static int __init at91_mci_probe(struct platform_device *pdev) ret = gpio_request(host->board->det_pin, "mmc_detect"); if (ret < 0) { dev_dbg(&pdev->dev, "couldn't claim card detect pin\n"); - goto fail5; + goto fail4b; } } if (host->board->wp_pin) { @@ -1132,6 +1084,10 @@ fail3: fail4: if (host->board->det_pin) gpio_free(host->board->det_pin); +fail4b: + if (host->buffer) + dma_free_coherent(&pdev->dev, MCI_BUFSIZE, + host->buffer, host->physical_address); fail5: mmc_free_host(mmc); fail6: @@ -1154,6 +1110,10 @@ static int __exit at91_mci_remove(struct platform_device *pdev) host = mmc_priv(mmc); + if (host->buffer) + dma_free_coherent(&pdev->dev, MCI_BUFSIZE, + host->buffer, host->physical_address); + if (host->board->det_pin) { if (device_can_wakeup(&pdev->dev)) free_irq(gpio_to_irq(host->board->det_pin), host); diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index 3343a57..56f7b44 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c @@ -115,7 +115,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) unsigned int length; unsigned int data_ctl; unsigned int dma_cfg; - struct scatterlist *sg; + unsigned int cycle_ns, timeout; dev_dbg(mmc_dev(host->mmc), "%s enter flags: 0x%x\n", __func__, data->flags); host->data = data; @@ -136,8 +136,11 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) data_ctl |= ((ffs(data->blksz) - 1) << 4); bfin_write_SDH_DATA_CTL(data_ctl); - - bfin_write_SDH_DATA_TIMER(0xFFFF); + /* the time of a host clock period in ns */ + cycle_ns = 1000000000 / (get_sclk() / (2 * (host->clk_div + 1))); + timeout = data->timeout_ns / cycle_ns; + timeout += data->timeout_clks; + bfin_write_SDH_DATA_TIMER(timeout); SSYNC(); if (data->flags & MMC_DATA_READ) { @@ -151,6 +154,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) #if defined(CONFIG_BF54x) dma_cfg |= DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_32 | DMAEN; { + struct scatterlist *sg; int i; for_each_sg(data->sg, sg, host->dma_len, i) { host->sg_cpu[i].start_addr = sg_dma_address(sg); diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index dd45e7c..3bd0ba2 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -73,6 +73,7 @@ /* DAVINCI_MMCCTL definitions */ #define MMCCTL_DATRST (1 << 0) #define MMCCTL_CMDRST (1 << 1) +#define MMCCTL_WIDTH_8_BIT (1 << 8) #define MMCCTL_WIDTH_4_BIT (1 << 2) #define MMCCTL_DATEG_DISABLED (0 << 6) #define MMCCTL_DATEG_RISING (1 << 6) @@ -791,22 +792,42 @@ static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios) static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { - unsigned int mmc_pclk = 0; struct mmc_davinci_host *host = mmc_priv(mmc); - mmc_pclk = host->mmc_input_clk; dev_dbg(mmc_dev(host->mmc), "clock %dHz busmode %d powermode %d Vdd %04x\n", ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); - if (ios->bus_width == MMC_BUS_WIDTH_4) { - dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n"); - writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_WIDTH_4_BIT, - host->base + DAVINCI_MMCCTL); - } else { - dev_dbg(mmc_dev(host->mmc), "Disabling 4 bit mode\n"); - writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_WIDTH_4_BIT, + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_8: + dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n"); + writel((readl(host->base + DAVINCI_MMCCTL) & + ~MMCCTL_WIDTH_4_BIT) | MMCCTL_WIDTH_8_BIT, host->base + DAVINCI_MMCCTL); + break; + case MMC_BUS_WIDTH_4: + dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n"); + if (host->version == MMC_CTLR_VERSION_2) + writel((readl(host->base + DAVINCI_MMCCTL) & + ~MMCCTL_WIDTH_8_BIT) | MMCCTL_WIDTH_4_BIT, + host->base + DAVINCI_MMCCTL); + else + writel(readl(host->base + DAVINCI_MMCCTL) | + MMCCTL_WIDTH_4_BIT, + host->base + DAVINCI_MMCCTL); + break; + case MMC_BUS_WIDTH_1: + dev_dbg(mmc_dev(host->mmc), "Enabling 1 bit mode\n"); + if (host->version == MMC_CTLR_VERSION_2) + writel(readl(host->base + DAVINCI_MMCCTL) & + ~(MMCCTL_WIDTH_8_BIT | MMCCTL_WIDTH_4_BIT), + host->base + DAVINCI_MMCCTL); + else + writel(readl(host->base + DAVINCI_MMCCTL) & + ~MMCCTL_WIDTH_4_BIT, + host->base + DAVINCI_MMCCTL); + break; } calculate_clk_divider(mmc, ios); @@ -1189,10 +1210,14 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) /* REVISIT: someday, support IRQ-driven card detection. */ mmc->caps |= MMC_CAP_NEEDS_POLL; + mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; - if (!pdata || pdata->wires == 4 || pdata->wires == 0) + if (pdata && (pdata->wires == 4 || pdata->wires == 0)) mmc->caps |= MMC_CAP_4_BIT_DATA; + if (pdata && (pdata->wires == 8)) + mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA); + host->version = pdata->version; mmc->ops = &mmc_davinci_ops; diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index b31946e..4c068e5 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1250,9 +1250,7 @@ msmsdcc_resume(struct platform_device *dev) if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) mmc_resume_host(mmc); - if (host->stat_irq) - enable_irq(host->stat_irq); - else if (host->stat_irq) + if (host->stat_irq) enable_irq(host->stat_irq); } return 0; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 60a2b69..2df9041 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -4,7 +4,7 @@ * This is a driver for the SDHC controller found in Freescale MX2/MX3 * SoCs. It is basically the same hardware as found on MX1 (imxmmc.c). * Unlike the hardware found on MX1, this hardware just works and does - * not need all the quirks found in imxmmc.c, hence the seperate driver. + * not need all the quirks found in imxmmc.c, hence the separate driver. * * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> @@ -708,7 +708,7 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->max_blk_size = 2048; mmc->max_blk_count = 65535; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_seg_size = mmc->max_seg_size; + mmc->max_seg_size = mmc->max_req_size; host = mmc_priv(mmc); host->base = ioremap(r->start, resource_size(r)); diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c deleted file mode 100644 index f627905..0000000 --- a/drivers/mmc/host/ricoh_mmc.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller. - * - * Copyright (C) 2007 Philip Langdale, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -/* - * This is a conceptually ridiculous driver, but it is required by the way - * the Ricoh multi-function chips (R5CXXX) work. These chips implement - * the four main memory card controllers (SD, MMC, MS, xD) and one or both - * of cardbus or firewire. It happens that they implement SD and MMC - * support as separate controllers (and PCI functions). The linux SDHCI - * driver supports MMC cards but the chip detects MMC cards in hardware - * and directs them to the MMC controller - so the SDHCI driver never sees - * them. To get around this, we must disable the useless MMC controller. - * At that point, the SDHCI controller will start seeing them. As a bonus, - * a detection event occurs immediately, even if the MMC card is already - * in the reader. - * - * It seems to be the case that the relevant PCI registers to deactivate the - * MMC controller live on PCI function 0, which might be the cardbus controller - * or the firewire controller, depending on the particular chip in question. As - * such, it makes what this driver has to do unavoidably ugly. Such is life. - */ - -#include <linux/pci.h> - -#define DRIVER_NAME "ricoh-mmc" - -static const struct pci_device_id pci_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = PCI_DEVICE_ID_RICOH_R5C843, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { /* end: all zeroes */ }, -}; - -MODULE_DEVICE_TABLE(pci, pci_ids); - -static int ricoh_mmc_disable(struct pci_dev *fw_dev) -{ - u8 write_enable; - u8 write_target; - u8 disable; - - if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) { - /* via RL5C476 */ - - pci_read_config_byte(fw_dev, 0xB7, &disable); - if (disable & 0x02) { - printk(KERN_INFO DRIVER_NAME - ": Controller already disabled. " \ - "Nothing to do.\n"); - return -ENODEV; - } - - pci_read_config_byte(fw_dev, 0x8E, &write_enable); - pci_write_config_byte(fw_dev, 0x8E, 0xAA); - pci_read_config_byte(fw_dev, 0x8D, &write_target); - pci_write_config_byte(fw_dev, 0x8D, 0xB7); - pci_write_config_byte(fw_dev, 0xB7, disable | 0x02); - pci_write_config_byte(fw_dev, 0x8E, write_enable); - pci_write_config_byte(fw_dev, 0x8D, write_target); - } else { - /* via R5C832 */ - - pci_read_config_byte(fw_dev, 0xCB, &disable); - if (disable & 0x02) { - printk(KERN_INFO DRIVER_NAME - ": Controller already disabled. " \ - "Nothing to do.\n"); - return -ENODEV; - } - - pci_read_config_byte(fw_dev, 0xCA, &write_enable); - pci_write_config_byte(fw_dev, 0xCA, 0x57); - pci_write_config_byte(fw_dev, 0xCB, disable | 0x02); - pci_write_config_byte(fw_dev, 0xCA, write_enable); - } - - printk(KERN_INFO DRIVER_NAME - ": Controller is now disabled.\n"); - - return 0; -} - -static int ricoh_mmc_enable(struct pci_dev *fw_dev) -{ - u8 write_enable; - u8 write_target; - u8 disable; - - if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) { - /* via RL5C476 */ - - pci_read_config_byte(fw_dev, 0x8E, &write_enable); - pci_write_config_byte(fw_dev, 0x8E, 0xAA); - pci_read_config_byte(fw_dev, 0x8D, &write_target); - pci_write_config_byte(fw_dev, 0x8D, 0xB7); - pci_read_config_byte(fw_dev, 0xB7, &disable); - pci_write_config_byte(fw_dev, 0xB7, disable & ~0x02); - pci_write_config_byte(fw_dev, 0x8E, write_enable); - pci_write_config_byte(fw_dev, 0x8D, write_target); - } else { - /* via R5C832 */ - - pci_read_config_byte(fw_dev, 0xCA, &write_enable); - pci_read_config_byte(fw_dev, 0xCB, &disable); - pci_write_config_byte(fw_dev, 0xCA, 0x57); - pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02); - pci_write_config_byte(fw_dev, 0xCA, write_enable); - } - - printk(KERN_INFO DRIVER_NAME - ": Controller is now re-enabled.\n"); - - return 0; -} - -static int __devinit ricoh_mmc_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - u8 rev; - u8 ctrlfound = 0; - - struct pci_dev *fw_dev = NULL; - - BUG_ON(pdev == NULL); - BUG_ON(ent == NULL); - - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev); - - printk(KERN_INFO DRIVER_NAME - ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n", - pci_name(pdev), (int)pdev->vendor, (int)pdev->device, - (int)rev); - - while ((fw_dev = - pci_get_device(PCI_VENDOR_ID_RICOH, - PCI_DEVICE_ID_RICOH_RL5C476, fw_dev))) { - if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && - PCI_FUNC(fw_dev->devfn) == 0 && - pdev->bus == fw_dev->bus) { - if (ricoh_mmc_disable(fw_dev) != 0) - return -ENODEV; - - pci_set_drvdata(pdev, fw_dev); - - ++ctrlfound; - break; - } - } - - fw_dev = NULL; - - while (!ctrlfound && - (fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, - PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) { - if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && - PCI_FUNC(fw_dev->devfn) == 0 && - pdev->bus == fw_dev->bus) { - if (ricoh_mmc_disable(fw_dev) != 0) - return -ENODEV; - - pci_set_drvdata(pdev, fw_dev); - - ++ctrlfound; - } - } - - if (!ctrlfound) { - printk(KERN_WARNING DRIVER_NAME - ": Main Ricoh function not found. Cannot disable controller.\n"); - return -ENODEV; - } - - return 0; -} - -static void __devexit ricoh_mmc_remove(struct pci_dev *pdev) -{ - struct pci_dev *fw_dev = NULL; - - fw_dev = pci_get_drvdata(pdev); - BUG_ON(fw_dev == NULL); - - ricoh_mmc_enable(fw_dev); - - pci_set_drvdata(pdev, NULL); -} - -static int ricoh_mmc_suspend_late(struct pci_dev *pdev, pm_message_t state) -{ - struct pci_dev *fw_dev = NULL; - - fw_dev = pci_get_drvdata(pdev); - BUG_ON(fw_dev == NULL); - - printk(KERN_INFO DRIVER_NAME ": Suspending.\n"); - - ricoh_mmc_enable(fw_dev); - - return 0; -} - -static int ricoh_mmc_resume_early(struct pci_dev *pdev) -{ - struct pci_dev *fw_dev = NULL; - - fw_dev = pci_get_drvdata(pdev); - BUG_ON(fw_dev == NULL); - - printk(KERN_INFO DRIVER_NAME ": Resuming.\n"); - - ricoh_mmc_disable(fw_dev); - - return 0; -} - -static struct pci_driver ricoh_mmc_driver = { - .name = DRIVER_NAME, - .id_table = pci_ids, - .probe = ricoh_mmc_probe, - .remove = __devexit_p(ricoh_mmc_remove), - .suspend_late = ricoh_mmc_suspend_late, - .resume_early = ricoh_mmc_resume_early, -}; - -/*****************************************************************************\ - * * - * Driver init/exit * - * * -\*****************************************************************************/ - -static int __init ricoh_mmc_drv_init(void) -{ - printk(KERN_INFO DRIVER_NAME - ": Ricoh MMC Controller disabling driver\n"); - printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n"); - - return pci_register_driver(&ricoh_mmc_driver); -} - -static void __exit ricoh_mmc_drv_exit(void) -{ - pci_unregister_driver(&ricoh_mmc_driver); -} - -module_init(ricoh_mmc_drv_init); -module_exit(ricoh_mmc_drv_exit); - -MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>"); -MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index d96e1ab..2fdf768 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1179,7 +1179,7 @@ static int s3cmci_card_present(struct mmc_host *mmc) struct s3c24xx_mci_pdata *pdata = host->pdata; int ret; - if (pdata->gpio_detect == 0) + if (pdata->no_detect) return -ENOSYS; ret = gpio_get_value(pdata->gpio_detect) ? 0 : 1; @@ -1360,6 +1360,8 @@ static struct mmc_host_ops s3cmci_ops = { static struct s3c24xx_mci_pdata s3cmci_def_pdata = { /* This is currently here to avoid a number of if (host->pdata) * checks. Any zero fields to ensure reasonable defaults are picked. */ + .no_wprotect = 1, + .no_detect = 1, }; #ifdef CONFIG_CPU_FREQ diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 5c3a176..8e1020c 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -80,9 +80,6 @@ struct sdhci_pci_chip { static int ricoh_probe(struct sdhci_pci_chip *chip) { - if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) - chip->quirks |= SDHCI_QUIRK_CLOCK_BEFORE_RESET; - if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG || chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; @@ -92,7 +89,9 @@ static int ricoh_probe(struct sdhci_pci_chip *chip) static const struct sdhci_pci_fixes sdhci_ricoh = { .probe = ricoh_probe, - .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR, + .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_FORCE_DMA | + SDHCI_QUIRK_CLOCK_BEFORE_RESET, }; static const struct sdhci_pci_fixes sdhci_ene_712 = { @@ -501,6 +500,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) { struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; + mmc_pm_flag_t pm_flags = 0; int i, ret; chip = pci_get_drvdata(pdev); @@ -519,6 +519,8 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) sdhci_resume_host(chip->slots[i]->host); return ret; } + + pm_flags |= slot->host->mmc->pm_flags; } if (chip->fixes && chip->fixes->suspend) { @@ -531,9 +533,15 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) } pci_save_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + if (pm_flags & MMC_PM_KEEP_POWER) { + if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_set_power_state(pdev, PCI_D3hot); + } else { + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + } return 0; } @@ -653,6 +661,8 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( goto unmap; } + host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; + ret = sdhci_add_host(host); if (ret) goto remove; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c279fbc..d6ab62d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -174,20 +174,31 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); } -static void sdhci_init(struct sdhci_host *host) +static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + +static void sdhci_init(struct sdhci_host *host, int soft) { - sdhci_reset(host, SDHCI_RESET_ALL); + if (soft) + sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + else + sdhci_reset(host, SDHCI_RESET_ALL); sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); + + if (soft) { + /* force clock reconfiguration */ + host->clock = 0; + sdhci_set_ios(host->mmc, &host->mmc->ios); + } } static void sdhci_reinit(struct sdhci_host *host) { - sdhci_init(host); + sdhci_init(host, 0); sdhci_enable_card_detection(host); } @@ -376,6 +387,20 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) local_irq_restore(*flags); } +static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd) +{ + __le32 *dataddr = (__le32 __force *)(desc + 4); + __le16 *cmdlen = (__le16 __force *)desc; + + /* SDHCI specification says ADMA descriptors should be 4 byte + * aligned, so using 16 or 32bit operations should be safe. */ + + cmdlen[0] = cpu_to_le16(cmd); + cmdlen[1] = cpu_to_le16(len); + + dataddr[0] = cpu_to_le32(addr); +} + static int sdhci_adma_table_pre(struct sdhci_host *host, struct mmc_data *data) { @@ -443,19 +468,11 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, sdhci_kunmap_atomic(buffer, &flags); } - desc[7] = (align_addr >> 24) & 0xff; - desc[6] = (align_addr >> 16) & 0xff; - desc[5] = (align_addr >> 8) & 0xff; - desc[4] = (align_addr >> 0) & 0xff; + /* tran, valid */ + sdhci_set_adma_desc(desc, align_addr, offset, 0x21); BUG_ON(offset > 65536); - desc[3] = (offset >> 8) & 0xff; - desc[2] = (offset >> 0) & 0xff; - - desc[1] = 0x00; - desc[0] = 0x21; /* tran, valid */ - align += 4; align_addr += 4; @@ -465,19 +482,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, len -= offset; } - desc[7] = (addr >> 24) & 0xff; - desc[6] = (addr >> 16) & 0xff; - desc[5] = (addr >> 8) & 0xff; - desc[4] = (addr >> 0) & 0xff; - BUG_ON(len > 65536); - desc[3] = (len >> 8) & 0xff; - desc[2] = (len >> 0) & 0xff; - - desc[1] = 0x00; - desc[0] = 0x21; /* tran, valid */ - + /* tran, valid */ + sdhci_set_adma_desc(desc, addr, len, 0x21); desc += 8; /* @@ -490,16 +498,9 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, /* * Add a terminating entry. */ - desc[7] = 0; - desc[6] = 0; - desc[5] = 0; - desc[4] = 0; - desc[3] = 0; - desc[2] = 0; - - desc[1] = 0x00; - desc[0] = 0x03; /* nop, end, valid */ + /* nop, end, valid */ + sdhci_set_adma_desc(desc, 0, 0, 0x3); /* * Resync align buffer as we might have changed it. @@ -1610,16 +1611,13 @@ int sdhci_resume_host(struct sdhci_host *host) if (ret) return ret; - sdhci_init(host); + sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); mmiowb(); ret = mmc_resume_host(host->mmc); - if (ret) - return ret; - sdhci_enable_card_detection(host); - return 0; + return ret; } EXPORT_SYMBOL_GPL(sdhci_resume_host); @@ -1874,7 +1872,7 @@ int sdhci_add_host(struct sdhci_host *host) if (ret) goto untasklet; - sdhci_init(host); + sdhci_init(host, 0); #ifdef CONFIG_MMC_DEBUG sdhci_dumpregs(host); diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e22c3fa..b2b577f 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -323,7 +323,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid) if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE); - mmc_detect_change(host->mmc, 0); + mmc_detect_change(host->mmc, msecs_to_jiffies(100)); } /* CRC and other errors */ @@ -550,6 +550,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) mmc->ops = &tmio_mmc_ops; mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps |= pdata->capabilities; mmc->f_max = pdata->hclk; mmc->f_min = mmc->f_max / 512; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; @@ -568,14 +569,14 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) if (ret >= 0) host->irq = ret; else - goto unmap_ctl; + goto cell_disable; disable_mmc_irqs(host, TMIO_MASK_ALL); ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host); if (ret) - goto unmap_ctl; + goto cell_disable; mmc_add_host(mmc); @@ -587,6 +588,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) return 0; +cell_disable: + if (cell->disable) + cell->disable(dev); unmap_ctl: iounmap(host->ctl); host_free: @@ -597,6 +601,7 @@ out: static int __devexit tmio_mmc_remove(struct platform_device *dev) { + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; struct mmc_host *mmc = platform_get_drvdata(dev); platform_set_drvdata(dev, NULL); @@ -605,6 +610,8 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev) struct tmio_mmc_host *host = mmc_priv(mmc); mmc_remove_host(mmc); free_irq(host->irq, host); + if (cell->disable) + cell->disable(dev); iounmap(host->ctl); mmc_free_host(mmc); } diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 692dc23..dafecfb 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -55,10 +55,8 @@ /* Define some IRQ masks */ /* This is the mask used at reset by the chip */ #define TMIO_MASK_ALL 0x837f031d -#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND | \ - TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) -#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND | \ - TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) +#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) +#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) #define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) |