static void ak98_sdio_start_command(struct ak98_mci_host *host, struct mmc_command *cmd) { unsigned int c; void __iomem *base = host->base; PK1("%s: op %i arg 0x%08x flags 0x%08x\n", __func__, cmd->opcode, cmd->arg, cmd->flags); if (readl(base + AK98MCICOMMAND) & MCI_CPSM_ENABLE) { writel(0, base + AK98MCICOMMAND); udelay(1); } c = MCI_CPSM_CMD(cmd->opcode) | MCI_CPSM_ENABLE; if (cmd->flags & MMC_RSP_PRESENT) { c |= MCI_CPSM_RESPONSE; if (cmd->flags & MMC_RSP_136) c |= MCI_CPSM_LONGRSP; } if (cmd->data) c |= MCI_CPSM_WITHDATA; host->cmd = cmd; writel(cmd->arg, base + AK98MCIARGUMENT); writel(readl(base + AK98MCIMASK) | MCI_CMDIRQMASKS, base + AK98MCIMASK); PK("ENABLE CMD IRQ\n"); PK("irqmask: 0x%08x\n", readl(base+AK98MCIMASK)); writel(c, base + AK98MCICOMMAND); }
static void ak98_sdio_stop_data(struct ak98_mci_host *host) { u32 masks; PK1("%s\n", __func__); writel(0, host->base + AK98MCIDMACTRL); writel(0, host->base + AK98MCIDATACTRL); masks = readl(host->base + AK98MCIMASK); masks &= ~(MCI_DATAIRQMASKS|MCI_FIFOFULLMASK|MCI_FIFOEMPTYMASK); writel(masks, host->base + AK98MCIMASK); PK("DISABLE DATA IRQ\n"); #ifdef MCI_USE_L2FIFO_DMA if (host->data->flags & MMC_DATA_WRITE) { dma_sync_sg_for_cpu(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, DMA_TO_DEVICE); dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, DMA_TO_DEVICE); } else { dma_sync_sg_for_cpu(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, DMA_FROM_DEVICE); dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, DMA_FROM_DEVICE); } #endif host->data = NULL; }
static void ak98_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct ak98_mci_host *host = mmc_priv(mmc); PK1("%s: CMD%i\n", __func__, mrq->cmd->opcode); host->mrq = mrq; if (mrq->data && !is_power_of_2(mrq->data->blksz)) { printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", mmc_hostname(mmc), mrq->data->blksz); mrq->cmd->error = -EINVAL; mmc_request_done(mmc, mrq); return; } if (ak98_mci_get_cd(mmc) == 0) { printk("%s: no medium present\n", __func__); host->mrq->cmd->error = -ENOMEDIUM; mmc_request_done(mmc, mrq); } else { ak98_mci_send_request(mmc); } }
static void ak98_mci_request_end(struct ak98_mci_host *host, struct mmc_request *mrq) { int not_retry = 0; PK1("%s\n", __func__); writel(0, host->base + AK98MCICOMMAND); BUG_ON(host->data); host->mrq = NULL; host->cmd = NULL; if(l2_mci_bufid != BUF_NULL) { ak98_l2_free(ADDR_MMC_SD); l2_mci_bufid = BUF_NULL; } if (mrq->data) mrq->data->bytes_xfered = host->data_xfered; /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... */ spin_unlock(&host->lock); not_retry = (!mrq->cmd->error) || ((mrq->cmd->error && (mrq->cmd->retries == 0))); mmc_request_done(host->mmc, mrq); #ifdef CONFIG_MTD_NAND_AK98 /*if request fail,then mmc_request_done send request again, * ak98_mci_send_request not down nand_lock in interrupt,so not to up nand_lock. */ if (not_retry) { up(&nand_lock); } #endif #ifdef CONFIG_CPU_FREQ /*if request fail,then mmc_request_done send request again, * ak98_mci_send_request not down freq_lock in interrupt,so not to unlock freq_lock. */ if (not_retry) { up(&host->freq_lock); } #endif spin_lock(&host->lock); }
static void ak98_sdio_data_irq(struct ak98_mci_host *host, struct mmc_data *data, unsigned int status) { if (status & MCI_DATABLOCKEND) { PK("BLOCKEND\n"); #ifdef AKMCI_L2FIFO_PIO if (data->flags & MMC_DATA_WRITE) { ak98_l2_clr_status(l2_sdio_bufid); } if (host->size > 0) mci_xfer(host); #endif } if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT)) { PK1("DATA ERROR: 0x%08x\n", status); if (status & MCI_DATACRCFAIL ) data->error = -EILSEQ; else if (status & MCI_DATATIMEOUT) data->error = -ETIMEDOUT; status |= MCI_DATAEND; /* * We hit an error condition. Ensure that any data * partially written to a page is properly coherent. */ if (host->sg_len && data->flags & MMC_DATA_READ) flush_dcache_page(sg_page(host->sg_ptr)); } if (status & MCI_DATAEND) { ak98_sdio_stop_data(host); //dump_data(data); if (!data->stop) { ak98_sdio_request_end(host, data->mrq); } else { ak98_sdio_start_command(host, data->stop); } } }
static void ak98_sdio_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct ak98_mci_host *host = mmc_priv(mmc); PK1("%s: CMD%i\n", __func__, mrq->cmd->opcode); host->mrq = mrq; if (ak98_sdio_get_cd(mmc) == 0) { printk("%s: no medium present\n", __func__); host->mrq->cmd->error = -ENOMEDIUM; mmc_request_done(mmc, mrq); } else { ak98_sdio_send_request(mmc); } }