static void at91_reset_host(struct at91mci_host *host) { unsigned long flags; u32 mr; u32 sdcr; u32 dtor; u32 imr; local_irq_save(flags); imr = at91_mci_read(host, AT91_MCI_IMR); at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; sdcr = at91_mci_read(host, AT91_MCI_SDCR); dtor = at91_mci_read(host, AT91_MCI_DTOR); at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); at91_mci_write(host, AT91_MCI_MR, mr); at91_mci_write(host, AT91_MCI_SDCR, sdcr); at91_mci_write(host, AT91_MCI_DTOR, dtor); at91_mci_write(host, AT91_MCI_IER, imr); at91_mci_read(host, AT91_MCI_SR); local_irq_restore(flags); }
/* * Reset the controller and restore most of the state */ static void at91_reset_host(struct at91mci_host *host) { unsigned long flags; u32 mr; u32 sdcr; u32 dtor; u32 imr; local_irq_save(flags); imr = at91_mci_read(host, AT91_MCI_IMR); at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); /* save current state */ mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; sdcr = at91_mci_read(host, AT91_MCI_SDCR); dtor = at91_mci_read(host, AT91_MCI_DTOR); /* reset the controller */ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); /* restore state */ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); at91_mci_write(host, AT91_MCI_MR, mr); at91_mci_write(host, AT91_MCI_SDCR, sdcr); at91_mci_write(host, AT91_MCI_DTOR, dtor); at91_mci_write(host, AT91_MCI_IER, imr); /* make sure sdio interrupts will fire */ at91_mci_read(host, AT91_MCI_SR); local_irq_restore(flags); }
/* * Handle a command that has been completed */ static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status) { struct mmc_command *cmd = host->cmd; struct mmc_data *data = cmd->data; at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); 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_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]); if (status & AT91_MCI_ERRORS) { if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { cmd->error = 0; } else { if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) { if (data) { if (status & AT91_MCI_DTOE) data->error = -ETIMEDOUT; else if (status & AT91_MCI_DCRCE) data->error = -EILSEQ; } } else { if (status & AT91_MCI_RTOE) cmd->error = -ETIMEDOUT; else if (status & AT91_MCI_RCRCE) cmd->error = -EILSEQ; else cmd->error = -EIO; } pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n", cmd->error, data ? data->error : 0, cmd->opcode, cmd->retries); } } else cmd->error = 0; at91_mci_process_next(host); }
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(host->mci_clk); host->bus_mode = ios->bus_mode; if (ios->clock == 0) { at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS); clkdiv = 0; } else { 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; else clkdiv = (at91_master_clock / ios->clock) / 2; pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv, at91_master_clock / (2 * (clkdiv + 1))); } if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) { pr_debug("MMC: Setting controller bus width to 4\n"); 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(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); } at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); if (gpio_is_valid(host->board->vcc_pin)) { switch (ios->power_mode) { case MMC_POWER_OFF: gpio_set_value(host->board->vcc_pin, 0); break; case MMC_POWER_UP: gpio_set_value(host->board->vcc_pin, 1); break; case MMC_POWER_ON: break; default: WARN_ON(1); } } }
/* * Handle a command that has been completed */ static void at91mci_completed_command(struct at91mci_host *host) { struct mmc_command *cmd = host->cmd; unsigned int status; at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); 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(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]); if (status & (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)) { if ((status & AT91_MCI_RCRCE) && ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) { cmd->error = MMC_ERR_NONE; } else { if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE)) cmd->error = MMC_ERR_TIMEOUT; else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE)) cmd->error = MMC_ERR_BADCRC; else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE)) cmd->error = MMC_ERR_FIFO; else cmd->error = MMC_ERR_FAILED; pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n", cmd->error, cmd->opcode, cmd->retries); } } else cmd->error = MMC_ERR_NONE; at91mci_process_next(host); }
static irqreturn_t at91_mmc_det_irq(int irq, void *_host) { struct at91mci_host *host = _host; int present; /* entering this ISR means that we have configured det_pin: * we can use its value in board structure */ present = !gpio_get_value(host->board->det_pin); /* * we expect this irq on both insert and remove, * and use a short delay to debounce. */ if (present != host->present) { host->present = present; pr_debug("%s: card %s\n", mmc_hostname(host->mmc), present ? "insert" : "remove"); if (!present) { 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); } /* 0.5s needed because of early card detect switch firing */ mmc_detect_change(host->mmc, msecs_to_jiffies(500)); } return IRQ_HANDLED; }
/* * Handle a command that has been completed */ static void at91_mci_completed_command(struct at91mci_host *host) { struct mmc_command *cmd = host->cmd; unsigned int status; at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); 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(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]); if (status & AT91_MCI_ERRORS) { if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { cmd->error = 0; } else { if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE)) cmd->error = -ETIMEDOUT; else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE)) cmd->error = -EILSEQ; else cmd->error = -EIO; pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n", cmd->error, cmd->opcode, cmd->retries); } } else cmd->error = 0; at91_mci_process_next(host); }
static irqreturn_t at91_mmc_det_irq(int irq, void *_host) { struct at91mci_host *host = _host; int present; present = !gpio_get_value(host->board->det_pin); if (present != host->present) { host->present = present; pr_debug("%s: card %s\n", mmc_hostname(host->mmc), present ? "insert" : "remove"); if (!present) { 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(500)); } return IRQ_HANDLED; }
static irqreturn_t at91_mmc_det_irq(int irq, void *_host) { struct at91mci_host *host = _host; int present = !at91_get_gpio_value(irq); /* * we expect this irq on both insert and remove, * and use a short delay to debounce. */ if (present != host->present) { host->present = present; pr_debug("%s: card %s\n", mmc_hostname(host->mmc), present ? "insert" : "remove"); if (!present) { 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)); } return IRQ_HANDLED; }
/* * Handle an interrupt */ static irqreturn_t at91_mci_irq(int irq, void *devid) { struct at91mci_host *host = devid; int completed = 0; unsigned int int_status, int_mask; 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; 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 */ if (int_status & AT91_MCI_TXBUFE) { pr_debug("TX buffer empty\n"); at91_mci_handle_transmitted(host); } if (int_status & AT91_MCI_ENDRX) { pr_debug("ENDRX\n"); at91_mci_post_dma_read(host); } if (int_status & AT91_MCI_RXBUFF) { pr_debug("RX buffer full\n"); at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX); completed = 1; } if (int_status & AT91_MCI_ENDTX) pr_debug("Transmit has ended\n"); if (int_status & AT91_MCI_NOTBUSY) { pr_debug("Card is ready\n"); completed = 1; } if (int_status & AT91_MCI_DTIP) pr_debug("Data transfer in progress\n"); if (int_status & AT91_MCI_BLKE) { pr_debug("Block transfer has ended\n"); completed = 1; } if (int_status & AT91_MCI_TXRDY) pr_debug("Ready to transmit\n"); if (int_status & AT91_MCI_RXRDY) pr_debug("Ready to receive\n"); if (int_status & AT91_MCI_CMDRDY) { pr_debug("Command ready\n"); completed = at91_mci_handle_cmdrdy(host); } } if (completed) { pr_debug("Completed command\n"); at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); at91_mci_completed_command(host); } else at91_mci_write(host, AT91_MCI_IDR, int_status); return IRQ_HANDLED; }
/* * Send a command */ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) { unsigned int cmdr, mr; unsigned int block_length; struct mmc_data *data = cmd->data; unsigned int blocks; unsigned int ier = 0; host->cmd = cmd; /* Needed for leaving busy state before CMD1 */ if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { pr_debug("Clearing timeout\n"); 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(host, AT91_MCI_SR)); } } cmdr = cmd->opcode; if (mmc_resp_type(cmd) == MMC_RSP_NONE) cmdr |= AT91_MCI_RSPTYP_NONE; else { /* if a response is expected then allow maximum response latancy */ cmdr |= AT91_MCI_MAXLAT; /* set 136 bit response for R2, 48 bit response otherwise */ if (mmc_resp_type(cmd) == MMC_RSP_R2) cmdr |= AT91_MCI_RSPTYP_136; else cmdr |= AT91_MCI_RSPTYP_48; } if (data) { if ( data->blksz & 0x3 ) { pr_debug("Unsupported block size\n"); cmd->error = -EINVAL; mmc_request_done(host->mmc, host->request); return; } block_length = data->blksz; blocks = data->blocks; /* always set data start - also set direction flag for read */ if (data->flags & MMC_DATA_READ) cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START); else if (data->flags & MMC_DATA_WRITE) cmdr |= AT91_MCI_TRCMD_START; if (data->flags & MMC_DATA_STREAM) cmdr |= AT91_MCI_TRTYP_STREAM; if (data->blocks > 1) cmdr |= AT91_MCI_TRTYP_MULTIPLE; } else { block_length = 0; blocks = 0; } if (host->flags & FL_SENT_STOP) cmdr |= AT91_MCI_TRCMD_STOP; if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) cmdr |= AT91_MCI_OPDCMD; /* * Set the arguments and send the command */ 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(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); at91_mci_write(host, ATMEL_PDC_RPR, 0); at91_mci_write(host, ATMEL_PDC_RCR, 0); at91_mci_write(host, ATMEL_PDC_RNPR, 0); at91_mci_write(host, ATMEL_PDC_RNCR, 0); at91_mci_write(host, ATMEL_PDC_TPR, 0); at91_mci_write(host, ATMEL_PDC_TCR, 0); at91_mci_write(host, ATMEL_PDC_TNPR, 0); at91_mci_write(host, ATMEL_PDC_TNCR, 0); ier = AT91_MCI_CMDRDY; } else { /* zero block length and PDC mode */ mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); /* * Disable the PDC controller */ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); if (cmdr & AT91_MCI_TRCMD_START) { data->bytes_xfered = 0; host->transfer_index = 0; host->in_use_index = 0; if (cmdr & AT91_MCI_TRDIR) { /* * Handle a read */ host->buffer = NULL; host->total_length = 0; at91_mci_pre_dma_read(host); ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; } else { /* * Handle a write */ host->total_length = block_length * blocks; host->buffer = dma_alloc_coherent(NULL, host->total_length, &host->physical_address, GFP_KERNEL); at91_mci_sg_to_dma(host, data); pr_debug("Transmitting %d bytes\n", host->total_length); at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4); ier = AT91_MCI_CMDRDY; } } } /* * Send the command and then enable the PDC - not the other way round as * the data sheet says */ 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(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } /* Enable selected interrupts */ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); }
/* * 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, sg->length / 4); } else { at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address); at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4); } } pr_debug("pre dma read done\n"); }
static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) { unsigned int cmdr, mr; unsigned int block_length; struct mmc_data *data = cmd->data; unsigned int blocks; unsigned int ier = 0; host->cmd = cmd; if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { pr_debug("Clearing timeout\n"); 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)) { pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); } } cmdr = cmd->opcode; if (mmc_resp_type(cmd) == MMC_RSP_NONE) cmdr |= AT91_MCI_RSPTYP_NONE; else { cmdr |= AT91_MCI_MAXLAT; if (mmc_resp_type(cmd) == MMC_RSP_R2) cmdr |= AT91_MCI_RSPTYP_136; else cmdr |= AT91_MCI_RSPTYP_48; } if (data) { if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) { if (data->blksz & 0x3) { pr_debug("Unsupported block size\n"); cmd->error = -EINVAL; mmc_request_done(host->mmc, host->request); return; } if (data->flags & MMC_DATA_STREAM) { pr_debug("Stream commands not supported\n"); cmd->error = -EINVAL; mmc_request_done(host->mmc, host->request); return; } } block_length = data->blksz; blocks = data->blocks; if (data->flags & MMC_DATA_READ) cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START); else if (data->flags & MMC_DATA_WRITE) cmdr |= AT91_MCI_TRCMD_START; if (cmd->opcode == SD_IO_RW_EXTENDED) { cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK; } else { if (data->flags & MMC_DATA_STREAM) cmdr |= AT91_MCI_TRTYP_STREAM; if (data->blocks > 1) cmdr |= AT91_MCI_TRTYP_MULTIPLE; } } else { block_length = 0; blocks = 0; } if (host->flags & FL_SENT_STOP) cmdr |= AT91_MCI_TRCMD_STOP; if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) cmdr |= AT91_MCI_OPDCMD; 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(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); at91_mci_write(host, ATMEL_PDC_RPR, 0); at91_mci_write(host, ATMEL_PDC_RCR, 0); at91_mci_write(host, ATMEL_PDC_RNPR, 0); at91_mci_write(host, ATMEL_PDC_RNCR, 0); at91_mci_write(host, ATMEL_PDC_TPR, 0); at91_mci_write(host, ATMEL_PDC_TCR, 0); at91_mci_write(host, ATMEL_PDC_TNPR, 0); at91_mci_write(host, ATMEL_PDC_TNCR, 0); ier = AT91_MCI_CMDRDY; } else { mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff; mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0; mr |= (block_length << 16); mr |= AT91_MCI_PDCMODE; at91_mci_write(host, AT91_MCI_MR, mr); if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261())) at91_mci_write(host, AT91_MCI_BLKR, AT91_MCI_BLKR_BCNT(blocks) | AT91_MCI_BLKR_BLKLEN(block_length)); at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); if (cmdr & AT91_MCI_TRCMD_START) { data->bytes_xfered = 0; host->transfer_index = 0; host->in_use_index = 0; if (cmdr & AT91_MCI_TRDIR) { host->total_length = 0; 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 ; } else { host->total_length = block_length * blocks; if (at91mci_is_mci1rev2xx()) if (host->total_length < 12) host->total_length = 12; at91_mci_sg_to_dma(host, data); pr_debug("Transmitting %d bytes\n", host->total_length); at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ? host->total_length : host->total_length / 4); ier = AT91_MCI_CMDRDY; } } } 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(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); }