/********************************************************************* * Method : * Description: * Parameters : * * Returns : * Note : *********************************************************************/ s32 sdxc_update_clk(struct awsmc_host* smc_host, u32 sclk, u32 cclk) { u32 rval; u32 clk_div; u32 real_clk; //caculate new clock divider clk_div = (sclk / cclk)>>1; real_clk = clk_div ? sclk/(clk_div<<1) : sclk; while (real_clk > cclk) { clk_div++; real_clk = sclk/(clk_div<<1); } awsmc_dbg("sdc %d change clock over, src_clk %d, req_clk %d, real_clk %d, div %d\n", smc_host->pdev->id, sclk, cclk, real_clk, clk_div); //update new clock //disable clock rval = sdc_read(SDXC_REG_CLKCR) & (~SDXC_CardClkOn) & (~SDXC_LowPowerOn); sdc_write(SDXC_REG_CLKCR, rval); if (-1 == sdxc_program_clk(smc_host)) { awsmc_dbg_err("clock program failed in step 1\n"); return -1; } //update divider rval = sdc_read(SDXC_REG_CLKCR); rval &= ~0xff; rval |= clk_div & 0xff; sdc_write(SDXC_REG_CLKCR, rval); if (-1 == sdxc_program_clk(smc_host)) { awsmc_dbg_err("clock program failed in step 2\n"); return -1; } //re-enable clock rval = sdc_read(SDXC_REG_CLKCR) | SDXC_CardClkOn ;//| SDXC_LowPowerOn; sdc_write(SDXC_REG_CLKCR, rval); if (-1 == sdxc_program_clk(smc_host)) { awsmc_dbg_err("clock program failed in step 3\n"); return -1; } smc_host->real_cclk = real_clk; return real_clk; }
static int sunximmc_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct mmc_host *mmc = platform_get_drvdata(pdev); int ret = 0; if (mmc) { struct sunxi_mmc_host *smc_host = mmc_priv(mmc); if (smc_host->power_on) { /* resume pins to correct status */ sunximmc_resume_pins(smc_host); /* enable mmc hclk */ if (mmc->card && mmc->card->type!=MMC_TYPE_SDIO) clk_enable(smc_host->hclk); /* enable mmc mclk */ clk_enable(smc_host->mclk); /* restore registers */ if (mmc->card && mmc->card->type!=MMC_TYPE_SDIO) sdxc_regs_restore(smc_host); sdxc_program_clk(smc_host); /* enable irq */ enable_irq(smc_host->irq); } if (mmc->card && (mmc->card->type!=MMC_TYPE_SDIO || mmc_pm_io_shd_suspend_host())) ret = mmc_resume_host(mmc); } SMC_DBG("smc %d resume\n", pdev->id); return ret; }
/********************************************************************* * Method : * Description: * Parameters : * * Returns : * Note : *********************************************************************/ s32 sdxc_request_done(struct awsmc_host* smc_host) { struct mmc_request* req = smc_host->mrq; u32 temp; s32 ret = 0; if (smc_host->int_sum & SDXC_IntErrBit) { awsmc_dbg_err("smc %d err, cmd %d, %s%s%s%s%s%s%s%s%s%s !!\n", smc_host->pdev->id, req->cmd->opcode, smc_host->int_sum & SDXC_RespErr ? " RE" : "", smc_host->int_sum & SDXC_RespCRCErr ? " RCE" : "", smc_host->int_sum & SDXC_DataCRCErr ? " DCE" : "", smc_host->int_sum & SDXC_RespTimeout ? " RTO" : "", smc_host->int_sum & SDXC_DataTimeout ? " DTO" : "", smc_host->int_sum & SDXC_DataStarve ? " DS" : "", smc_host->int_sum & SDXC_FIFORunErr ? " FE" : "", smc_host->int_sum & SDXC_HardWLocked ? " HL" : "", smc_host->int_sum & SDXC_StartBitErr ? " SBE" : "", smc_host->int_sum & SDXC_EndBitErr ? " EBE" : "" ); if (req->data) { awsmc_dbg_err("In data %s operation\n", req->data->flags & MMC_DATA_WRITE ? "write" : "read"); } ret = -1; goto _out_; } if (req->cmd) { if (req->cmd->flags & MMC_RSP_136) { req->cmd->resp[0] = sdc_read(SDXC_REG_RESP3); req->cmd->resp[1] = sdc_read(SDXC_REG_RESP2); req->cmd->resp[2] = sdc_read(SDXC_REG_RESP1); req->cmd->resp[3] = sdc_read(SDXC_REG_RESP0); } else { req->cmd->resp[0] = sdc_read(SDXC_REG_RESP0); } } _out_: if (req->data) { if (!(req->data->flags & MMC_DATA_WRITE) && (sdc_read(SDXC_REG_STAS) & SDXC_DataFSMBusy)) { printk("data fsm busy\n"); } if (smc_host->dodma) { smc_host->dma_done = 0; sdc_write(SDXC_REG_IDST, 0x337); sdc_write(SDXC_REG_IDIE, 0); sdxc_idma_off(smc_host); sdxc_dma_disable(smc_host); } sdxc_fifo_reset(smc_host); } temp = sdc_read(SDXC_REG_STAS); if ((temp & SDXC_DataFSMBusy) || (smc_host->int_sum & (SDXC_RespErr | SDXC_HardWLocked | SDXC_RespTimeout))) { awsmc_dbg("sdc %d abnormal status: %s %s\n", smc_host->pdev->id, temp & SDXC_DataFSMBusy ? "DataFSMBusy" : "", smc_host->int_sum & SDXC_HardWLocked ? "HardWLocked" : ""); sdxc_reset(smc_host); sdxc_program_clk(smc_host); } sdc_write(SDXC_REG_RINTR, 0xffff); sdxc_clear_imask(smc_host); //re-enable card detect debounce if (smc_host->cd_gpio == CARD_DETECT_BY_DATA3) { sdxc_cd_debounce_on(smc_host); } awsmc_dbg("smc %d done, resp %08x %08x %08x %08x\n", smc_host->pdev->id, req->cmd->resp[0], req->cmd->resp[1], req->cmd->resp[2], req->cmd->resp[3]); if (req->data && req->data->stop && (smc_host->int_sum & SDXC_IntErrBit)) { awsmc_msg("found data error, need to send stop command !!\n"); sdxc_send_manual_stop(smc_host, req); } if ((smc_host->pdev->id==3) && req->data && (req->data->flags & MMC_DATA_WRITE) && !(smc_host->int_sum & SDXC_IntErrBit)) { u32 ready = 0; // u32 i = 0; do { // awsmc_msg("smc %d check ready %d \r", smc_host->pdev->id, i++); ready = sdxc_check_r1_ready(smc_host); } while (!ready); // awsmc_msg("\n"); } return ret; }
static void sunximmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct sunxi_mmc_host *smc_host = mmc_priv(mmc); s32 ret = -1; /* Set the power state */ switch (ios->power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: if (!smc_host->power_on) { SMC_MSG("mmc %d power on !!\n", smc_host->pdev->id); /* resume pins to correct status */ sunximmc_resume_pins(smc_host); /* enable mmc hclk */ clk_enable(smc_host->hclk); /* enable mmc mclk */ clk_enable(smc_host->mclk); /* restore registers */ sdxc_regs_restore(smc_host); sdxc_program_clk(smc_host); /* enable irq */ enable_irq(smc_host->irq); smc_host->power_on = 1; } break; case MMC_POWER_OFF: if (smc_host->power_on) { SMC_MSG("mmc %d power off !!\n", smc_host->pdev->id); /* disable irq */ disable_irq(smc_host->irq); /* backup registers */ sdxc_regs_save(smc_host); /* disable mmc mclk */ clk_disable(smc_host->mclk); /* disable mmc hclk */ clk_disable(smc_host->hclk); /* suspend pins to save power */ sunximmc_suspend_pins(smc_host); smc_host->power_on = 0; smc_host->ferror = 0; } default: break; } /* set clock */ if (smc_host->power_on) { /* set clock */ if (ios->clock) { smc_host->cclk = ios->clock; ret = sdxc_update_clk(smc_host, smc_host->mod_clk, smc_host->cclk); if (ret == -1) { SMC_ERR("Fatal error, please check your pin configuration.\n"); smc_host->ferror = 1; } if ((ios->power_mode == MMC_POWER_ON) || (ios->power_mode == MMC_POWER_UP)) { SMC_DBG("running at %dkHz (requested: %dkHz).\n", smc_host->real_cclk/1000, ios->clock/1000); } else { SMC_DBG("powered down.\n"); } } /* set bus width */ if (smc_host->bus_width != (1<<ios->bus_width)) { sdxc_set_buswidth(smc_host, 1<<ios->bus_width); smc_host->bus_width = 1<<ios->bus_width; } } }