diff options
Diffstat (limited to 'drivers/mmc/at91_mci.c')
-rw-r--r-- | drivers/mmc/at91_mci.c | 352 |
1 files changed, 188 insertions, 164 deletions
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 494b23fb0a0..08a33c33f6e 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -1,5 +1,5 @@ /* - * linux/drivers/mmc/at91_mci.c - ATMEL AT91RM9200 MCI Driver + * linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver * * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved * @@ -11,7 +11,7 @@ */ /* - This is the AT91RM9200 MCI driver that has been tested with both MMC cards + This is the AT91 MCI driver that has been tested with both MMC cards and SD-cards. Boards that support write protect are now supported. The CCAT91SBC001 board does not support SD cards. @@ -38,8 +38,8 @@ controller to manage the transfers. A read is done from the controller directly to the scatterlist passed in from the request. - Due to a bug in the controller, when a read is completed, all the words are byte - swapped in the scatterlist buffers. + Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte + swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug. The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY @@ -72,42 +72,27 @@ #include <asm/irq.h> #include <asm/mach/mmc.h> #include <asm/arch/board.h> +#include <asm/arch/cpu.h> #include <asm/arch/gpio.h> -#include <asm/arch/at91rm9200_mci.h> -#include <asm/arch/at91rm9200_pdc.h> +#include <asm/arch/at91_mci.h> +#include <asm/arch/at91_pdc.h> #define DRIVER_NAME "at91_mci" #undef SUPPORT_4WIRE -static struct clk *mci_clk; +#define FL_SENT_COMMAND (1 << 0) +#define FL_SENT_STOP (1 << 1) -#define FL_SENT_COMMAND (1 << 0) -#define FL_SENT_STOP (1 << 1) +#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \ + | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \ + | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE) +#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg)) +#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg)) /* - * Read from a MCI register. - */ -static inline unsigned long at91_mci_read(unsigned int reg) -{ - void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI; - - return __raw_readl(mci_base + reg); -} - -/* - * Write to a MCI register. - */ -static inline void at91_mci_write(unsigned int reg, unsigned long value) -{ - void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI; - - __raw_writel(value, mci_base + reg); -} - -/* * Low level type for this driver */ struct at91mci_host @@ -116,9 +101,14 @@ struct at91mci_host struct mmc_command *cmd; struct mmc_request *request; + void __iomem *baseaddr; + int irq; + struct at91_mmc_data *board; int present; + struct clk *mci_clk; + /* * Flag indicating when the command has been sent. This is used to * work out whether or not to send the stop @@ -158,7 +148,6 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data for (i = 0; i < len; i++) { struct scatterlist *sg; int amount; - int index; unsigned int *sgbuffer; sg = &data->sg[i]; @@ -166,10 +155,15 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; amount = min(size, sg->length); size -= amount; - amount /= 4; - for (index = 0; index < amount; index++) - *dmabuf++ = swab32(sgbuffer[index]); + if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */ + int index; + + for (index = 0; index < (amount / 4); index++) + *dmabuf++ = swab32(sgbuffer[index]); + } + else + memcpy(dmabuf, sgbuffer, amount); kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); @@ -217,13 +211,13 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) /* Check to see if this needs filling */ if (i == 0) { - if (at91_mci_read(AT91_PDC_RCR) != 0) { + if (at91_mci_read(host, AT91_PDC_RCR) != 0) { pr_debug("Transfer active in current\n"); continue; } } else { - if (at91_mci_read(AT91_PDC_RNCR) != 0) { + if (at91_mci_read(host, AT91_PDC_RNCR) != 0) { pr_debug("Transfer active in next\n"); continue; } @@ -240,12 +234,12 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length); if (i == 0) { - at91_mci_write(AT91_PDC_RPR, sg->dma_address); - at91_mci_write(AT91_PDC_RCR, sg->length / 4); + at91_mci_write(host, AT91_PDC_RPR, sg->dma_address); + at91_mci_write(host, AT91_PDC_RCR, sg->length / 4); } else { - at91_mci_write(AT91_PDC_RNPR, sg->dma_address); - at91_mci_write(AT91_PDC_RNCR, sg->length / 4); + at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address); + at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4); } } @@ -276,8 +270,6 @@ static void at91mci_post_dma_read(struct at91mci_host *host) while (host->in_use_index < host->transfer_index) { unsigned int *buffer; - int index; - int len; struct scatterlist *sg; @@ -295,11 +287,13 @@ static void at91mci_post_dma_read(struct at91mci_host *host) data->bytes_xfered += sg->length; - len = sg->length / 4; + if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */ + int index; - for (index = 0; index < len; index++) { - buffer[index] = swab32(buffer[index]); + for (index = 0; index < (sg->length / 4); index++) + buffer[index] = swab32(buffer[index]); } + kunmap_atomic(buffer, KM_BIO_SRC_IRQ); flush_dcache_page(sg->page); } @@ -308,8 +302,8 @@ static void at91mci_post_dma_read(struct at91mci_host *host) if (host->transfer_index < data->sg_len) at91mci_pre_dma_read(host); else { - at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF); - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); } pr_debug("post dma read done\n"); @@ -326,11 +320,11 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) pr_debug("Handling the transmit\n"); /* Disable the transfer */ - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); /* Now wait for cmd ready */ - at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE); - at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY); + at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); cmd = host->cmd; if (!cmd) return; @@ -344,21 +338,23 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) /* * Enable the controller */ -static void at91_mci_enable(void) +static void at91_mci_enable(struct at91mci_host *host) { - at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN); - at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF); - at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); - at91_mci_write(AT91_MCI_MR, 0x834A); - at91_mci_write(AT91_MCI_SDCR, 0x0); + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); + at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); + at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); + at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a); + + /* use Slot A or B (only one at same time) */ + at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b); } /* * Disable the controller */ -static void at91_mci_disable(void) +static void at91_mci_disable(struct at91mci_host *host) { - at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); } /* @@ -378,13 +374,13 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ /* Not sure if this is needed */ #if 0 - if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { + if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { pr_debug("Clearing timeout\n"); - at91_mci_write(AT91_MCI_ARGR, 0); - at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD); - while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) { + at91_mci_write(host, AT91_MCI_ARGR, 0); + at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD); + while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) { /* spin */ - pr_debug("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR)); + pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); } } #endif @@ -431,32 +427,32 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ /* * Set the arguments and send the command */ - pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n", - cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR)); + pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n", + cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR)); if (!data) { - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); - at91_mci_write(AT91_PDC_RPR, 0); - at91_mci_write(AT91_PDC_RCR, 0); - at91_mci_write(AT91_PDC_RNPR, 0); - at91_mci_write(AT91_PDC_RNCR, 0); - at91_mci_write(AT91_PDC_TPR, 0); - at91_mci_write(AT91_PDC_TCR, 0); - at91_mci_write(AT91_PDC_TNPR, 0); - at91_mci_write(AT91_PDC_TNCR, 0); - - at91_mci_write(AT91_MCI_ARGR, cmd->arg); - at91_mci_write(AT91_MCI_CMDR, cmdr); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); + at91_mci_write(host, AT91_PDC_RPR, 0); + at91_mci_write(host, AT91_PDC_RCR, 0); + at91_mci_write(host, AT91_PDC_RNPR, 0); + at91_mci_write(host, AT91_PDC_RNCR, 0); + at91_mci_write(host, AT91_PDC_TPR, 0); + at91_mci_write(host, AT91_PDC_TCR, 0); + at91_mci_write(host, AT91_PDC_TNPR, 0); + at91_mci_write(host, AT91_PDC_TNCR, 0); + + at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); + at91_mci_write(host, AT91_MCI_CMDR, cmdr); return AT91_MCI_CMDRDY; } - mr = at91_mci_read(AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */ - at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); + mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */ + at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); /* * Disable the PDC controller */ - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); if (cmdr & AT91_MCI_TRCMD_START) { data->bytes_xfered = 0; @@ -485,8 +481,8 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ pr_debug("Transmitting %d bytes\n", host->total_length); - at91_mci_write(AT91_PDC_TPR, host->physical_address); - at91_mci_write(AT91_PDC_TCR, host->total_length / 4); + at91_mci_write(host, AT91_PDC_TPR, host->physical_address); + at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4); ier = AT91_MCI_TXBUFE; } } @@ -496,14 +492,14 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ * the data sheet says */ - at91_mci_write(AT91_MCI_ARGR, cmd->arg); - at91_mci_write(AT91_MCI_CMDR, cmdr); + at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); + at91_mci_write(host, AT91_MCI_CMDR, cmdr); if (cmdr & AT91_MCI_TRCMD_START) { if (cmdr & AT91_MCI_TRDIR) - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTEN); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN); else - at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN); + at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN); } return ier; } @@ -520,7 +516,7 @@ static void at91mci_process_command(struct at91mci_host *host, struct mmc_comman pr_debug("setting ier to %08X\n", ier); /* Stop on errors or the required value */ - at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); } /* @@ -548,19 +544,19 @@ static void at91mci_completed_command(struct at91mci_host *host) struct mmc_command *cmd = host->cmd; unsigned int status; - at91_mci_write(AT91_MCI_IDR, 0xffffffff); + at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); - cmd->resp[0] = at91_mci_read(AT91_MCI_RSPR(0)); - cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1)); - cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2)); - cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3)); + cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0)); + cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1)); + 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_free_coherent(NULL, host->total_length, host->buffer, host->physical_address); host->buffer = NULL; } - status = at91_mci_read(AT91_MCI_SR); + status = at91_mci_read(host, AT91_MCI_SR); pr_debug("Status = %08X [%08X %08X %08X %08X]\n", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); @@ -611,18 +607,18 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { int clkdiv; struct at91mci_host *host = mmc_priv(mmc); - unsigned long at91_master_clock = clk_get_rate(mci_clk); + unsigned long at91_master_clock = clk_get_rate(host->mci_clk); host->bus_mode = ios->bus_mode; if (ios->clock == 0) { /* Disable the MCI controller */ - at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS); + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS); clkdiv = 0; } else { /* Enable the MCI controller */ - at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN); + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); if ((at91_master_clock % (ios->clock * 2)) == 0) clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; @@ -634,25 +630,25 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) { pr_debug("MMC: Setting controller bus width to 4\n"); - at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS); + at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS); } else { pr_debug("MMC: Setting controller bus width to 1\n"); - at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); + at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); } /* Set the clock divider */ - at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); + at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); /* maybe switch power to the card */ if (host->board->vcc_pin) { switch (ios->power_mode) { case MMC_POWER_OFF: - at91_set_gpio_output(host->board->vcc_pin, 0); + at91_set_gpio_value(host->board->vcc_pin, 0); break; case MMC_POWER_UP: case MMC_POWER_ON: - at91_set_gpio_output(host->board->vcc_pin, 1); + at91_set_gpio_value(host->board->vcc_pin, 1); break; } } @@ -665,39 +661,40 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) { struct at91mci_host *host = devid; int completed = 0; + unsigned int int_status, int_mask; - unsigned int int_status; + int_status = at91_mci_read(host, AT91_MCI_SR); + int_mask = at91_mci_read(host, AT91_MCI_IMR); + + pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask, + int_status & int_mask); + + int_status = int_status & int_mask; - int_status = at91_mci_read(AT91_MCI_SR); - pr_debug("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR), - int_status & at91_mci_read(AT91_MCI_IMR)); - - if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000) + if (int_status & AT91_MCI_ERRORS) { completed = 1; + + if (int_status & AT91_MCI_UNRE) + pr_debug("MMC: Underrun error\n"); + if (int_status & AT91_MCI_OVRE) + pr_debug("MMC: Overrun error\n"); + if (int_status & AT91_MCI_DTOE) + pr_debug("MMC: Data timeout\n"); + if (int_status & AT91_MCI_DCRCE) + pr_debug("MMC: CRC error in data\n"); + if (int_status & AT91_MCI_RTOE) + pr_debug("MMC: Response timeout\n"); + if (int_status & AT91_MCI_RENDE) + pr_debug("MMC: Response end bit error\n"); + if (int_status & AT91_MCI_RCRCE) + pr_debug("MMC: Response CRC error\n"); + if (int_status & AT91_MCI_RDIRE) + pr_debug("MMC: Response direction error\n"); + if (int_status & AT91_MCI_RINDE) + pr_debug("MMC: Response index error\n"); + } else { + /* Only continue processing if no errors */ - int_status &= at91_mci_read(AT91_MCI_IMR); - - if (int_status & AT91_MCI_UNRE) - pr_debug("MMC: Underrun error\n"); - if (int_status & AT91_MCI_OVRE) - pr_debug("MMC: Overrun error\n"); - if (int_status & AT91_MCI_DTOE) - pr_debug("MMC: Data timeout\n"); - if (int_status & AT91_MCI_DCRCE) - pr_debug("MMC: CRC error in data\n"); - if (int_status & AT91_MCI_RTOE) - pr_debug("MMC: Response timeout\n"); - if (int_status & AT91_MCI_RENDE) - pr_debug("MMC: Response end bit error\n"); - if (int_status & AT91_MCI_RCRCE) - pr_debug("MMC: Response CRC error\n"); - if (int_status & AT91_MCI_RDIRE) - pr_debug("MMC: Response direction error\n"); - if (int_status & AT91_MCI_RINDE) - pr_debug("MMC: Response index error\n"); - - /* Only continue processing if no errors */ - if (!completed) { if (int_status & AT91_MCI_TXBUFE) { pr_debug("TX buffer empty\n"); at91_mci_handle_transmitted(host); @@ -705,12 +702,11 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) if (int_status & AT91_MCI_RXBUFF) { pr_debug("RX buffer full\n"); - at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY); } - if (int_status & AT91_MCI_ENDTX) { + if (int_status & AT91_MCI_ENDTX) pr_debug("Transmit has ended\n"); - } if (int_status & AT91_MCI_ENDRX) { pr_debug("Receive has ended\n"); @@ -719,37 +715,33 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) if (int_status & AT91_MCI_NOTBUSY) { pr_debug("Card is ready\n"); - at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY); } - if (int_status & AT91_MCI_DTIP) { + if (int_status & AT91_MCI_DTIP) pr_debug("Data transfer in progress\n"); - } - if (int_status & AT91_MCI_BLKE) { + if (int_status & AT91_MCI_BLKE) pr_debug("Block transfer has ended\n"); - } - if (int_status & AT91_MCI_TXRDY) { + if (int_status & AT91_MCI_TXRDY) pr_debug("Ready to transmit\n"); - } - if (int_status & AT91_MCI_RXRDY) { + if (int_status & AT91_MCI_RXRDY) pr_debug("Ready to receive\n"); - } if (int_status & AT91_MCI_CMDRDY) { pr_debug("Command ready\n"); completed = 1; } } - at91_mci_write(AT91_MCI_IDR, int_status); if (completed) { pr_debug("Completed command\n"); - at91_mci_write(AT91_MCI_IDR, 0xffffffff); + at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); at91mci_completed_command(host); - } + } else + at91_mci_write(host, AT91_MCI_IDR, int_status); return IRQ_HANDLED; } @@ -769,7 +761,7 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host) present ? "insert" : "remove"); if (!present) { pr_debug("****** Resetting SD-card bus width ******\n"); - at91_mci_write(AT91_MCI_SDCR, 0); + 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)); } @@ -793,7 +785,7 @@ int at91_mci_get_ro(struct mmc_host *mmc) return read_only; } -static struct mmc_host_ops at91_mci_ops = { +static const struct mmc_host_ops at91_mci_ops = { .request = at91_mci_request, .set_ios = at91_mci_set_ios, .get_ro = at91_mci_get_ro, @@ -806,15 +798,22 @@ static int at91_mci_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct at91mci_host *host; + struct resource *res; int ret; pr_debug("Probe MCI devices\n"); - at91_mci_disable(); - at91_mci_enable(); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME)) + return -EBUSY; mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); if (!mmc) { pr_debug("Failed to allocate mmc host\n"); + release_mem_region(res->start, res->end - res->start + 1); return -ENOMEM; } @@ -833,30 +832,51 @@ static int at91_mci_probe(struct platform_device *pdev) #ifdef SUPPORT_4WIRE mmc->caps |= MMC_CAP_4_BIT_DATA; #else - printk("MMC: 4 wire bus mode not supported by this driver - using 1 wire\n"); + printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n"); #endif } /* * Get Clock */ - mci_clk = clk_get(&pdev->dev, "mci_clk"); - if (IS_ERR(mci_clk)) { + host->mci_clk = clk_get(&pdev->dev, "mci_clk"); + if (IS_ERR(host->mci_clk)) { printk(KERN_ERR "AT91 MMC: no clock defined.\n"); mmc_free_host(mmc); + release_mem_region(res->start, res->end - res->start + 1); return -ENODEV; } - clk_enable(mci_clk); /* Enable the peripheral clock */ + + /* + * Map I/O region + */ + host->baseaddr = ioremap(res->start, res->end - res->start + 1); + if (!host->baseaddr) { + clk_put(host->mci_clk); + mmc_free_host(mmc); + release_mem_region(res->start, res->end - res->start + 1); + return -ENOMEM; + } + + /* + * Reset hardware + */ + clk_enable(host->mci_clk); /* Enable the peripheral clock */ + at91_mci_disable(host); + at91_mci_enable(host); /* * Allocate the MCI interrupt */ - ret = request_irq(AT91RM9200_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host); + host->irq = platform_get_irq(pdev, 0); + ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host); if (ret) { - printk(KERN_ERR "Failed to request MCI interrupt\n"); - clk_disable(mci_clk); - clk_put(mci_clk); + printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n"); + clk_disable(host->mci_clk); + clk_put(host->mci_clk); mmc_free_host(mmc); + iounmap(host->baseaddr); + release_mem_region(res->start, res->end - res->start + 1); return ret; } @@ -879,10 +899,10 @@ static int at91_mci_probe(struct platform_device *pdev) ret = request_irq(host->board->det_pin, at91_mmc_det_irq, 0, DRIVER_NAME, host); if (ret) - printk(KERN_ERR "couldn't allocate MMC detect irq\n"); + printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n"); } - pr_debug(KERN_INFO "Added MCI driver\n"); + pr_debug("Added MCI driver\n"); return 0; } @@ -894,6 +914,7 @@ static int at91_mci_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct at91mci_host *host; + struct resource *res; if (!mmc) return -1; @@ -905,16 +926,19 @@ static int at91_mci_remove(struct platform_device *pdev) cancel_delayed_work(&host->mmc->detect); } + at91_mci_disable(host); mmc_remove_host(mmc); - at91_mci_disable(); - free_irq(AT91RM9200_ID_MCI, host); - mmc_free_host(mmc); + free_irq(host->irq, host); - clk_disable(mci_clk); /* Disable the peripheral clock */ - clk_put(mci_clk); + clk_disable(host->mci_clk); /* Disable the peripheral clock */ + clk_put(host->mci_clk); - platform_set_drvdata(pdev, NULL); + iounmap(host->baseaddr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + mmc_free_host(mmc); + platform_set_drvdata(pdev, NULL); pr_debug("MCI Removed\n"); return 0; |