static int mmc_config_clock(struct mmc *mmc, unsigned clk) { struct sunxi_mmc_host* mmchost = (struct sunxi_mmc_host *)mmc->priv; unsigned rval = readl(&mmchost->reg->clkcr); // unsigned int clkdiv = 0; /* Disable Clock */ rval &= ~(1 << 16); writel(rval, &mmchost->reg->clkcr); if(mmc_update_clk(mmc)){ mmcinfo("mmc %d disable clock failed\n",mmchost ->mmc_no); return -1; } // clkdiv = mmchost->mclk/clk/2; //disable mclk first writel(0,mmchost->mclkbase); mmcdbg("mmc %d mclkbase %x\n",mmchost ->mmc_no,readl(mmchost->mclkbase)); if (clk <=400000) { mmchost->mclk = 400000; writel(0x0002000f, mmchost->mclkbase); mmcdbg("mmc %d mclkbase%x\n",mmchost ->mmc_no,readl(mmchost->mclkbase)); } else { mmchost->mclk = 12000000; writel(0x00000001, mmchost->mclkbase); mmcdbg("mmc %d mclkbase%x\n",mmchost ->mmc_no,readl(mmchost->mclkbase)); } //re-enable mclk writel(readl(mmchost->mclkbase)|(1<<31),mmchost->mclkbase); mmcdbg("mmc %d mclkbase%x\n",mmchost ->mmc_no,readl(mmchost->mclkbase)); /* * CLKCREG[7:0]: divider * CLKCREG[16]: on/off * CLKCREG[17]: power save */ /* Change Divider Factor */ rval &= ~(0xFF); writel(rval, &mmchost->reg->clkcr); if(mmc_update_clk(mmc)){ mmcinfo("mmc %d Change Divider Factor failed\n",mmchost ->mmc_no); return -1; } /* Re-enable Clock */ rval |= (3 << 16); writel(rval, &mmchost->reg->clkcr); if(mmc_update_clk(mmc)){ mmcinfo("mmc %d re-enable clock failed\n",mmchost ->mmc_no); return -1; } return 0; }
static int mmc_update_phase(struct mmc *mmc) { struct sunxi_mmc_host* mmchost = (struct sunxi_mmc_host *)mmc->priv; if (mmchost->timing_mode == SUNXI_MMC_TIMING_MODE_1) { MMCDBG("mmc re-update_phase\n"); return mmc_update_clk(mmchost); } return 0; }