diff options
Diffstat (limited to 'arch/arm/mach-ep93xx/clock.c')
| -rw-r--r-- | arch/arm/mach-ep93xx/clock.c | 123 | 
1 files changed, 88 insertions, 35 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index e8ebeaea6c4..6c4c1633ed1 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -21,15 +21,50 @@  #include <asm/div64.h>  #include <mach/hardware.h> + +/* + * The EP93xx has two external crystal oscillators.  To generate the + * required high-frequency clocks, the processor uses two phase-locked- + * loops (PLLs) to multiply the incoming external clock signal to much + * higher frequencies that are then divided down by programmable dividers + * to produce the needed clocks.  The PLLs operate independently of one + * another. + */ +#define EP93XX_EXT_CLK_RATE	14745600 +#define EP93XX_EXT_RTC_RATE	32768 + +  struct clk {  	unsigned long	rate;  	int		users; +	int		sw_locked;  	u32		enable_reg;  	u32		enable_mask; + +	unsigned long	(*get_rate)(struct clk *clk);  }; -static struct clk clk_uart = { -	.rate		= 14745600, + +static unsigned long get_uart_rate(struct clk *clk); + + +static struct clk clk_uart1 = { +	.sw_locked	= 1, +	.enable_reg	= EP93XX_SYSCON_DEVICE_CONFIG, +	.enable_mask	= EP93XX_SYSCON_DEVICE_CONFIG_U1EN, +	.get_rate	= get_uart_rate, +}; +static struct clk clk_uart2 = { +	.sw_locked	= 1, +	.enable_reg	= EP93XX_SYSCON_DEVICE_CONFIG, +	.enable_mask	= EP93XX_SYSCON_DEVICE_CONFIG_U2EN, +	.get_rate	= get_uart_rate, +}; +static struct clk clk_uart3 = { +	.sw_locked	= 1, +	.enable_reg	= EP93XX_SYSCON_DEVICE_CONFIG, +	.enable_mask	= EP93XX_SYSCON_DEVICE_CONFIG_U3EN, +	.get_rate	= get_uart_rate,  };  static struct clk clk_pll1;  static struct clk clk_f; @@ -37,73 +72,73 @@ static struct clk clk_h;  static struct clk clk_p;  static struct clk clk_pll2;  static struct clk clk_usb_host = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= EP93XX_SYSCON_CLOCK_USH_EN, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_USH_EN,  };  /* DMA Clocks */  static struct clk clk_m2p0 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x00020000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P0,  };  static struct clk clk_m2p1 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x00010000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P1,  };  static struct clk clk_m2p2 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x00080000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P2,  };  static struct clk clk_m2p3 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x00040000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P3,  };  static struct clk clk_m2p4 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x00200000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P4,  };  static struct clk clk_m2p5 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x00100000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P5,  };  static struct clk clk_m2p6 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x00800000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P6,  };  static struct clk clk_m2p7 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x00400000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P7,  };  static struct clk clk_m2p8 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x02000000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P8,  };  static struct clk clk_m2p9 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x01000000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P9,  };  static struct clk clk_m2m0 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x04000000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2M0,  };  static struct clk clk_m2m1 = { -	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL, -	.enable_mask	= 0x08000000, +	.enable_reg	= EP93XX_SYSCON_PWRCNT, +	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2M1,  };  #define INIT_CK(dev,con,ck)					\  	{ .dev_id = dev, .con_id = con, .clk = ck }  static struct clk_lookup clocks[] = { -	INIT_CK("apb:uart1", NULL, &clk_uart), -	INIT_CK("apb:uart2", NULL, &clk_uart), -	INIT_CK("apb:uart3", NULL, &clk_uart), +	INIT_CK("apb:uart1", NULL, &clk_uart1), +	INIT_CK("apb:uart2", NULL, &clk_uart2), +	INIT_CK("apb:uart3", NULL, &clk_uart3),  	INIT_CK(NULL, "pll1", &clk_pll1),  	INIT_CK(NULL, "fclk", &clk_f),  	INIT_CK(NULL, "hclk", &clk_h),  	INIT_CK(NULL, "pclk", &clk_p),  	INIT_CK(NULL, "pll2", &clk_pll2), -	INIT_CK(NULL, "usb_host", &clk_usb_host), +	INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),  	INIT_CK(NULL, "m2p0", &clk_m2p0),  	INIT_CK(NULL, "m2p1", &clk_m2p1),  	INIT_CK(NULL, "m2p2", &clk_m2p2), @@ -125,6 +160,8 @@ int clk_enable(struct clk *clk)  		u32 value;  		value = __raw_readl(clk->enable_reg); +		if (clk->sw_locked) +			__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);  		__raw_writel(value | clk->enable_mask, clk->enable_reg);  	} @@ -138,13 +175,29 @@ void clk_disable(struct clk *clk)  		u32 value;  		value = __raw_readl(clk->enable_reg); +		if (clk->sw_locked) +			__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);  		__raw_writel(value & ~clk->enable_mask, clk->enable_reg);  	}  }  EXPORT_SYMBOL(clk_disable); +static unsigned long get_uart_rate(struct clk *clk) +{ +	u32 value; + +	value = __raw_readl(EP93XX_SYSCON_PWRCNT); +	if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD) +		return EP93XX_EXT_CLK_RATE; +	else +		return EP93XX_EXT_CLK_RATE / 2; +} +  unsigned long clk_get_rate(struct clk *clk)  { +	if (clk->get_rate) +		return clk->get_rate(clk); +  	return clk->rate;  }  EXPORT_SYMBOL(clk_get_rate); @@ -162,7 +215,7 @@ static unsigned long calc_pll_rate(u32 config_word)  	unsigned long long rate;  	int i; -	rate = 14745600; +	rate = EP93XX_EXT_CLK_RATE;  	rate *= ((config_word >> 11) & 0x1f) + 1;		/* X1FBD */  	rate *= ((config_word >> 5) & 0x3f) + 1;		/* X2FBD */  	do_div(rate, (config_word & 0x1f) + 1);			/* X2IPD */ @@ -195,7 +248,7 @@ static int __init ep93xx_clock_init(void)  	value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);  	if (!(value & 0x00800000)) {			/* PLL1 bypassed?  */ -		clk_pll1.rate = 14745600; +		clk_pll1.rate = EP93XX_EXT_CLK_RATE;  	} else {  		clk_pll1.rate = calc_pll_rate(value);  	} @@ -206,7 +259,7 @@ static int __init ep93xx_clock_init(void)  	value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);  	if (!(value & 0x00080000)) {			/* PLL2 bypassed?  */ -		clk_pll2.rate = 14745600; +		clk_pll2.rate = EP93XX_EXT_CLK_RATE;  	} else if (value & 0x00040000) {		/* PLL2 enabled?  */  		clk_pll2.rate = calc_pll_rate(value);  	} else {  |