/** * sdhci_s3c_set_clock - callback on clock change * @host: The SDHCI host being changed * @clock: The clock rate being requested. * * When the card's clock is going to be changed, look at the new frequency * and find the best clock source to go with it. */ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned int best = UINT_MAX; unsigned int delta; int best_src = 0; int src; u32 ctrl; /* don't bother if the clock is going off. */ if (clock == 0) return; for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, clock); if (delta < best) { best = delta; best_src = src; } } dev_dbg(&ourhost->pdev->dev, "selected source %d, clock %d, delta %d\n", best_src, clock, best); /* select the new clock source */ if (ourhost->cur_clk != best_src) { struct clk *clk = ourhost->clk_bus[best_src]; /* turn clock off to card before changing clock source */ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); ourhost->cur_clk = best_src; host->max_clk = clk_get_rate(clk); ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } /* reprogram default hardware configuration */ writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, host->ioaddr + S3C64XX_SDHCI_CONTROL4); ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); ctrl |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR | S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK | S3C_SDHCI_CTRL2_ENFBCLKRX | S3C_SDHCI_CTRL2_DFCNT_NONE | S3C_SDHCI_CTRL2_ENCLKOUTHOLD); writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); /* reconfigure the controller for new clock rate */ ctrl = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0); if (clock < 25 * 1000000) ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2); writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3); }
/** * sdhci_s3c_set_clock - callback on clock change * @host: The SDHCI host being changed * @clock: The clock rate being requested. * * When the card's clock is going to be changed, look at the new frequency * and find the best clock source to go with it. */ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned int best = UINT_MAX; unsigned int delta; int best_src = 0; int src; u32 ctrl; /* don't bother if the clock is going off. */ if (clock == 0) return; for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, clock); if (delta < best) { best = delta; best_src = src; } } dev_dbg(&ourhost->pdev->dev, "selected source %d, clock %d, delta %d\n", best_src, clock, best); /* select the new clock source */ if (ourhost->cur_clk != best_src) { struct clk *clk = ourhost->clk_bus[best_src]; /* turn clock off to card before changing clock source */ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); ourhost->cur_clk = best_src; host->max_clk = clk_get_rate(clk); ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } /* reconfigure the hardware for new clock rate */ { struct mmc_ios ios; ios.clock = clock; if (ourhost->pdata->cfg_card) (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, &ios, NULL); #ifdef CONFIG_MACH_MIDAS /* call cfg_gpio with 4bit data bus */ if (ourhost->pdata->cfg_gpio) ourhost->pdata->cfg_gpio(ourhost->pdev, 4); #endif } }
static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned int best = UINT_MAX; unsigned int delta; int best_src = 0; int src; u32 ctrl; if (clock == 0) return; for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, clock); if (delta < best) { best = delta; best_src = src; } } dev_dbg(&ourhost->pdev->dev, "selected source %d, clock %d, delta %d\n", best_src, clock, best); if (ourhost->cur_clk != best_src) { struct clk *clk = ourhost->clk_bus[best_src]; writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); ourhost->cur_clk = best_src; host->max_clk = clk_get_rate(clk); host->timeout_clk = sdhci_s3c_get_timeout_clk(host); ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } { struct mmc_ios ios; ios.clock = clock; if (ourhost->pdata->cfg_card) (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, &ios, NULL); } }
/** * sdhci_s3c_get_min_clock - callback to get minimal supported clock value * @host: The SDHCI host being queried * * To init mmc host properly a minimal clock value is needed. For high system * bus clock's values the standard formula gives values out of allowed range. * The clock still can be set to lower values, if clock source other then * system bus is selected. */ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned int delta, min = UINT_MAX; int src; for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, 0); if (delta == UINT_MAX) continue; /* delta is a negative value in this case */ if (-delta < min) min = -delta; } return min; }
/** * sdhci_s3c_set_clock - callback on clock change * @host: The SDHCI host being changed * @clock: The clock rate being requested. * * When the card's clock is going to be changed, look at the new frequency * and find the best clock source to go with it. */ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned int best = UINT_MAX; unsigned int delta; int best_src = 0; int src; u32 ctrl; /* don't bother if the clock is going off. */ if (clock == 0) return; for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, clock); if (delta < best) { best = delta; best_src = src; } } dev_dbg(&ourhost->pdev->dev, "selected source %d, clock %d, delta %d\n", best_src, clock, best); //printk("%s selected source %d, clock %d, delta %d\n", mmc_hostname(host->mmc), best_src, clock, best); /* select the new clock source */ if (ourhost->cur_clk != best_src) { struct clk *clk = ourhost->clk_bus[best_src]; /* turn clock off to card before changing clock source */ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); ourhost->cur_clk = best_src; host->max_clk = clk_get_rate(clk); host->timeout_clk = sdhci_s3c_get_timeout_clk(host); ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } }
/** * sdhci_s3c_get_min_clock - callback to get minimal supported clock value * @host: The SDHCI host being queried * * To init mmc host properly a minimal clock value is needed. For high system * bus clock's values the standard formula gives values out of allowed range. * The clock still can be set to lower values, if clock source other then * system bus is selected. */ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned int delta, min = UINT_MAX; int src; if(host->quirks & SDHCI_QUIRK_BROKEN_CLOCK_DIVIDER) return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000); for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, 0); if (delta == UINT_MAX) continue; /* delta is a negative value in this case */ if (-delta < min) min = -delta; } return min; }
static void sdhci_s3c_change_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned int best = UINT_MAX; unsigned int delta; int best_src = 0; int src; u32 ctrl; for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, clock); if (delta < best) { best = delta; best_src = src; } } /* turn clock off to card before changing clock source */ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); /* select the new clock source */ if (ourhost->cur_clk != best_src) { struct clk *clk = ourhost->clk_bus[best_src]; ourhost->cur_clk = best_src; host->max_clk = clk_get_rate(clk); host->timeout_clk = host->max_clk / 1000000; ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } sdhci_change_clock(host, clock); }
/** * sdhci_s3c_set_clock - callback on clock change * @host: The SDHCI host being changed * @clock: The clock rate being requested. * * When the card's clock is going to be changed, look at the new frequency * and find the best clock source to go with it. */ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); unsigned int best = UINT_MAX; unsigned int delta; int best_src = 0; int src; u32 ctrl; unsigned int timeout; /* don't bother if the clock is going off. */ if (clock == 0) { writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); host->clock = clock; return; } for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, clock); if (delta < best) { best = delta; best_src = src; } } dev_dbg(&ourhost->pdev->dev, "selected source %d, clock %d, delta %d\n", best_src, clock, best); /* select the new clock source */ if (ourhost->cur_clk != best_src) { struct clk *clk = ourhost->clk_bus[best_src]; /* turn clock off to card before changing clock source */ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); ourhost->cur_clk = best_src; host->max_clk = clk_get_rate(clk); ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } /* reconfigure the hardware for new clock rate */ { struct mmc_ios ios; ios.clock = clock; if (ourhost->pdata->cfg_card) (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, &ios, NULL); } if(host->quirks & SDHCI_QUIRK_BROKEN_CLOCK_DIVIDER) { writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); writew(SDHCI_CLOCK_INT_EN, host->ioaddr + SDHCI_CLOCK_CONTROL); /* Wait max 20 ms */ timeout = 20; while (!((sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { printk(KERN_ERR "%s: Internal clock never " "stabilised.\n", mmc_hostname(host->mmc)); return; } timeout--; mdelay(1); } writew(SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN, host->ioaddr + SDHCI_CLOCK_CONTROL); host->clock = clock; } }
static void sdhci_s3c_set_clock_src(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); struct clk *clk_sclk_mmc = ourhost->clk_bus[0];//lisw sd : for different clk source structure struct clksrc_clk *clksrc_parent = to_clksrc(clk_sclk_mmc->parent); unsigned int best = UINT_MAX; unsigned int delta; int best_src = 0; int src; u32 ctrl; /* don't bother if the clock is going off. */ if (clock == 0) return; if(MAX_BUS_CLK==1){ for (src = 6; src < clksrc_parent->sources->nr_sources; src++) {//lisw ms : set 6 as firsrt selection because XXTI 24Mhz is not stable delta = sdhci_s3c_consider_clock(ourhost, src, clock); if (delta < best) { best = delta; best_src = src; } } } else return; //printk("selected source %d, clock %d, delta %d\n", // best_src, clock, best); /* select the new clock source */ if (ourhost->cur_clk != best_src) { struct clk *clk = clksrc_parent->sources->sources[best_src]; /* turn clock off to card before changing clock source */ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); ourhost->cur_clk = best_src; host->max_clk = clk_get_rate(clk); // ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); // ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; // ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; // writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); //***use base clock select funtion in CMU instread in SD host controller***// if (clk_set_parent(clk_sclk_mmc->parent, clk)) printk("Unable to set parent %s of clock %s.\n", clk->name, clksrc_parent->clk.name); clk_sclk_mmc->parent->parent = clk; } // s3c_setrate_clksrc_two_div(clk_sclk_mmc,clock); /* reconfigure the hardware for new clock rate */ { struct mmc_ios ios; ios.clock = clock; if (ourhost->pdata->cfg_card) (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, &ios, NULL); } }