diff options
Diffstat (limited to 'arch/arm/mach-davinci/aemif.c')
| -rw-r--r-- | arch/arm/mach-davinci/aemif.c | 107 | 
1 files changed, 96 insertions, 11 deletions
diff --git a/arch/arm/mach-davinci/aemif.c b/arch/arm/mach-davinci/aemif.c index f091a9010c2..ff8b7e76b6e 100644 --- a/arch/arm/mach-davinci/aemif.c +++ b/arch/arm/mach-davinci/aemif.c @@ -16,6 +16,7 @@  #include <linux/time.h>  #include <linux/platform_data/mtd-davinci-aemif.h> +#include <linux/platform_data/mtd-davinci.h>  /* Timing value configuration */ @@ -43,6 +44,17 @@  				WSTROBE(WSTROBE_MAX) | \  				WSETUP(WSETUP_MAX)) +static inline unsigned int davinci_aemif_readl(void __iomem *base, int offset) +{ +	return readl_relaxed(base + offset); +} + +static inline void davinci_aemif_writel(void __iomem *base, +					int offset, unsigned long value) +{ +	writel_relaxed(value, base + offset); +} +  /*   * aemif_calc_rate - calculate timing data.   * @wanted: The cycle time needed in nanoseconds. @@ -76,6 +88,7 @@ static int aemif_calc_rate(int wanted, unsigned long clk, int max)   * @t: timing values to be progammed   * @base: The virtual base address of the AEMIF interface   * @cs: chip-select to program the timing values for + * @clkrate: the AEMIF clkrate   *   * This function programs the given timing values (in real clock) into the   * AEMIF registers taking the AEMIF clock into account. @@ -86,24 +99,17 @@ static int aemif_calc_rate(int wanted, unsigned long clk, int max)   *   * Returns 0 on success, else negative errno.   */ -int davinci_aemif_setup_timing(struct davinci_aemif_timing *t, -					void __iomem *base, unsigned cs) +static int davinci_aemif_setup_timing(struct davinci_aemif_timing *t, +					void __iomem *base, unsigned cs, +					unsigned long clkrate)  {  	unsigned set, val;  	int 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); @@ -130,4 +136,83 @@ int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,  	return 0;  } -EXPORT_SYMBOL(davinci_aemif_setup_timing); + +/** + * davinci_aemif_setup - setup AEMIF interface by davinci_nand_pdata + * @pdev - link to platform device to setup settings for + * + * 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. + */ +int davinci_aemif_setup(struct platform_device *pdev) +{ +	struct davinci_nand_pdata *pdata = dev_get_platdata(&pdev->dev); +	uint32_t val; +	unsigned long clkrate; +	struct resource	*res; +	void __iomem *base; +	struct clk *clk; +	int ret = 0; + +	clk = clk_get(&pdev->dev, "aemif"); +	if (IS_ERR(clk)) { +		ret = PTR_ERR(clk); +		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret); +		return ret; +	} + +	ret = clk_prepare_enable(clk); +	if (ret < 0) { +		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n", +			ret); +		goto err_put; +	} + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +	if (!res) { +		dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); +		ret = -ENOMEM; +		goto err; +	} + +	base = ioremap(res->start, resource_size(res)); +	if (!base) { +		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res); +		ret = -ENOMEM; +		goto err; +	} + +	/* +	 * Setup Async configuration register in case we did not boot +	 * from NAND and so bootloader did not bother to set it up. +	 */ +	val = davinci_aemif_readl(base, A1CR_OFFSET + pdev->id * 4); +	/* +	 * Extended Wait is not valid and Select Strobe mode is not +	 * used +	 */ +	val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK); +	if (pdata->options & NAND_BUSWIDTH_16) +		val |= 0x1; + +	davinci_aemif_writel(base, A1CR_OFFSET + pdev->id * 4, val); + +	clkrate = clk_get_rate(clk); + +	if (pdata->timing) +		ret = davinci_aemif_setup_timing(pdata->timing, base, pdev->id, +						 clkrate); + +	if (ret < 0) +		dev_dbg(&pdev->dev, "NAND timing values setup fail\n"); + +	iounmap(base); +err: +	clk_disable_unprepare(clk); +err_put: +	clk_put(clk); +	return ret; +}  | 
