Ejemplo n.º 1
0
/*********************************************************************
* 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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
/*********************************************************************
* 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;
}
Ejemplo n.º 4
0
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;
        }
    }
}