static int sh_mmcif_single_read(struct sh_mmcif_host *host, struct mmc_request *mrq) { struct mmc_data *data = mrq->data; long time; u32 blocksize, i, *p = sg_virt(data->sg); host->wait_int = 0; /* buf read enable */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); time = wait_event_interruptible_timeout(host->intr_wait, host->wait_int == 1 || host->sd_error == 1, host->timeout); if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) return sh_mmcif_error_manage(host); host->wait_int = 0; blocksize = (BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; for (i = 0; i < blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); /* buffer read end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); time = wait_event_interruptible_timeout(host->intr_wait, host->wait_int == 1 || host->sd_error == 1, host->timeout); if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) return sh_mmcif_error_manage(host); host->wait_int = 0; return 0; }
static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) { struct sh_mmcif_host *host = dev_id; u32 state, mask; state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); mask = sh_mmcif_readl(host->addr, MMCIF_CE_INT_MASK); if (host->ccs_enable) sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(state & mask)); else sh_mmcif_writel(host->addr, MMCIF_CE_INT, INT_CCS | ~(state & mask)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state & MASK_CLEAN); if (state & ~MASK_CLEAN) dev_dbg(&host->pd->dev, "IRQ state = 0x%08x incompletely cleared\n", state); if (state & INT_ERR_STS || state & ~INT_ALL) { host->sd_error = true; dev_dbg(&host->pd->dev, "int err state = 0x%08x\n", state); } if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { if (!host->mrq) dev_dbg(&host->pd->dev, "NULL IRQ state = 0x%08x\n", state); if (!host->dma_active) return IRQ_WAKE_THREAD; else if (host->sd_error) mmcif_dma_complete(host); } else { dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state); } return IRQ_HANDLED; }
static int sh_mmcif_multi_read(struct sh_mmcif_host *host, struct mmc_request *mrq) { struct mmc_data *data = mrq->data; long time; u32 blocksize, i, j, sec, *p; blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET); for (j = 0; j < data->sg_len; j++) { p = sg_virt(data->sg); host->wait_int = 0; for (sec = 0; sec < data->sg->length / blocksize; sec++) { sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); /* buf read enable */ time = wait_event_interruptible_timeout(host->intr_wait, host->wait_int == 1 || host->sd_error == 1, host->timeout); if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) return sh_mmcif_error_manage(host); host->wait_int = 0; for (i = 0; i < blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); } if (j < data->sg_len - 1) data->sg++; } return 0; }
static void sh_mmcif_get_response(struct sh_mmcif_host *host, struct mmc_command *cmd) { if (cmd->flags & MMC_RSP_136) { cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP3); cmd->resp[1] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP2); cmd->resp[2] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP1); cmd->resp[3] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); } else cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); }
static int sh_mmcif_error_manage(struct sh_mmcif_host *host) { u32 state1, state2; int ret, timeout; host->sd_error = false; state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1); state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2); dev_dbg(&host->pd->dev, "ERR HOST_STS1 = %08x\n", state1); dev_dbg(&host->pd->dev, "ERR HOST_STS2 = %08x\n", state2); if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); for (timeout = 10000000; timeout; timeout--) { if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) & STS1_CMDSEQ)) break; mdelay(1); } if (!timeout) { dev_err(&host->pd->dev, "Forced end of command sequence timeout err\n"); return -EIO; } sh_mmcif_sync_reset(host); dev_dbg(&host->pd->dev, "Forced end of command sequence\n"); return -EIO; } if (state2 & STS2_CRC_ERR) { dev_err(&host->pd->dev, " CRC error: state %u, wait %u\n", host->state, host->wait_for); ret = -EIO; } else if (state2 & STS2_TIMEOUT_ERR) { dev_err(&host->pd->dev, " Timeout: state %u, wait %u\n", host->state, host->wait_for); ret = -ETIMEDOUT; } else { dev_dbg(&host->pd->dev, " End/Index error: state %u, wait %u\n", host->state, host->wait_for); ret = -EIO; } return ret; }
static int sh_mmcif_error_manage(struct sh_mmcif_host *host) { u32 state1, state2; int ret, timeout = 10000000; host->sd_error = 0; host->wait_int = 0; state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1); state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2); pr_debug("%s: ERR HOST_STS1 = %08x\n", DRIVER_NAME, state1); pr_debug("%s: ERR HOST_STS2 = %08x\n", DRIVER_NAME, state2); if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); while (1) { timeout--; if (timeout < 0) { pr_err(DRIVER_NAME": Forceed end of " \ "command sequence timeout err\n"); return -EIO; } if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) & STS1_CMDSEQ)) break; mdelay(1); } sh_mmcif_sync_reset(host); pr_debug(DRIVER_NAME": Forced end of command sequence\n"); return -EIO; } if (state2 & STS2_CRC_ERR) { pr_debug(DRIVER_NAME": Happened CRC error\n"); ret = -EIO; } else if (state2 & STS2_TIMEOUT_ERR) { pr_debug(DRIVER_NAME": Happened Timeout error\n"); ret = -ETIMEDOUT; } else { pr_debug(DRIVER_NAME": Happened End/Index error\n"); ret = -EIO; } return ret; }
static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) { struct sh_mmcif_host *host = dev_id; u32 state = 0; int err = 0; state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); if (state & INT_RBSYE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); } else if (state & INT_CRSPE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_CRSPE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE); } else if (state & INT_BUFREN) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFREN); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); } else if (state & INT_BUFWEN) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFWEN); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); } else if (state & INT_CMD12DRE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | INT_BUFRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); } else if (state & INT_BUFRE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); } else if (state & INT_DTRANE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); } else if (state & INT_CMD12RBE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12RBE | INT_CMD12CRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); } else if (state & INT_ERR_STS) { /* err interrupts */ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } else { pr_debug("%s: Not support int\n", DRIVER_NAME); sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } if (err) { host->sd_error = 1; pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state); } host->wait_int = 1; wake_up(&host->intr_wait); return IRQ_HANDLED; }
static void sh_mmcif_single_write(struct sh_mmcif_host *host, struct mmc_request *mrq) { host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & BLOCK_SIZE_MASK) + 3; host->wait_for = MMCIF_WAIT_FOR_WRITE; /* buf write enable */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); }
static void sh_mmcif_single_read(struct sh_mmcif_host *host, struct mmc_request *mrq) { host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & BLOCK_SIZE_MASK) + 3; host->wait_for = MMCIF_WAIT_FOR_READ; schedule_delayed_work(&host->timeout_work, host->timeout); /* buf read enable */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); }
static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) { u32 tmp; tmp = 0x010f0000 & sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL); sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON); sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29); /* byte swap on */ sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP); }
static void sh_mmcif_multi_write(struct sh_mmcif_host *host, struct mmc_request *mrq) { struct mmc_data *data = mrq->data; if (!data->sg_len || !data->sg->length) return; host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & BLOCK_SIZE_MASK; host->wait_for = MMCIF_WAIT_FOR_MWRITE; host->sg_idx = 0; host->sg_blkidx = 0; host->pio_ptr = sg_virt(data->sg); sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); }
static void sh_mmcif_multi_read(struct sh_mmcif_host *host, struct mmc_request *mrq) { struct mmc_data *data = mrq->data; if (!data->sg_len || !data->sg->length) return; host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & BLOCK_SIZE_MASK; host->wait_for = MMCIF_WAIT_FOR_MREAD; host->sg_idx = 0; host->sg_blkidx = 0; host->pio_ptr = sg_virt(data->sg); schedule_delayed_work(&host->timeout_work, host->timeout); sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); }
static bool sh_mmcif_read_block(struct sh_mmcif_host *host) { struct mmc_data *data = host->mrq->data; u32 *p = sg_virt(data->sg); int i; if (host->sd_error) { data->error = sh_mmcif_error_manage(host); return false; } for (i = 0; i < host->blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); /* buffer read end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); host->wait_for = MMCIF_WAIT_FOR_READ_END; return true; }
static bool sh_mmcif_mread_block(struct sh_mmcif_host *host) { struct mmc_data *data = host->mrq->data; u32 *p = host->pio_ptr; int i; if (host->sd_error) { data->error = sh_mmcif_error_manage(host); return false; } BUG_ON(!data->sg->length); for (i = 0; i < host->blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); if (!sh_mmcif_next_block(host, p)) return false; schedule_delayed_work(&host->timeout_work, host->timeout); sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); return true; }
static bool sh_mmcif_mread_block(struct sh_mmcif_host *host) { struct mmc_data *data = host->mrq->data; u32 *p = host->pio_ptr; int i; if (host->sd_error) { data->error = sh_mmcif_error_manage(host); dev_dbg(&host->pd->dev, "%s(): %d\n", __func__, data->error); return false; } BUG_ON(!data->sg->length); for (i = 0; i < host->blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); if (!sh_mmcif_next_block(host, p)) return false; sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); return true; }
static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, struct mmc_command *cmd) { cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP_CMD12); }
static int sh_mmcif_probe(struct platform_device *pdev) { int ret = 0, irq[2]; struct mmc_host *mmc; struct sh_mmcif_host *host; struct sh_mmcif_plat_data *pd = pdev->dev.platform_data; struct resource *res; void __iomem *reg; const char *name; irq[0] = platform_get_irq(pdev, 0); irq[1] = platform_get_irq(pdev, 1); if (irq[0] < 0) { dev_err(&pdev->dev, "Get irq error\n"); return -ENXIO; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "platform_get_resource error.\n"); return -ENXIO; } reg = ioremap(res->start, resource_size(res)); if (!reg) { dev_err(&pdev->dev, "ioremap error.\n"); return -ENOMEM; } mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; goto ealloch; } ret = mmc_of_parse(mmc); if (ret < 0) goto eofparse; host = mmc_priv(mmc); host->mmc = mmc; host->addr = reg; host->timeout = msecs_to_jiffies(10000); host->ccs_enable = !pd || !pd->ccs_unsupported; host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present; host->pd = pdev; spin_lock_init(&host->lock); mmc->ops = &sh_mmcif_ops; sh_mmcif_init_ocr(host); mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY; if (pd && pd->caps) mmc->caps |= pd->caps; mmc->max_segs = 32; mmc->max_blk_size = 512; mmc->max_req_size = PAGE_CACHE_SIZE * mmc->max_segs; mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size; mmc->max_seg_size = mmc->max_req_size; platform_set_drvdata(pdev, host); pm_runtime_enable(&pdev->dev); host->power = false; host->hclk = clk_get(&pdev->dev, NULL); if (IS_ERR(host->hclk)) { ret = PTR_ERR(host->hclk); dev_err(&pdev->dev, "cannot get clock: %d\n", ret); goto eclkget; } ret = sh_mmcif_clk_update(host); if (ret < 0) goto eclkupdate; ret = pm_runtime_resume(&pdev->dev); if (ret < 0) goto eresume; INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); sh_mmcif_sync_reset(host); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); name = irq[1] < 0 ? dev_name(&pdev->dev) : "sh_mmc:error"; ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, name, host); if (ret) { dev_err(&pdev->dev, "request_irq error (%s)\n", name); goto ereqirq0; } if (irq[1] >= 0) { ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); if (ret) { dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); goto ereqirq1; } } if (pd && pd->use_cd_gpio) { ret = mmc_gpio_request_cd(mmc, pd->cd_gpio, 0); if (ret < 0) goto erqcd; } mutex_init(&host->thread_lock); clk_disable_unprepare(host->hclk); ret = mmc_add_host(mmc); if (ret < 0) goto emmcaddh; dev_pm_qos_expose_latency_limit(&pdev->dev, 100); dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); dev_dbg(&pdev->dev, "chip ver H'%04x\n", sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); return ret; emmcaddh: erqcd: if (irq[1] >= 0) free_irq(irq[1], host); ereqirq1: free_irq(irq[0], host); ereqirq0: pm_runtime_suspend(&pdev->dev); eresume: clk_disable_unprepare(host->hclk); eclkupdate: clk_put(host->hclk); eclkget: pm_runtime_disable(&pdev->dev); eofparse: mmc_free_host(mmc); ealloch: iounmap(reg); return ret; }
static int __devinit sh_mmcif_probe(struct platform_device *pdev) { int ret = 0, irq[2]; struct mmc_host *mmc; struct sh_mmcif_host *host = NULL; struct sh_mmcif_plat_data *pd = NULL; struct resource *res; void __iomem *reg; char clk_name[8]; irq[0] = platform_get_irq(pdev, 0); irq[1] = platform_get_irq(pdev, 1); if (irq[0] < 0 || irq[1] < 0) { pr_err(DRIVER_NAME": Get irq error\n"); return -ENXIO; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "platform_get_resource error.\n"); return -ENXIO; } reg = ioremap(res->start, resource_size(res)); if (!reg) { dev_err(&pdev->dev, "ioremap error.\n"); return -ENOMEM; } pd = (struct sh_mmcif_plat_data *)(pdev->dev.platform_data); if (!pd) { dev_err(&pdev->dev, "sh_mmcif plat data error.\n"); ret = -ENXIO; goto clean_up; } mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; goto clean_up; } host = mmc_priv(mmc); host->mmc = mmc; host->addr = reg; host->timeout = 1000; snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); host->hclk = clk_get(&pdev->dev, clk_name); if (IS_ERR(host->hclk)) { dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); ret = PTR_ERR(host->hclk); goto clean_up1; } clk_enable(host->hclk); host->clk = clk_get_rate(host->hclk); host->pd = pdev; init_waitqueue_head(&host->intr_wait); mmc->ops = &sh_mmcif_ops; mmc->f_max = host->clk; /* close to 400KHz */ if (mmc->f_max < 51200000) mmc->f_min = mmc->f_max / 128; else if (mmc->f_max < 102400000) mmc->f_min = mmc->f_max / 256; else mmc->f_min = mmc->f_max / 512; if (pd->ocr) mmc->ocr_avail = pd->ocr; mmc->caps = MMC_CAP_MMC_HIGHSPEED; if (pd->caps) mmc->caps |= pd->caps; mmc->max_phys_segs = 128; mmc->max_hw_segs = 128; mmc->max_blk_size = 512; mmc->max_blk_count = 65535; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; sh_mmcif_sync_reset(host); platform_set_drvdata(pdev, host); mmc_add_host(mmc); ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host); if (ret) { pr_err(DRIVER_NAME": request_irq error (sh_mmc:error)\n"); goto clean_up2; } ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host); if (ret) { free_irq(irq[0], host); pr_err(DRIVER_NAME": request_irq error (sh_mmc:int)\n"); goto clean_up2; } sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); sh_mmcif_detect(host->mmc); pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION); pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME, sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); return ret; clean_up2: clk_disable(host->hclk); clean_up1: mmc_free_host(mmc); clean_up: if (reg) iounmap(reg); return ret; }
static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) { struct sh_mmcif_host *host = dev_id; u32 state; int err = 0; state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); if (state & INT_ERR_STS) { /* error interrupts - process first */ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } else if (state & INT_RBSYE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); } else if (state & INT_CRSPE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_CRSPE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE); } else if (state & INT_BUFREN) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFREN); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); } else if (state & INT_BUFWEN) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFWEN); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); } else if (state & INT_CMD12DRE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | INT_BUFRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); } else if (state & INT_BUFRE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); } else if (state & INT_DTRANE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | INT_DTRANE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); } else if (state & INT_CMD12RBE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12RBE | INT_CMD12CRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); } else { dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state); sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } if (err) { host->sd_error = true; dev_dbg(&host->pd->dev, "int err state = %08x\n", state); } if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { if (!host->dma_active) return IRQ_WAKE_THREAD; else if (host->sd_error) mmcif_dma_complete(host); } else { dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state); } return IRQ_HANDLED; }