int davinci_aemif_setup_timing(struct davinci_aemif_timing *t, void __iomem *base, unsigned cs) { unsigned set, val; unsigned ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup; unsigned offset = A1CR_OFFSET + cs * 4; struct clk *aemif_clk; unsigned long clkrate; if (!t) return 0; /* Nothing to do */ aemif_clk = clk_get(NULL, "aemif"); if (IS_ERR(aemif_clk)) return PTR_ERR(aemif_clk); clkrate = clk_get_rate(aemif_clk); clkrate /= 1000; /* turn clock into kHz for ease of use */ ta = aemif_calc_rate(t->ta, clkrate, TA_MAX); rhold = aemif_calc_rate(t->rhold, clkrate, RHOLD_MAX); rstrobe = aemif_calc_rate(t->rstrobe, clkrate, RSTROBE_MAX); rsetup = aemif_calc_rate(t->rsetup, clkrate, RSETUP_MAX); whold = aemif_calc_rate(t->whold, clkrate, WHOLD_MAX); wstrobe = aemif_calc_rate(t->wstrobe, clkrate, WSTROBE_MAX); wsetup = aemif_calc_rate(t->wsetup, clkrate, WSETUP_MAX); if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 || whold < 0 || wstrobe < 0 || wsetup < 0) { pr_err("%s: cannot get suitable timings\n", __func__); return -EINVAL; } set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) | WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup); val = __raw_readl(base + offset); val &= ~TIMING_MASK; val |= set; __raw_writel(val, base + offset); return 0; }
/** * aemif_config_abus - configure async bus parameters * @pdev: platform device to configure for * @csnum: aemif chip select number * * This function programs the given timing values (in real clock) into the * AEMIF registers taking the AEMIF clock into account. * * This function does not use any locking while programming the AEMIF * because it is expected that there is only one user of a given * chip-select. * * Returns 0 on success, else negative errno. */ static int aemif_config_abus(struct platform_device *pdev, int csnum) { struct aemif_device *aemif = platform_get_drvdata(pdev); struct aemif_cs_data *data = &aemif->cs_data[csnum]; int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup; unsigned long clk_rate = aemif->clk_rate; unsigned offset; u32 set, val; offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4; ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX); rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX); rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX); rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX); whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX); wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX); wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX); if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 || whold < 0 || wstrobe < 0 || wsetup < 0) { dev_err(&pdev->dev, "%s: cannot get suitable timings\n", __func__); return -EINVAL; } set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) | WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup); set |= (data->asize & ACR_ASIZE_MASK); if (data->enable_ew) set |= ACR_EW_MASK; if (data->enable_ss) set |= ACR_SS_MASK; val = readl(aemif->base + offset); val &= ~CONFIG_MASK; val |= set; writel(val, aemif->base + offset); return 0; }