The patch titled From: Lars-Peter Clausen <lars@xxxxxxxxxx> has been added to the -mm tree. Its filename is mmc-add-jz4740-mmc-driver-v6.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/SubmitChecklist when testing your code *** See http://userweb.kernel.org/~akpm/stuff/added-to-mm.txt to find out what to do about this The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/ ------------------------------------------------------ Subject: From: Lars-Peter Clausen <lars@xxxxxxxxxx> - Rework Kconfig entry - Avoid reloading the fifo address before each read/write Signed-off-by: Lars-Peter Clausen <lars@xxxxxxxxxx> Cc: Matt Fleming <matt@xxxxxxxxxxxxxxxxx> Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx> Cc: <linux-mmc@xxxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- arch/mips/include/asm/mach-jz4740/jz4740_mmc.h | 15 drivers/mmc/host/Kconfig | 17 drivers/mmc/host/jz4740_mmc.c | 490 ++++++++------- include/linux/mmc/jz4740_mmc.h | 15 4 files changed, 301 insertions(+), 236 deletions(-) diff -puN /dev/null arch/mips/include/asm/mach-jz4740/jz4740_mmc.h --- /dev/null +++ a/arch/mips/include/asm/mach-jz4740/jz4740_mmc.h @@ -0,0 +1,15 @@ +#ifndef __LINUX_MMC_JZ4740_MMC +#define __LINUX_MMC_JZ4740_MMC + +struct jz4740_mmc_platform_data { + int gpio_power; + int gpio_card_detect; + int gpio_read_only; + unsigned card_detect_active_low:1; + unsigned read_only_active_low:1; + unsigned power_active_low:1; + + unsigned data_1bit:1; +}; + +#endif diff -puN drivers/mmc/host/Kconfig~mmc-add-jz4740-mmc-driver-v6 drivers/mmc/host/Kconfig --- a/drivers/mmc/host/Kconfig~mmc-add-jz4740-mmc-driver-v6 +++ a/drivers/mmc/host/Kconfig @@ -81,14 +81,6 @@ config MMC_RICOH_MMC If unsure, say Y. -config MMC_JZ4740 - tristate "JZ4740 SD/Multimedia Card Interface support" - depends on MACH_JZ4740 - help - This selects the Ingenic Z4740 SD/Multimedia card Interface. - If you have an ngenic platform with a Multimedia Card slot, - say Y or M here. - config MMC_SDHCI_OF tristate "SDHCI support on OpenFirmware platforms" depends on MMC_SDHCI && PPC_OF @@ -440,3 +432,12 @@ config MMC_SH_MMCIF This selects the MMC Host Interface controler (MMCIF). This driver supports MMCIF in sh7724/sh7757/sh7372. + +config MMC_JZ4740 + tristate "JZ4740 SD/Multimedia Card Interface support" + depends on MACH_JZ4740 + help + This selects support for the SD/MMC controller on Ingenic JZ4740 + SoCs. + If you have a board based on such a SoC and with a SD/MMC slot, + say Y or M here. diff -puN drivers/mmc/host/jz4740_mmc.c~mmc-add-jz4740-mmc-driver-v6 drivers/mmc/host/jz4740_mmc.c --- a/drivers/mmc/host/jz4740_mmc.c~mmc-add-jz4740-mmc-driver-v6 +++ a/drivers/mmc/host/jz4740_mmc.c @@ -22,7 +22,6 @@ #include <linux/delay.h> #include <linux/scatterlist.h> #include <linux/clk.h> -#include <linux/mmc/jz4740_mmc.h> #include <linux/bitops.h> #include <linux/gpio.h> @@ -30,6 +29,7 @@ #include <asm/cacheflush.h> #include <linux/dma-mapping.h> +#include <asm/mach-jz4740/jz4740_mmc.h> #define JZ_REG_MMC_STRPCL 0x00 #define JZ_REG_MMC_STATUS 0x04 @@ -103,7 +103,12 @@ #define JZ_MMC_CLK_RATE 24000000 -#define JZ4740_MMC_MAX_TIMEOUT 10000000 +enum jz4740_mmc_state { + JZ4740_MMC_STATE_READ_RESPONSE, + JZ4740_MMC_STATE_TRANSFER_DATA, + JZ4740_MMC_STATE_SEND_STOP, + JZ4740_MMC_STATE_DONE, +}; struct jz4740_mmc_host { struct mmc_host *mmc; @@ -121,7 +126,6 @@ struct jz4740_mmc_host { unsigned long waiting; - int max_clock; uint32_t cmdat; uint16_t irq_mask; @@ -129,6 +133,8 @@ struct jz4740_mmc_host { spinlock_t lock; struct timer_list timeout_timer; + struct sg_mapping_iter miter; + enum jz4740_mmc_state state; }; static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, @@ -160,22 +166,24 @@ static void jz4740_mmc_clock_enable(stru static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host) { uint32_t status; + unsigned int timeout = 1000; writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL); do { status = readl(host->base + JZ_REG_MMC_STATUS); - } while (status & JZ_MMC_STATUS_CLK_EN); + } while (status & JZ_MMC_STATUS_CLK_EN && --timeout); } static void jz4740_mmc_reset(struct jz4740_mmc_host *host) { uint32_t status; + unsigned int timeout = 1000; writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL); udelay(10); do { status = readl(host->base + JZ_REG_MMC_STATUS); - } while (status & JZ_MMC_STATUS_IS_RESETTING); + } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout); } static void jz4740_mmc_request_done(struct jz4740_mmc_host *host) @@ -188,177 +196,171 @@ static void jz4740_mmc_request_done(stru mmc_request_done(host->mmc, req); } -static unsigned int jz4740_mmc_wait_irq(struct jz4740_mmc_host *host, +static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host, unsigned int irq) { - unsigned int timeout = JZ4740_MMC_MAX_TIMEOUT; + unsigned int timeout = 0x800; uint16_t status; do { status = readw(host->base + JZ_REG_MMC_IREG); } while (!(status & irq) && --timeout); - return timeout; + if (timeout == 0) { + set_bit(0, &host->waiting); + mod_timer(&host->timeout_timer, jiffies + 5*HZ); + jz4740_mmc_set_irq_enabled(host, irq, true); + return true; + } + + return false; } -static void jz4740_mmc_write_data(struct jz4740_mmc_host *host, +static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host, struct mmc_data *data) { - struct sg_mapping_iter miter; - uint32_t *buf; int status; - unsigned int timeout; + + status = readl(host->base + JZ_REG_MMC_STATUS); + if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) { + if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) { + host->req->cmd->error = -ETIMEDOUT; + data->error = -ETIMEDOUT; + } else { + host->req->cmd->error = -EIO; + data->error = -EIO; + } + } +} + +static bool jz4740_mmc_write_data(struct jz4740_mmc_host *host, + struct mmc_data *data) +{ + struct sg_mapping_iter *miter = &host->miter; + void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO; + uint32_t *buf; + bool timeout; size_t i, j; - sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG); - while (sg_miter_next(&miter)) { - buf = miter.addr; - i = miter.length / 4; - j = i >> 3; + while (sg_miter_next(miter)) { + buf = miter->addr; + i = miter->length / 4; + j = i / 8; i = i & 0x7; while (j) { - timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); - if (unlikely(timeout == 0)) { - sg_miter_stop(&miter); - goto err_timeout; - } - - writel(buf[0], host->base + JZ_REG_MMC_TXFIFO); - writel(buf[1], host->base + JZ_REG_MMC_TXFIFO); - writel(buf[2], host->base + JZ_REG_MMC_TXFIFO); - writel(buf[3], host->base + JZ_REG_MMC_TXFIFO); - writel(buf[4], host->base + JZ_REG_MMC_TXFIFO); - writel(buf[5], host->base + JZ_REG_MMC_TXFIFO); - writel(buf[6], host->base + JZ_REG_MMC_TXFIFO); - writel(buf[7], host->base + JZ_REG_MMC_TXFIFO); + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); + if (unlikely(timeout)) + goto poll_timeout; + + writel(buf[0], fifo_addr); + writel(buf[1], fifo_addr); + writel(buf[2], fifo_addr); + writel(buf[3], fifo_addr); + writel(buf[4], fifo_addr); + writel(buf[5], fifo_addr); + writel(buf[6], fifo_addr); + writel(buf[7], fifo_addr); buf += 8; --j; } if (unlikely(i)) { - timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); - if (unlikely(timeout == 0)) { - sg_miter_stop(&miter); - goto err_timeout; - } + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); + if (unlikely(timeout)) + goto poll_timeout; while (i) { - writel(*buf, host->base + JZ_REG_MMC_TXFIFO); + writel(*buf, fifo_addr); ++buf; --i; } } - data->bytes_xfered += miter.length; - } - sg_miter_stop(&miter); - - status = readl(host->base + JZ_REG_MMC_STATUS); - if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) { - if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) { - host->req->cmd->error = -ETIMEDOUT; - data->error = -ETIMEDOUT; - } else { - host->req->cmd->error = -EIO; - data->error = -EIO; - } - return; + data->bytes_xfered += miter->length; } + sg_miter_stop(miter); - timeout = JZ4740_MMC_MAX_TIMEOUT; - do { - status = readl(host->base + JZ_REG_MMC_STATUS); - } while ((status & JZ_MMC_STATUS_DATA_TRAN_DONE) == 0 && --timeout); + return false; - if (unlikely(timeout == 0)) - goto err_timeout; - writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG); +poll_timeout: + miter->consumed = (void *)buf - miter->addr; + data->bytes_xfered += miter->consumed; + sg_miter_stop(miter); - return; - -err_timeout: - host->req->cmd->error = -ETIMEDOUT; - data->error = -ETIMEDOUT; + return true; } -static void jz4740_mmc_read_data(struct jz4740_mmc_host *host, +static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host, struct mmc_data *data) { - struct sg_mapping_iter miter; + struct sg_mapping_iter *miter = &host->miter; + void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO; uint32_t *buf; uint32_t d; - uint16_t status = 0; + uint16_t status; size_t i, j; unsigned int timeout; - sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG); - while (sg_miter_next(&miter)) { - buf = miter.addr; - i = miter.length; - j = i >> 5; + while (sg_miter_next(miter)) { + buf = miter->addr; + i = miter->length; + j = i / 32; i = i & 0x1f; while (j) { - timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); - if (unlikely(timeout == 0)) { - sg_miter_stop(&miter); - goto err_timeout; - } - - buf[0] = readl(host->base + JZ_REG_MMC_RXFIFO); - buf[1] = readl(host->base + JZ_REG_MMC_RXFIFO); - buf[2] = readl(host->base + JZ_REG_MMC_RXFIFO); - buf[3] = readl(host->base + JZ_REG_MMC_RXFIFO); - buf[4] = readl(host->base + JZ_REG_MMC_RXFIFO); - buf[5] = readl(host->base + JZ_REG_MMC_RXFIFO); - buf[6] = readl(host->base + JZ_REG_MMC_RXFIFO); - buf[7] = readl(host->base + JZ_REG_MMC_RXFIFO); + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); + if (unlikely(timeout)) + goto poll_timeout; + + buf[0] = readl(fifo_addr); + buf[1] = readl(fifo_addr); + buf[2] = readl(fifo_addr); + buf[3] = readl(fifo_addr); + buf[4] = readl(fifo_addr); + buf[5] = readl(fifo_addr); + buf[6] = readl(fifo_addr); + buf[7] = readl(fifo_addr); buf += 8; --j; } - while (i >= 4) { - timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); - if (unlikely(timeout == 0)) { - sg_miter_stop(&miter); - goto err_timeout; + if (unlikely(i)) { + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); + if (unlikely(timeout)) + goto poll_timeout; + + while (i >= 4) { + *buf++ = readl(fifo_addr); + i -= 4; + } + if (unlikely(i > 0)) { + d = readl(fifo_addr); + memcpy(buf, &d, i); } - - *buf++ = readl(host->base + JZ_REG_MMC_RXFIFO); - i -= 4; - } - if (unlikely(i > 0)) { - d = readl(host->base + JZ_REG_MMC_RXFIFO); - memcpy(buf, &d, i); } - data->bytes_xfered += miter.length; + data->bytes_xfered += miter->length; - /* This can go away once MIPS implements flush_kernel_dcache_page */ - flush_dcache_page(miter.page); - } - sg_miter_stop(&miter); - - status = readl(host->base + JZ_REG_MMC_STATUS); - if (status & JZ_MMC_STATUS_READ_ERROR_MASK) { - if (status & JZ_MMC_STATUS_TIMEOUT_READ) { - host->req->cmd->error = -ETIMEDOUT; - data->error = -ETIMEDOUT; - } else { - host->req->cmd->error = -EIO; - data->error = -EIO; - } - return; + /* This can go away once MIPS implements + * flush_kernel_dcache_page */ + flush_dcache_page(miter->page); } + sg_miter_stop(miter); /* For whatever reason there is sometime one word more in the fifo then * requested */ - while ((status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) == 0 && --timeout) { - d = readl(host->base + JZ_REG_MMC_RXFIFO); + timeout = 1000; + status = readl(host->base + JZ_REG_MMC_STATUS); + while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) { + d = readl(fifo_addr); status = readl(host->base + JZ_REG_MMC_STATUS); } - return; -err_timeout: - host->req->cmd->error = -ETIMEDOUT; - data->error = -ETIMEDOUT; + return false; + +poll_timeout: + miter->consumed = (void *)buf - miter->addr; + data->bytes_xfered += miter->consumed; + sg_miter_stop(miter); + + return true; } static void jz4740_mmc_timeout(unsigned long data) @@ -379,19 +381,21 @@ static void jz4740_mmc_read_response(str { int i; uint16_t tmp; + void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO; if (cmd->flags & MMC_RSP_136) { - tmp = readw(host->base + JZ_REG_MMC_RESP_FIFO); + tmp = readw(fifo_addr); for (i = 0; i < 4; ++i) { cmd->resp[i] = tmp << 24; - cmd->resp[i] |= readw(host->base + JZ_REG_MMC_RESP_FIFO) << 8; - tmp = readw(host->base + JZ_REG_MMC_RESP_FIFO); + tmp = readw(fifo_addr); + cmd->resp[i] |= tmp << 8; + tmp = readw(fifo_addr); cmd->resp[i] |= tmp >> 8; } } else { - cmd->resp[0] = readw(host->base + JZ_REG_MMC_RESP_FIFO) << 24; - cmd->resp[0] |= readw(host->base + JZ_REG_MMC_RESP_FIFO) << 8; - cmd->resp[0] |= readw(host->base + JZ_REG_MMC_RESP_FIFO) & 0xff; + cmd->resp[0] = readw(fifo_addr) << 24; + cmd->resp[0] |= readw(fifo_addr) << 8; + cmd->resp[0] |= readw(fifo_addr) & 0xff; } } @@ -441,41 +445,78 @@ static void jz4740_mmc_send_command(stru jz4740_mmc_clock_enable(host, 1); } +static void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host) +{ + struct mmc_command *cmd = host->req->cmd; + struct mmc_data *data = cmd->data; + int direction; + + if (data->flags & MMC_DATA_READ) + direction = SG_MITER_TO_SG; + else + direction = SG_MITER_FROM_SG; + + sg_miter_start(&host->miter, data->sg, data->sg_len, direction); +} + static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) { struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid; struct mmc_command *cmd = host->req->cmd; struct mmc_request *req = host->req; - unsigned int timeout = JZ4740_MMC_MAX_TIMEOUT; - uint32_t status; + bool timeout = false; if (cmd->error) - goto done; + host->state = JZ4740_MMC_STATE_DONE; - if (cmd->flags & MMC_RSP_PRESENT) - jz4740_mmc_read_response(host, cmd); + switch (host->state) { + case JZ4740_MMC_STATE_READ_RESPONSE: + if (cmd->flags & MMC_RSP_PRESENT) + jz4740_mmc_read_response(host, cmd); - if (cmd->data) { + if (!cmd->data) + break; + + jz_mmc_prepare_data_transfer(host); + + case JZ4740_MMC_STATE_TRANSFER_DATA: if (cmd->data->flags & MMC_DATA_READ) - jz4740_mmc_read_data(host, cmd->data); + timeout = jz4740_mmc_read_data(host, cmd->data); else - jz4740_mmc_write_data(host, cmd->data); - } + timeout = jz4740_mmc_write_data(host, cmd->data); + + if (unlikely(timeout)) { + host->state = JZ4740_MMC_STATE_TRANSFER_DATA; + break; + } + + jz4740_mmc_transfer_check_state(host, cmd->data); + + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE); + if (unlikely(timeout)) { + host->state = JZ4740_MMC_STATE_SEND_STOP; + break; + } + writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG); + + case JZ4740_MMC_STATE_SEND_STOP: + if (!req->stop) + break; - if (req->stop) { jz4740_mmc_send_command(host, req->stop); - do { - status = readw(host->base + JZ_REG_MMC_IREG); - } while ((status & JZ_MMC_IRQ_PRG_DONE) == 0 && --timeout); - writew(JZ_MMC_IRQ_PRG_DONE, host->base + JZ_REG_MMC_IREG); - } - if (unlikely(timeout == 0)) - req->stop->error = -ETIMEDOUT; + timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_PRG_DONE); + if (timeout) { + host->state = JZ4740_MMC_STATE_DONE; + break; + } + case JZ4740_MMC_STATE_DONE: + break; + } -done: - jz4740_mmc_request_done(host); + if (!timeout) + jz4740_mmc_request_done(host); return IRQ_HANDLED; } @@ -483,8 +524,8 @@ done: static irqreturn_t jz_mmc_irq(int irq, void *devid) { struct jz4740_mmc_host *host = devid; + struct mmc_command *cmd = host->cmd; uint16_t irq_reg, status, tmp; - irqreturn_t ret = IRQ_HANDLED; irq_reg = readw(host->base + JZ_REG_MMC_IREG); @@ -492,7 +533,7 @@ static irqreturn_t jz_mmc_irq(int irq, v irq_reg &= ~host->irq_mask; tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ | - JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); + JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); if (tmp != irq_reg) writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG); @@ -500,39 +541,39 @@ static irqreturn_t jz_mmc_irq(int irq, v if (irq_reg & JZ_MMC_IRQ_SDIO) { writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG); mmc_signal_sdio_irq(host->mmc); + irq_reg &= ~JZ_MMC_IRQ_SDIO; } - if (!host->req || !host->cmd) - goto handled; - - if (!(irq_reg & JZ_MMC_IRQ_END_CMD_RES)) - goto handled; - - if (test_and_clear_bit(0, &host->waiting)) { - del_timer(&host->timeout_timer); + if (host->req && cmd && irq_reg) { + if (test_and_clear_bit(0, &host->waiting)) { + del_timer(&host->timeout_timer); + + status = readl(host->base + JZ_REG_MMC_STATUS); + + if (status & JZ_MMC_STATUS_TIMEOUT_RES) { + cmd->error = -ETIMEDOUT; + } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { + cmd->error = -EIO; + } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | + JZ_MMC_STATUS_CRC_WRITE_ERROR)) { + if (cmd->data) + cmd->data->error = -EIO; + cmd->error = -EIO; + } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | + JZ_MMC_STATUS_CRC_WRITE_ERROR)) { + if (cmd->data) + cmd->data->error = -EIO; + cmd->error = -EIO; + } - status = readl(host->base + JZ_REG_MMC_STATUS); + jz4740_mmc_set_irq_enabled(host, irq_reg, false); + writew(irq_reg, host->base + JZ_REG_MMC_IREG); - if (status & JZ_MMC_STATUS_TIMEOUT_RES) { - host->cmd->error = -ETIMEDOUT; - } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { - host->cmd->error = -EIO; - } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | - JZ_MMC_STATUS_CRC_WRITE_ERROR)) { - host->cmd->data->error = -EIO; - } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | - JZ_MMC_STATUS_CRC_WRITE_ERROR)) { - host->cmd->data->error = -EIO; + return IRQ_WAKE_THREAD; } - - ret = IRQ_WAKE_THREAD; } - jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false); - writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG); - -handled: - return ret; + return IRQ_HANDLED; } static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate) @@ -565,6 +606,7 @@ static void jz4740_mmc_request(struct mm writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG); jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true); + host->state = JZ4740_MMC_STATE_READ_RESPONSE; set_bit(0, &host->waiting); mod_timer(&host->timeout_timer, jiffies + 5*HZ); jz4740_mmc_send_command(host, req->cmd); @@ -631,7 +673,7 @@ static irqreturn_t jz4740_mmc_card_detec { struct jz4740_mmc_host *host = devid; - mmc_detect_change(host->mmc, HZ / 3); + mmc_detect_change(host->mmc, HZ / 2); return IRQ_HANDLED; } @@ -659,6 +701,28 @@ static const struct jz_gpio_bulk_request JZ_GPIO_BULK_PIN(MSC_DATA3), }; +static int __devinit jz4740_mmc_request_gpio(struct device *dev, int gpio, + const char *name, bool output, int value) +{ + int ret; + + if (!gpio_is_valid(gpio)) + return 0; + + ret = gpio_request(gpio, name); + if (ret) { + dev_err(dev, "Failed to request %s gpio: %d\n", name, ret); + return ret; + } + + if (output) + gpio_direction_output(gpio, value); + else + gpio_direction_input(gpio); + + return 0; +} + static int __devinit jz4740_mmc_request_gpios(struct platform_device *pdev) { int ret; @@ -667,32 +731,20 @@ static int __devinit jz4740_mmc_request_ if (!pdata) return 0; - if (gpio_is_valid(pdata->gpio_card_detect)) { - ret = gpio_request(pdata->gpio_card_detect, "MMC detect change"); - if (ret) { - dev_err(&pdev->dev, "Failed to request detect change gpio\n"); - goto err; - } - gpio_direction_input(pdata->gpio_card_detect); - } + ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_card_detect, + "MMC detect change", false, 0); + if (ret) + goto err; - if (gpio_is_valid(pdata->gpio_read_only)) { - ret = gpio_request(pdata->gpio_read_only, "MMC read only"); - if (ret) { - dev_err(&pdev->dev, "Failed to request read only gpio: %d\n", ret); - goto err_free_gpio_card_detect; - } - gpio_direction_input(pdata->gpio_read_only); - } + ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_read_only, + "MMC read only", false, 0); + if (ret) + goto err_free_gpio_card_detect; - if (gpio_is_valid(pdata->gpio_power)) { - ret = gpio_request(pdata->gpio_power, "MMC power"); - if (ret) { - dev_err(&pdev->dev, "Failed to request power gpio: %d\n", ret); - goto err_free_gpio_read_only; - } - gpio_direction_output(pdata->gpio_power, pdata->power_active_low); - } + ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power, + "MMC read only", true, pdata->power_active_low); + if (ret) + goto err_free_gpio_read_only; return 0; @@ -706,6 +758,29 @@ err: return ret; } +static int __devinit jz4740_mmc_request_cd_irq(struct platform_device *pdev, + struct jz4740_mmc_host *host) +{ + int ret; + struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; + + if (gpio_is_valid(pdata->gpio_card_detect)) + return 0; + + host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect); + + if (host->card_detect_irq < 0) { + dev_warn(&pdev->dev, "Failed to get card detect irq\n"); + return 0; + } + return request_irq(host->card_detect_irq, jz4740_mmc_card_detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "MMC card detect", host); + + + return ret; +} + static void jz4740_mmc_free_gpios(struct platform_device *pdev) { struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; @@ -811,24 +886,13 @@ static int __devinit jz4740_mmc_probe(st host->mmc = mmc; host->pdev = pdev; - host->max_clock = JZ_MMC_CLK_RATE; spin_lock_init(&host->lock); host->irq_mask = 0xffff; - host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect); - - if (host->card_detect_irq < 0) { - dev_warn(&pdev->dev, "Failed to get irq for card detect gpio\n"); - } else { - ret = request_irq(host->card_detect_irq, - jz4740_mmc_card_detect_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "MMC card detect", host); - - if (ret) { - dev_err(&pdev->dev, "Failed to request card detect irq"); - goto err_free_gpios; - } + ret = jz4740_mmc_request_cd_irq(pdev, host); + if (ret) { + dev_err(&pdev->dev, "Failed to request card detect irq\n"); + goto err_free_gpios; } ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0, @@ -842,7 +906,7 @@ static int __devinit jz4740_mmc_probe(st jz4740_mmc_clock_disable(host); setup_timer(&host->timeout_timer, jz4740_mmc_timeout, (unsigned long)host); - /* It is not that important when it times out, it just needs to timeout. */ + /* It is not important when it times out, it just needs to timeout. */ set_timer_slack(&host->timeout_timer, HZ); platform_set_drvdata(pdev, host); diff -puN include/linux/mmc/jz4740_mmc.h~mmc-add-jz4740-mmc-driver-v6 /dev/null --- a/include/linux/mmc/jz4740_mmc.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __LINUX_MMC_JZ4740_MMC -#define __LINUX_MMC_JZ4740_MMC - -struct jz4740_mmc_platform_data { - int gpio_power; - int gpio_card_detect; - int gpio_read_only; - unsigned card_detect_active_low:1; - unsigned read_only_active_low:1; - unsigned power_active_low:1; - - unsigned data_1bit:1; -}; - -#endif _ Patches currently in -mm which might be from lars@xxxxxxxxxx are linux-next.patch mmc-add-jz4740-mmc-driver.patch mmc-add-jz4740-mmc-driver-v6.patch -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html