Commit 69de7fc0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc:
  AT91 MMC update for 2.6.19
  mmc: Change SDHCI iomem error to a warning
  mmc: fix "prev->state: 2 != TASK_RUNNING??" problem on SD/MMC  card removal
  AT91 MMC 5 : Minor cleanups
  AT91 MMC 4 : Interrupt handler cleanup
  AT91 MMC 3 : Move global mci_clk variable
  AT91 MMC 2 : Use platform resources
  AT91 MMC 1: Pass host structure.
parents 116140b7 99eeb8df
/* /*
* 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 * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
* *
...@@ -11,7 +11,7 @@ ...@@ -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. and SD-cards. Boards that support write protect are now supported.
The CCAT91SBC001 board does not support SD cards. The CCAT91SBC001 board does not support SD cards.
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
controller to manage the transfers. controller to manage the transfers.
A read is done from the controller directly to the scatterlist passed in from the request. 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 Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
swapped in the scatterlist buffers. swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug.
The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/mmc.h> #include <asm/mach/mmc.h>
#include <asm/arch/board.h> #include <asm/arch/board.h>
#include <asm/arch/cpu.h>
#include <asm/arch/gpio.h> #include <asm/arch/gpio.h>
#include <asm/arch/at91_mci.h> #include <asm/arch/at91_mci.h>
#include <asm/arch/at91_pdc.h> #include <asm/arch/at91_pdc.h>
...@@ -80,33 +81,17 @@ ...@@ -80,33 +81,17 @@
#undef SUPPORT_4WIRE #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 AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \
#define FL_SENT_STOP (1 << 1) | 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 * Low level type for this driver
*/ */
...@@ -116,9 +101,14 @@ struct at91mci_host ...@@ -116,9 +101,14 @@ struct at91mci_host
struct mmc_command *cmd; struct mmc_command *cmd;
struct mmc_request *request; struct mmc_request *request;
void __iomem *baseaddr;
int irq;
struct at91_mmc_data *board; struct at91_mmc_data *board;
int present; int present;
struct clk *mci_clk;
/* /*
* Flag indicating when the command has been sent. This is used to * Flag indicating when the command has been sent. This is used to
* work out whether or not to send the stop * 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 ...@@ -158,7 +148,6 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
struct scatterlist *sg; struct scatterlist *sg;
int amount; int amount;
int index;
unsigned int *sgbuffer; unsigned int *sgbuffer;
sg = &data->sg[i]; sg = &data->sg[i];
...@@ -166,10 +155,15 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data ...@@ -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; sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
amount = min(size, sg->length); amount = min(size, sg->length);
size -= amount; size -= amount;
amount /= 4;
for (index = 0; index < amount; index++) if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
*dmabuf++ = swab32(sgbuffer[index]); 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); kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
...@@ -217,13 +211,13 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) ...@@ -217,13 +211,13 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
/* Check to see if this needs filling */ /* Check to see if this needs filling */
if (i == 0) { 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"); pr_debug("Transfer active in current\n");
continue; continue;
} }
} }
else { 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"); pr_debug("Transfer active in next\n");
continue; continue;
} }
...@@ -240,12 +234,12 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) ...@@ -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); pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
if (i == 0) { if (i == 0) {
at91_mci_write(AT91_PDC_RPR, sg->dma_address); at91_mci_write(host, AT91_PDC_RPR, sg->dma_address);
at91_mci_write(AT91_PDC_RCR, sg->length / 4); at91_mci_write(host, AT91_PDC_RCR, sg->length / 4);
} }
else { else {
at91_mci_write(AT91_PDC_RNPR, sg->dma_address); at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address);
at91_mci_write(AT91_PDC_RNCR, sg->length / 4); at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4);
} }
} }
...@@ -276,8 +270,6 @@ static void at91mci_post_dma_read(struct at91mci_host *host) ...@@ -276,8 +270,6 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
while (host->in_use_index < host->transfer_index) { while (host->in_use_index < host->transfer_index) {
unsigned int *buffer; unsigned int *buffer;
int index;
int len;
struct scatterlist *sg; struct scatterlist *sg;
...@@ -295,11 +287,13 @@ static void at91mci_post_dma_read(struct at91mci_host *host) ...@@ -295,11 +287,13 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
data->bytes_xfered += sg->length; data->bytes_xfered += sg->length;
len = sg->length / 4; if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
int index;
for (index = 0; index < len; index++) { for (index = 0; index < (sg->length / 4); index++)
buffer[index] = swab32(buffer[index]); buffer[index] = swab32(buffer[index]);
} }
kunmap_atomic(buffer, KM_BIO_SRC_IRQ); kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
flush_dcache_page(sg->page); flush_dcache_page(sg->page);
} }
...@@ -308,8 +302,8 @@ static void at91mci_post_dma_read(struct at91mci_host *host) ...@@ -308,8 +302,8 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
if (host->transfer_index < data->sg_len) if (host->transfer_index < data->sg_len)
at91mci_pre_dma_read(host); at91mci_pre_dma_read(host);
else { else {
at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF); at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
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);
} }
pr_debug("post dma read done\n"); pr_debug("post dma read done\n");
...@@ -326,11 +320,11 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) ...@@ -326,11 +320,11 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
pr_debug("Handling the transmit\n"); pr_debug("Handling the transmit\n");
/* Disable the transfer */ /* 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 */ /* Now wait for cmd ready */
at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE); at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY); at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
cmd = host->cmd; cmd = host->cmd;
if (!cmd) return; if (!cmd) return;
...@@ -344,21 +338,23 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) ...@@ -344,21 +338,23 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
/* /*
* Enable the controller * 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(host, AT91_MCI_CR, AT91_MCI_MCIEN);
at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF); at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
at91_mci_write(AT91_MCI_MR, 0x834A); at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);
at91_mci_write(AT91_MCI_SDCR, 0x0);
/* use Slot A or B (only one at same time) */
at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
} }
/* /*
* Disable the controller * 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_ ...@@ -378,13 +374,13 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
/* Not sure if this is needed */ /* Not sure if this is needed */
#if 0 #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"); pr_debug("Clearing timeout\n");
at91_mci_write(AT91_MCI_ARGR, 0); at91_mci_write(host, AT91_MCI_ARGR, 0);
at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD); at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) { while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
/* spin */ /* 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 #endif
...@@ -431,32 +427,32 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ ...@@ -431,32 +427,32 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
/* /*
* Set the arguments and send the command * Set the arguments and send the command
*/ */
pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n", 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(AT91_MCI_MR)); cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
if (!data) { if (!data) {
at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
at91_mci_write(AT91_PDC_RPR, 0); at91_mci_write(host, AT91_PDC_RPR, 0);
at91_mci_write(AT91_PDC_RCR, 0); at91_mci_write(host, AT91_PDC_RCR, 0);
at91_mci_write(AT91_PDC_RNPR, 0); at91_mci_write(host, AT91_PDC_RNPR, 0);
at91_mci_write(AT91_PDC_RNCR, 0); at91_mci_write(host, AT91_PDC_RNCR, 0);
at91_mci_write(AT91_PDC_TPR, 0); at91_mci_write(host, AT91_PDC_TPR, 0);
at91_mci_write(AT91_PDC_TCR, 0); at91_mci_write(host, AT91_PDC_TCR, 0);
at91_mci_write(AT91_PDC_TNPR, 0); at91_mci_write(host, AT91_PDC_TNPR, 0);
at91_mci_write(AT91_PDC_TNCR, 0); at91_mci_write(host, AT91_PDC_TNCR, 0);
at91_mci_write(AT91_MCI_ARGR, cmd->arg); at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
at91_mci_write(AT91_MCI_CMDR, cmdr); at91_mci_write(host, AT91_MCI_CMDR, cmdr);
return AT91_MCI_CMDRDY; return AT91_MCI_CMDRDY;
} }
mr = at91_mci_read(AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */ mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
/* /*
* Disable the PDC controller * 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) { if (cmdr & AT91_MCI_TRCMD_START) {
data->bytes_xfered = 0; data->bytes_xfered = 0;
...@@ -485,8 +481,8 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ ...@@ -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); pr_debug("Transmitting %d bytes\n", host->total_length);
at91_mci_write(AT91_PDC_TPR, host->physical_address); at91_mci_write(host, AT91_PDC_TPR, host->physical_address);
at91_mci_write(AT91_PDC_TCR, host->total_length / 4); at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4);
ier = AT91_MCI_TXBUFE; ier = AT91_MCI_TXBUFE;
} }
} }
...@@ -496,14 +492,14 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ ...@@ -496,14 +492,14 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
* the data sheet says * the data sheet says
*/ */
at91_mci_write(AT91_MCI_ARGR, cmd->arg); at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
at91_mci_write(AT91_MCI_CMDR, cmdr); at91_mci_write(host, AT91_MCI_CMDR, cmdr);
if (cmdr & AT91_MCI_TRCMD_START) { if (cmdr & AT91_MCI_TRCMD_START) {
if (cmdr & AT91_MCI_TRDIR) 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 else
at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN); at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN);
} }
return ier; return ier;
} }
...@@ -520,7 +516,7 @@ static void at91mci_process_command(struct at91mci_host *host, struct mmc_comman ...@@ -520,7 +516,7 @@ static void at91mci_process_command(struct at91mci_host *host, struct mmc_comman
pr_debug("setting ier to %08X\n", ier); pr_debug("setting ier to %08X\n", ier);
/* Stop on errors or the required value */ /* 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) ...@@ -548,19 +544,19 @@ static void at91mci_completed_command(struct at91mci_host *host)
struct mmc_command *cmd = host->cmd; struct mmc_command *cmd = host->cmd;
unsigned int status; 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[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1)); cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2)); cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3)); cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
if (host->buffer) { if (host->buffer) {
dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address); dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
host->buffer = NULL; 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", pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); 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) ...@@ -611,18 +607,18 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{ {
int clkdiv; int clkdiv;
struct at91mci_host *host = mmc_priv(mmc); 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; host->bus_mode = ios->bus_mode;
if (ios->clock == 0) { if (ios->clock == 0) {
/* Disable the MCI controller */ /* 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; clkdiv = 0;
} }
else { else {
/* Enable the MCI controller */ /* 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) if ((at91_master_clock % (ios->clock * 2)) == 0)
clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; 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) ...@@ -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) { if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
pr_debug("MMC: Setting controller bus width to 4\n"); 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 { else {
pr_debug("MMC: Setting controller bus width to 1\n"); 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 */ /* 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 */ /* maybe switch power to the card */
if (host->board->vcc_pin) { if (host->board->vcc_pin) {
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_OFF: case MMC_POWER_OFF:
at91_set_gpio_output(host->board->vcc_pin, 0); at91_set_gpio_value(host->board->vcc_pin, 0);
break; break;
case MMC_POWER_UP: case MMC_POWER_UP:
case MMC_POWER_ON: case MMC_POWER_ON:
at91_set_gpio_output(host->board->vcc_pin, 1); at91_set_gpio_value(host->board->vcc_pin, 1);
break; break;
} }
} }
...@@ -665,39 +661,40 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) ...@@ -665,39 +661,40 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
{ {
struct at91mci_host *host = devid; struct at91mci_host *host = devid;
int completed = 0; 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); if (int_status & AT91_MCI_ERRORS) {
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)
completed = 1; 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) { if (int_status & AT91_MCI_TXBUFE) {
pr_debug("TX buffer empty\n"); pr_debug("TX buffer empty\n");
at91_mci_handle_transmitted(host); at91_mci_handle_transmitted(host);
...@@ -705,12 +702,11 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) ...@@ -705,12 +702,11 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
if (int_status & AT91_MCI_RXBUFF) { if (int_status & AT91_MCI_RXBUFF) {
pr_debug("RX buffer full\n"); 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"); pr_debug("Transmit has ended\n");
}
if (int_status & AT91_MCI_ENDRX) { if (int_status & AT91_MCI_ENDRX) {
pr_debug("Receive has ended\n"); pr_debug("Receive has ended\n");
...@@ -719,37 +715,33 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) ...@@ -719,37 +715,33 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
if (int_status & AT91_MCI_NOTBUSY) { if (int_status & AT91_MCI_NOTBUSY) {
pr_debug("Card is ready\n"); 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"); 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"); 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"); pr_debug("Ready to transmit\n");
}
if (int_status & AT91_MCI_RXRDY) { if (int_status & AT91_MCI_RXRDY)
pr_debug("Ready to receive\n"); pr_debug("Ready to receive\n");
}
if (int_status & AT91_MCI_CMDRDY) { if (int_status & AT91_MCI_CMDRDY) {
pr_debug("Command ready\n"); pr_debug("Command ready\n");
completed = 1; completed = 1;
} }
} }
at91_mci_write(AT91_MCI_IDR, int_status);
if (completed) { if (completed) {
pr_debug("Completed command\n"); pr_debug("Completed command\n");
at91_mci_write(AT91_MCI_IDR, 0xffffffff); at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
at91mci_completed_command(host); at91mci_completed_command(host);
} } else
at91_mci_write(host, AT91_MCI_IDR, int_status);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -769,7 +761,7 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host) ...@@ -769,7 +761,7 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
present ? "insert" : "remove"); present ? "insert" : "remove");
if (!present) { if (!present) {
pr_debug("****** Resetting SD-card bus width ******\n"); 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)); mmc_detect_change(host->mmc, msecs_to_jiffies(100));
} }
...@@ -806,15 +798,22 @@ static int at91_mci_probe(struct platform_device *pdev) ...@@ -806,15 +798,22 @@ static int at91_mci_probe(struct platform_device *pdev)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
struct at91mci_host *host; struct at91mci_host *host;
struct resource *res;
int ret; int ret;
pr_debug("Probe MCI devices\n"); 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); mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
if (!mmc) { if (!mmc) {
pr_debug("Failed to allocate mmc host\n"); pr_debug("Failed to allocate mmc host\n");
release_mem_region(res->start, res->end - res->start + 1);
return -ENOMEM; return -ENOMEM;
} }
...@@ -833,30 +832,51 @@ static int at91_mci_probe(struct platform_device *pdev) ...@@ -833,30 +832,51 @@ static int at91_mci_probe(struct platform_device *pdev)
#ifdef SUPPORT_4WIRE #ifdef SUPPORT_4WIRE
mmc->caps |= MMC_CAP_4_BIT_DATA; mmc->caps |= MMC_CAP_4_BIT_DATA;
#else #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 #endif
} }
/* /*
* Get Clock * Get Clock
*/ */
mci_clk = clk_get(&pdev->dev, "mci_clk"); host->mci_clk = clk_get(&pdev->dev, "mci_clk");
if (IS_ERR(mci_clk)) { if (IS_ERR(host->mci_clk)) {
printk(KERN_ERR "AT91 MMC: no clock defined.\n"); printk(KERN_ERR "AT91 MMC: no clock defined.\n");
mmc_free_host(mmc); mmc_free_host(mmc);
release_mem_region(res->start, res->end - res->start + 1);
return -ENODEV; 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 * 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) { if (ret) {
printk(KERN_ERR "Failed to request MCI interrupt\n"); printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
clk_disable(mci_clk); clk_disable(host->mci_clk);
clk_put(mci_clk); clk_put(host->mci_clk);
mmc_free_host(mmc); mmc_free_host(mmc);
iounmap(host->baseaddr);
release_mem_region(res->start, res->end - res->start + 1);
return ret; return ret;
} }
...@@ -879,10 +899,10 @@ static int at91_mci_probe(struct platform_device *pdev) ...@@ -879,10 +899,10 @@ static int at91_mci_probe(struct platform_device *pdev)
ret = request_irq(host->board->det_pin, at91_mmc_det_irq, ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
0, DRIVER_NAME, host); 0, DRIVER_NAME, host);
if (ret) 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; return 0;
} }
...@@ -894,6 +914,7 @@ static int at91_mci_remove(struct platform_device *pdev) ...@@ -894,6 +914,7 @@ static int at91_mci_remove(struct platform_device *pdev)
{ {
struct mmc_host *mmc = platform_get_drvdata(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev);
struct at91mci_host *host; struct at91mci_host *host;
struct resource *res;
if (!mmc) if (!mmc)
return -1; return -1;
...@@ -905,16 +926,19 @@ static int at91_mci_remove(struct platform_device *pdev) ...@@ -905,16 +926,19 @@ static int at91_mci_remove(struct platform_device *pdev)
cancel_delayed_work(&host->mmc->detect); cancel_delayed_work(&host->mmc->detect);
} }
at91_mci_disable(host);
mmc_remove_host(mmc); mmc_remove_host(mmc);
at91_mci_disable(); free_irq(host->irq, host);
free_irq(AT91RM9200_ID_MCI, host);
mmc_free_host(mmc);
clk_disable(mci_clk); /* Disable the peripheral clock */ clk_disable(host->mci_clk); /* Disable the peripheral clock */
clk_put(mci_clk); 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"); pr_debug("MCI Removed\n");
return 0; return 0;
......
...@@ -78,8 +78,10 @@ static int mmc_queue_thread(void *d) ...@@ -78,8 +78,10 @@ static int mmc_queue_thread(void *d)
spin_unlock_irq(q->queue_lock); spin_unlock_irq(q->queue_lock);
if (!req) { if (!req) {
if (kthread_should_stop()) if (kthread_should_stop()) {
set_current_state(TASK_RUNNING);
break; break;
}
up(&mq->thread_sem); up(&mq->thread_sem);
schedule(); schedule();
down(&mq->thread_sem); down(&mq->thread_sem);
......
...@@ -1170,8 +1170,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) ...@@ -1170,8 +1170,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
} }
if (pci_resource_len(pdev, first_bar + slot) != 0x100) { if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. Aborting.\n"); printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
return -ENODEV; "You may experience problems.\n");
} }
if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment