| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * arch/arm/mach-pnx4008/clock.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Clock control driver for PNX4008 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com> | 
					
						
							|  |  |  |  * Generic clock management functions are partially based on: | 
					
						
							|  |  |  |  *  linux/arch/arm/mach-omap/clock.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under | 
					
						
							|  |  |  |  * the terms of the GNU General Public License version 2. This program | 
					
						
							|  |  |  |  * is licensed "as is" without any warranty of any kind, whether express | 
					
						
							|  |  |  |  * or implied. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/list.h>
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/device.h>
 | 
					
						
							|  |  |  | #include <linux/err.h>
 | 
					
						
							|  |  |  | #include <linux/delay.h>
 | 
					
						
							| 
									
										
										
										
											2008-09-06 12:10:45 +01:00
										 |  |  | #include <linux/io.h>
 | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 10:32:41 +00:00
										 |  |  | #include <asm/clkdev.h>
 | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 10:32:41 +00:00
										 |  |  | #include <mach/hardware.h>
 | 
					
						
							| 
									
										
										
										
											2008-08-05 16:14:15 +01:00
										 |  |  | #include <mach/clock.h>
 | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | #include "clock.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*forward declaration*/ | 
					
						
							|  |  |  | static struct clk per_ck; | 
					
						
							|  |  |  | static struct clk hclk_ck; | 
					
						
							|  |  |  | static struct clk ck_1MHz; | 
					
						
							|  |  |  | static struct clk ck_13MHz; | 
					
						
							|  |  |  | static struct clk ck_pll1; | 
					
						
							|  |  |  | static int local_set_rate(struct clk *clk, u32 rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void clock_lock(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	local_irq_disable(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void clock_unlock(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	local_irq_enable(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void propagate_rate(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct clk *tmp_clk; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp_clk = clk; | 
					
						
							|  |  |  | 	while (tmp_clk->propagate_next) { | 
					
						
							|  |  |  | 		tmp_clk = tmp_clk->propagate_next; | 
					
						
							|  |  |  | 		local_set_rate(tmp_clk, tmp_clk->user_rate); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 11:28:59 +00:00
										 |  |  | static void clk_reg_disable(struct clk *clk) | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (clk->enable_reg) | 
					
						
							|  |  |  | 		__raw_writel(__raw_readl(clk->enable_reg) & | 
					
						
							|  |  |  | 			     ~(1 << clk->enable_shift), clk->enable_reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 11:28:59 +00:00
										 |  |  | static int clk_reg_enable(struct clk *clk) | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (clk->enable_reg) | 
					
						
							|  |  |  | 		__raw_writel(__raw_readl(clk->enable_reg) | | 
					
						
							|  |  |  | 			     (1 << clk->enable_shift), clk->enable_reg); | 
					
						
							| 
									
										
										
										
											2009-11-20 11:28:59 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void clk_reg_disable1(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (clk->enable_reg1) | 
					
						
							|  |  |  | 		__raw_writel(__raw_readl(clk->enable_reg1) & | 
					
						
							|  |  |  | 			     ~(1 << clk->enable_shift1), clk->enable_reg1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void clk_reg_enable1(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (clk->enable_reg1) | 
					
						
							|  |  |  | 		__raw_writel(__raw_readl(clk->enable_reg1) | | 
					
						
							|  |  |  | 			     (1 << clk->enable_shift1), clk->enable_reg1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int clk_wait_for_pll_lock(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	i = 0; | 
					
						
							|  |  |  | 	while (i++ < 0xFFF && !(__raw_readl(clk->scale_reg) & 1)) ;	/*wait for PLL to lock */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(__raw_readl(clk->scale_reg) & 1)) { | 
					
						
							|  |  |  | 		printk(KERN_ERR | 
					
						
							|  |  |  | 		       "%s ERROR: failed to lock, scale reg data: %x\n", | 
					
						
							|  |  |  | 		       clk->name, __raw_readl(clk->scale_reg)); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int switch_to_dirty_13mhz(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	u32 tmp_reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!clk->rate) | 
					
						
							|  |  |  | 		clk_reg_enable1(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp_reg = __raw_readl(clk->parent_switch_reg); | 
					
						
							|  |  |  | 	/*if 13Mhz clock selected, select 13'MHz (dirty) source from OSC */ | 
					
						
							|  |  |  | 	if (!(tmp_reg & 1)) { | 
					
						
							|  |  |  | 		tmp_reg |= (1 << 1);	/* Trigger switch to 13'MHz (dirty) clock */ | 
					
						
							|  |  |  | 		__raw_writel(tmp_reg, clk->parent_switch_reg); | 
					
						
							|  |  |  | 		i = 0; | 
					
						
							|  |  |  | 		while (i++ < 0xFFF && !(__raw_readl(clk->parent_switch_reg) & 1)) ;	/*wait for 13'MHz selection status */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!(__raw_readl(clk->parent_switch_reg) & 1)) { | 
					
						
							|  |  |  | 			printk(KERN_ERR | 
					
						
							|  |  |  | 			       "%s ERROR: failed to select 13'MHz, parent sw reg data: %x\n", | 
					
						
							|  |  |  | 			       clk->name, __raw_readl(clk->parent_switch_reg)); | 
					
						
							|  |  |  | 			ret = -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!clk->rate) | 
					
						
							|  |  |  | 		clk_reg_disable1(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int switch_to_clean_13mhz(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	u32 tmp_reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!clk->rate) | 
					
						
							|  |  |  | 		clk_reg_enable1(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp_reg = __raw_readl(clk->parent_switch_reg); | 
					
						
							|  |  |  | 	/*if 13'Mhz clock selected, select 13MHz (clean) source from OSC */ | 
					
						
							|  |  |  | 	if (tmp_reg & 1) { | 
					
						
							|  |  |  | 		tmp_reg &= ~(1 << 1);	/* Trigger switch to 13MHz (clean) clock */ | 
					
						
							|  |  |  | 		__raw_writel(tmp_reg, clk->parent_switch_reg); | 
					
						
							|  |  |  | 		i = 0; | 
					
						
							|  |  |  | 		while (i++ < 0xFFF && (__raw_readl(clk->parent_switch_reg) & 1)) ;	/*wait for 13MHz selection status */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (__raw_readl(clk->parent_switch_reg) & 1) { | 
					
						
							|  |  |  | 			printk(KERN_ERR | 
					
						
							|  |  |  | 			       "%s ERROR: failed to select 13MHz, parent sw reg data: %x\n", | 
					
						
							|  |  |  | 			       clk->name, __raw_readl(clk->parent_switch_reg)); | 
					
						
							|  |  |  | 			ret = -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!clk->rate) | 
					
						
							|  |  |  | 		clk_reg_disable1(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int set_13MHz_parent(struct clk *clk, struct clk *parent) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (parent == &ck_13MHz) | 
					
						
							|  |  |  | 		ret = switch_to_clean_13mhz(clk); | 
					
						
							|  |  |  | 	else if (parent == &ck_pll1) | 
					
						
							|  |  |  | 		ret = switch_to_dirty_13mhz(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PLL160_MIN_FCCO 156000
 | 
					
						
							|  |  |  | #define PLL160_MAX_FCCO 320000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Calculate pll160 settings. | 
					
						
							|  |  |  |  * Possible input: up to 320MHz with step of clk->parent->rate. | 
					
						
							|  |  |  |  * In PNX4008 parent rate for pll160s may be either 1 or 13MHz. | 
					
						
							|  |  |  |  * Ignored paths: "feedback" (bit 13 set), "div-by-N". | 
					
						
							|  |  |  |  * Setting ARM PLL4 rate to 0 will put CPU into direct run mode. | 
					
						
							|  |  |  |  * Setting PLL5 and PLL3 rate to 0 will disable USB and DSP clock input. | 
					
						
							|  |  |  |  * Please refer to PNX4008 IC manual for details. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int pll160_set_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 tmp_reg, tmp_m, tmp_2p, i; | 
					
						
							|  |  |  | 	u32 parent_rate; | 
					
						
							|  |  |  | 	int ret = -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	parent_rate = clk->parent->rate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!parent_rate) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* set direct run for ARM or disable output for others  */ | 
					
						
							|  |  |  | 	clk_reg_disable(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* disable source input as well (ignored for ARM) */ | 
					
						
							|  |  |  | 	clk_reg_disable1(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp_reg = __raw_readl(clk->scale_reg); | 
					
						
							|  |  |  | 	tmp_reg &= ~0x1ffff;	/*clear all settings, power down */ | 
					
						
							|  |  |  | 	__raw_writel(tmp_reg, clk->scale_reg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rate -= rate % parent_rate;	/*round down the input */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (rate > PLL160_MAX_FCCO) | 
					
						
							|  |  |  | 		rate = PLL160_MAX_FCCO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rate) { | 
					
						
							|  |  |  | 		clk->rate = 0; | 
					
						
							|  |  |  | 		ret = 0; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	clk_reg_enable1(clk); | 
					
						
							|  |  |  | 	tmp_reg = __raw_readl(clk->scale_reg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (rate == parent_rate) { | 
					
						
							|  |  |  | 		/*enter direct bypass mode */ | 
					
						
							|  |  |  | 		tmp_reg |= ((1 << 14) | (1 << 15)); | 
					
						
							|  |  |  | 		__raw_writel(tmp_reg, clk->scale_reg); | 
					
						
							|  |  |  | 		clk->rate = parent_rate; | 
					
						
							|  |  |  | 		clk_reg_enable(clk); | 
					
						
							|  |  |  | 		ret = 0; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i = 0; | 
					
						
							|  |  |  | 	for (tmp_2p = 1; tmp_2p < 16; tmp_2p <<= 1) { | 
					
						
							|  |  |  | 		if (rate * tmp_2p >= PLL160_MIN_FCCO) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		i++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (tmp_2p > 1) | 
					
						
							|  |  |  | 		tmp_reg |= ((i - 1) << 11); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		tmp_reg |= (1 << 14);	/*direct mode, no divide */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp_m = rate * tmp_2p; | 
					
						
							|  |  |  | 	tmp_m /= parent_rate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp_reg |= (tmp_m - 1) << 1;	/*calculate M */ | 
					
						
							|  |  |  | 	tmp_reg |= (1 << 16);	/*power up PLL */ | 
					
						
							|  |  |  | 	__raw_writel(tmp_reg, clk->scale_reg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (clk_wait_for_pll_lock(clk) < 0) { | 
					
						
							|  |  |  | 		clk_reg_disable(clk); | 
					
						
							|  |  |  | 		clk_reg_disable1(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tmp_reg = __raw_readl(clk->scale_reg); | 
					
						
							|  |  |  | 		tmp_reg &= ~0x1ffff;	/*clear all settings, power down */ | 
					
						
							|  |  |  | 		__raw_writel(tmp_reg, clk->scale_reg); | 
					
						
							|  |  |  | 		clk->rate = 0; | 
					
						
							|  |  |  | 		ret = -EFAULT; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	clk->rate = (tmp_m * parent_rate) / tmp_2p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (clk->flags & RATE_PROPAGATES) | 
					
						
							|  |  |  | 		propagate_rate(clk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	clk_reg_enable(clk); | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*configure PER_CLK*/ | 
					
						
							|  |  |  | static int per_clk_set_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp = __raw_readl(clk->scale_reg); | 
					
						
							|  |  |  | 	tmp &= ~(0x1f << 2); | 
					
						
							|  |  |  | 	tmp |= ((clk->parent->rate / clk->rate) - 1) << 2; | 
					
						
							|  |  |  | 	__raw_writel(tmp, clk->scale_reg); | 
					
						
							|  |  |  | 	clk->rate = rate; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*configure HCLK*/ | 
					
						
							|  |  |  | static int hclk_set_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 tmp; | 
					
						
							|  |  |  | 	tmp = __raw_readl(clk->scale_reg); | 
					
						
							|  |  |  | 	tmp = tmp & ~0x3; | 
					
						
							|  |  |  | 	switch (rate) { | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 2: | 
					
						
							|  |  |  | 		tmp |= 1; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 4: | 
					
						
							|  |  |  | 		tmp |= 2; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__raw_writel(tmp, clk->scale_reg); | 
					
						
							|  |  |  | 	clk->rate = rate; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 hclk_round_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (rate) { | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 	case 4: | 
					
						
							|  |  |  | 		return rate; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 2; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 per_clk_round_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return CLK_RATE_13MHZ; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int on_off_set_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (rate) { | 
					
						
							|  |  |  | 		clk_reg_enable(clk); | 
					
						
							|  |  |  | 		clk->rate = 1; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		clk_reg_disable(clk); | 
					
						
							|  |  |  | 		clk->rate = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int on_off_inv_set_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (rate) { | 
					
						
							|  |  |  | 		clk_reg_disable(clk);	/*enable bit is inverted */ | 
					
						
							|  |  |  | 		clk->rate = 1; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		clk_reg_enable(clk); | 
					
						
							|  |  |  | 		clk->rate = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 on_off_round_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (rate ? 1 : 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 pll4_round_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (rate > CLK_RATE_208MHZ) | 
					
						
							|  |  |  | 		rate = CLK_RATE_208MHZ; | 
					
						
							|  |  |  | 	if (rate == CLK_RATE_208MHZ && hclk_ck.user_rate == 1) | 
					
						
							|  |  |  | 		rate = CLK_RATE_208MHZ - CLK_RATE_13MHZ; | 
					
						
							|  |  |  | 	return (rate - (rate % (hclk_ck.user_rate * CLK_RATE_13MHZ))); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 pll3_round_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (rate > CLK_RATE_208MHZ) | 
					
						
							|  |  |  | 		rate = CLK_RATE_208MHZ; | 
					
						
							|  |  |  | 	return (rate - rate % CLK_RATE_13MHZ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 pll5_round_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (rate ? CLK_RATE_48MHZ : 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 ck_13MHz_round_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (rate ? CLK_RATE_13MHZ : 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ck_13MHz_set_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (rate) { | 
					
						
							|  |  |  | 		clk_reg_disable(clk);	/*enable bit is inverted */ | 
					
						
							|  |  |  | 		udelay(500); | 
					
						
							|  |  |  | 		clk->rate = CLK_RATE_13MHZ; | 
					
						
							|  |  |  | 		ck_1MHz.rate = CLK_RATE_1MHZ; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		clk_reg_enable(clk); | 
					
						
							|  |  |  | 		clk->rate = 0; | 
					
						
							|  |  |  | 		ck_1MHz.rate = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int pll1_set_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #if 0 /* doesn't work on some boards, probably a HW BUG */
 | 
					
						
							|  |  |  | 	if (rate) { | 
					
						
							|  |  |  | 		clk_reg_disable(clk);	/*enable bit is inverted */ | 
					
						
							|  |  |  | 		if (!clk_wait_for_pll_lock(clk)) { | 
					
						
							|  |  |  | 			clk->rate = CLK_RATE_13MHZ; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			clk_reg_enable(clk); | 
					
						
							|  |  |  | 			clk->rate = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		clk_reg_enable(clk); | 
					
						
							|  |  |  | 		clk->rate = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Clock sources */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk osc_13MHz = { | 
					
						
							|  |  |  | 	.name = "osc_13MHz", | 
					
						
							|  |  |  | 	.flags = FIXED_RATE, | 
					
						
							|  |  |  | 	.rate = CLK_RATE_13MHZ, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk ck_13MHz = { | 
					
						
							|  |  |  | 	.name = "ck_13MHz", | 
					
						
							|  |  |  | 	.parent = &osc_13MHz, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &ck_13MHz_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &ck_13MHz_set_rate, | 
					
						
							|  |  |  | 	.enable_reg = OSC13CTRL_REG, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.rate = CLK_RATE_13MHZ, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk osc_32KHz = { | 
					
						
							|  |  |  | 	.name = "osc_32KHz", | 
					
						
							|  |  |  | 	.flags = FIXED_RATE, | 
					
						
							|  |  |  | 	.rate = CLK_RATE_32KHZ, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*attached to PLL5*/ | 
					
						
							|  |  |  | static struct clk ck_1MHz = { | 
					
						
							|  |  |  | 	.name = "ck_1MHz", | 
					
						
							|  |  |  | 	.flags = FIXED_RATE | PARENT_SET_RATE, | 
					
						
							|  |  |  | 	.parent = &ck_13MHz, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* PLL1 (397) - provides 13' MHz clock */ | 
					
						
							|  |  |  | static struct clk ck_pll1 = { | 
					
						
							|  |  |  | 	.name = "ck_pll1", | 
					
						
							|  |  |  | 	.parent = &osc_32KHz, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &ck_13MHz_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &pll1_set_rate, | 
					
						
							|  |  |  | 	.enable_reg = PLLCTRL_REG, | 
					
						
							|  |  |  | 	.enable_shift = 1, | 
					
						
							|  |  |  | 	.scale_reg = PLLCTRL_REG, | 
					
						
							|  |  |  | 	.rate = CLK_RATE_13MHZ, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* CPU/Bus PLL */ | 
					
						
							|  |  |  | static struct clk ck_pll4 = { | 
					
						
							|  |  |  | 	.name = "ck_pll4", | 
					
						
							|  |  |  | 	.parent = &ck_pll1, | 
					
						
							|  |  |  | 	.flags = RATE_PROPAGATES | NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.propagate_next = &per_ck, | 
					
						
							|  |  |  | 	.round_rate = &pll4_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &pll160_set_rate, | 
					
						
							|  |  |  | 	.rate = CLK_RATE_208MHZ, | 
					
						
							|  |  |  | 	.scale_reg = HCLKPLLCTRL_REG, | 
					
						
							|  |  |  | 	.enable_reg = PWRCTRL_REG, | 
					
						
							|  |  |  | 	.enable_shift = 2, | 
					
						
							|  |  |  | 	.parent_switch_reg = SYSCLKCTRL_REG, | 
					
						
							|  |  |  | 	.set_parent = &set_13MHz_parent, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* USB PLL */ | 
					
						
							|  |  |  | static struct clk ck_pll5 = { | 
					
						
							|  |  |  | 	.name = "ck_pll5", | 
					
						
							|  |  |  | 	.parent = &ck_1MHz, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &pll5_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &pll160_set_rate, | 
					
						
							|  |  |  | 	.scale_reg = USBCTRL_REG, | 
					
						
							|  |  |  | 	.enable_reg = USBCTRL_REG, | 
					
						
							|  |  |  | 	.enable_shift = 18, | 
					
						
							|  |  |  | 	.enable_reg1 = USBCTRL_REG, | 
					
						
							|  |  |  | 	.enable_shift1 = 17, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* XPERTTeak DSP PLL */ | 
					
						
							|  |  |  | static struct clk ck_pll3 = { | 
					
						
							|  |  |  | 	.name = "ck_pll3", | 
					
						
							|  |  |  | 	.parent = &ck_pll1, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &pll3_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &pll160_set_rate, | 
					
						
							|  |  |  | 	.scale_reg = DSPPLLCTRL_REG, | 
					
						
							|  |  |  | 	.enable_reg = DSPCLKCTRL_REG, | 
					
						
							|  |  |  | 	.enable_shift = 3, | 
					
						
							|  |  |  | 	.enable_reg1 = DSPCLKCTRL_REG, | 
					
						
							|  |  |  | 	.enable_shift1 = 2, | 
					
						
							|  |  |  | 	.parent_switch_reg = DSPCLKCTRL_REG, | 
					
						
							|  |  |  | 	.set_parent = &set_13MHz_parent, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk hclk_ck = { | 
					
						
							|  |  |  | 	.name = "hclk_ck", | 
					
						
							|  |  |  | 	.parent = &ck_pll4, | 
					
						
							|  |  |  | 	.flags = PARENT_SET_RATE, | 
					
						
							|  |  |  | 	.set_rate = &hclk_set_rate, | 
					
						
							|  |  |  | 	.round_rate = &hclk_round_rate, | 
					
						
							|  |  |  | 	.scale_reg = HCLKDIVCTRL_REG, | 
					
						
							|  |  |  | 	.rate = 2, | 
					
						
							|  |  |  | 	.user_rate = 2, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk per_ck = { | 
					
						
							|  |  |  | 	.name = "per_ck", | 
					
						
							|  |  |  | 	.parent = &ck_pll4, | 
					
						
							|  |  |  | 	.flags = FIXED_RATE, | 
					
						
							|  |  |  | 	.propagate_next = &hclk_ck, | 
					
						
							|  |  |  | 	.set_rate = &per_clk_set_rate, | 
					
						
							|  |  |  | 	.round_rate = &per_clk_round_rate, | 
					
						
							|  |  |  | 	.scale_reg = HCLKDIVCTRL_REG, | 
					
						
							|  |  |  | 	.rate = CLK_RATE_13MHZ, | 
					
						
							|  |  |  | 	.user_rate = CLK_RATE_13MHZ, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk m2hclk_ck = { | 
					
						
							|  |  |  | 	.name = "m2hclk_ck", | 
					
						
							|  |  |  | 	.parent = &hclk_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_inv_set_rate, | 
					
						
							|  |  |  | 	.rate = 1, | 
					
						
							|  |  |  | 	.enable_shift = 6, | 
					
						
							|  |  |  | 	.enable_reg = PWRCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk vfp9_ck = { | 
					
						
							|  |  |  | 	.name = "vfp9_ck", | 
					
						
							|  |  |  | 	.parent = &ck_pll4, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.rate = 1, | 
					
						
							|  |  |  | 	.enable_shift = 4, | 
					
						
							|  |  |  | 	.enable_reg = VFP9CLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk keyscan_ck = { | 
					
						
							|  |  |  | 	.name = "keyscan_ck", | 
					
						
							|  |  |  | 	.parent = &osc_32KHz, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = KEYCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk touch_ck = { | 
					
						
							|  |  |  | 	.name = "touch_ck", | 
					
						
							|  |  |  | 	.parent = &osc_32KHz, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = TSCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk pwm1_ck = { | 
					
						
							|  |  |  | 	.name = "pwm1_ck", | 
					
						
							|  |  |  | 	.parent = &osc_32KHz, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = PWMCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk pwm2_ck = { | 
					
						
							|  |  |  | 	.name = "pwm2_ck", | 
					
						
							|  |  |  | 	.parent = &osc_32KHz, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 2, | 
					
						
							|  |  |  | 	.enable_reg = PWMCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk jpeg_ck = { | 
					
						
							|  |  |  | 	.name = "jpeg_ck", | 
					
						
							|  |  |  | 	.parent = &hclk_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = JPEGCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk ms_ck = { | 
					
						
							|  |  |  | 	.name = "ms_ck", | 
					
						
							|  |  |  | 	.parent = &ck_pll4, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 5, | 
					
						
							|  |  |  | 	.enable_reg = MSCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk dum_ck = { | 
					
						
							|  |  |  | 	.name = "dum_ck", | 
					
						
							|  |  |  | 	.parent = &hclk_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = DUMCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk flash_ck = { | 
					
						
							|  |  |  | 	.name = "flash_ck", | 
					
						
							|  |  |  | 	.parent = &hclk_ck, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 1,	/* Only MLC clock supported */ | 
					
						
							|  |  |  | 	.enable_reg = FLASHCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk i2c0_ck = { | 
					
						
							|  |  |  | 	.name = "i2c0_ck", | 
					
						
							|  |  |  | 	.parent = &per_ck, | 
					
						
							| 
									
										
										
										
											2009-11-20 12:46:07 +00:00
										 |  |  | 	.flags = NEEDS_INITIALIZATION | FIXED_RATE, | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = I2CCLKCTRL_REG, | 
					
						
							| 
									
										
										
										
											2009-11-20 12:46:07 +00:00
										 |  |  | 	.rate = 13000000, | 
					
						
							| 
									
										
										
										
											2009-11-20 11:44:46 +00:00
										 |  |  | 	.enable = clk_reg_enable, | 
					
						
							|  |  |  | 	.disable = clk_reg_disable, | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk i2c1_ck = { | 
					
						
							|  |  |  | 	.name = "i2c1_ck", | 
					
						
							|  |  |  | 	.parent = &per_ck, | 
					
						
							| 
									
										
										
										
											2009-11-20 12:46:07 +00:00
										 |  |  | 	.flags = NEEDS_INITIALIZATION | FIXED_RATE, | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 	.enable_shift = 1, | 
					
						
							|  |  |  | 	.enable_reg = I2CCLKCTRL_REG, | 
					
						
							| 
									
										
										
										
											2009-11-20 12:46:07 +00:00
										 |  |  | 	.rate = 13000000, | 
					
						
							| 
									
										
										
										
											2009-11-20 11:44:46 +00:00
										 |  |  | 	.enable = clk_reg_enable, | 
					
						
							|  |  |  | 	.disable = clk_reg_disable, | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk i2c2_ck = { | 
					
						
							|  |  |  | 	.name = "i2c2_ck", | 
					
						
							|  |  |  | 	.parent = &per_ck, | 
					
						
							| 
									
										
										
										
											2009-11-20 12:46:07 +00:00
										 |  |  | 	.flags = NEEDS_INITIALIZATION | FIXED_RATE, | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 	.enable_shift = 2, | 
					
						
							|  |  |  | 	.enable_reg = USB_OTG_CLKCTRL_REG, | 
					
						
							| 
									
										
										
										
											2009-11-20 12:46:07 +00:00
										 |  |  | 	.rate = 13000000, | 
					
						
							| 
									
										
										
										
											2009-11-20 11:44:46 +00:00
										 |  |  | 	.enable = clk_reg_enable, | 
					
						
							|  |  |  | 	.disable = clk_reg_disable, | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk spi0_ck = { | 
					
						
							|  |  |  | 	.name = "spi0_ck", | 
					
						
							|  |  |  | 	.parent = &hclk_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = SPICTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk spi1_ck = { | 
					
						
							|  |  |  | 	.name = "spi1_ck", | 
					
						
							|  |  |  | 	.parent = &hclk_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 4, | 
					
						
							|  |  |  | 	.enable_reg = SPICTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk dma_ck = { | 
					
						
							|  |  |  | 	.name = "dma_ck", | 
					
						
							|  |  |  | 	.parent = &hclk_ck, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = DMACLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk uart3_ck = { | 
					
						
							|  |  |  | 	.name = "uart3_ck", | 
					
						
							|  |  |  | 	.parent = &per_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.rate = 1, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = UARTCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk uart4_ck = { | 
					
						
							|  |  |  | 	.name = "uart4_ck", | 
					
						
							|  |  |  | 	.parent = &per_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 1, | 
					
						
							|  |  |  | 	.enable_reg = UARTCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk uart5_ck = { | 
					
						
							|  |  |  | 	.name = "uart5_ck", | 
					
						
							|  |  |  | 	.parent = &per_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.rate = 1, | 
					
						
							|  |  |  | 	.enable_shift = 2, | 
					
						
							|  |  |  | 	.enable_reg = UARTCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clk uart6_ck = { | 
					
						
							|  |  |  | 	.name = "uart6_ck", | 
					
						
							|  |  |  | 	.parent = &per_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.round_rate = &on_off_round_rate, | 
					
						
							|  |  |  | 	.set_rate = &on_off_set_rate, | 
					
						
							|  |  |  | 	.enable_shift = 3, | 
					
						
							|  |  |  | 	.enable_reg = UARTCLKCTRL_REG, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-26 19:31:49 +04:00
										 |  |  | static struct clk wdt_ck = { | 
					
						
							|  |  |  | 	.name = "wdt_ck", | 
					
						
							|  |  |  | 	.parent = &per_ck, | 
					
						
							|  |  |  | 	.flags = NEEDS_INITIALIZATION, | 
					
						
							|  |  |  | 	.enable_shift = 0, | 
					
						
							|  |  |  | 	.enable_reg = TIMCLKCTRL_REG, | 
					
						
							| 
									
										
										
										
											2009-11-20 13:04:14 +00:00
										 |  |  | 	.enable = clk_reg_enable, | 
					
						
							|  |  |  | 	.disable = clk_reg_disable, | 
					
						
							| 
									
										
										
										
											2006-06-26 19:31:49 +04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | /* These clocks are visible outside this module
 | 
					
						
							|  |  |  |  * and can be initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2009-11-20 10:32:41 +00:00
										 |  |  | static struct clk *onchip_clks[] __initdata = { | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 	&ck_13MHz, | 
					
						
							|  |  |  | 	&ck_pll1, | 
					
						
							|  |  |  | 	&ck_pll4, | 
					
						
							|  |  |  | 	&ck_pll5, | 
					
						
							|  |  |  | 	&ck_pll3, | 
					
						
							|  |  |  | 	&vfp9_ck, | 
					
						
							|  |  |  | 	&m2hclk_ck, | 
					
						
							|  |  |  | 	&hclk_ck, | 
					
						
							|  |  |  | 	&dma_ck, | 
					
						
							|  |  |  | 	&flash_ck, | 
					
						
							|  |  |  | 	&dum_ck, | 
					
						
							|  |  |  | 	&keyscan_ck, | 
					
						
							|  |  |  | 	&pwm1_ck, | 
					
						
							|  |  |  | 	&pwm2_ck, | 
					
						
							|  |  |  | 	&jpeg_ck, | 
					
						
							|  |  |  | 	&ms_ck, | 
					
						
							|  |  |  | 	&touch_ck, | 
					
						
							|  |  |  | 	&i2c0_ck, | 
					
						
							|  |  |  | 	&i2c1_ck, | 
					
						
							|  |  |  | 	&i2c2_ck, | 
					
						
							|  |  |  | 	&spi0_ck, | 
					
						
							|  |  |  | 	&spi1_ck, | 
					
						
							|  |  |  | 	&uart3_ck, | 
					
						
							|  |  |  | 	&uart4_ck, | 
					
						
							|  |  |  | 	&uart5_ck, | 
					
						
							|  |  |  | 	&uart6_ck, | 
					
						
							| 
									
										
										
										
											2006-06-26 19:31:49 +04:00
										 |  |  | 	&wdt_ck, | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 10:32:41 +00:00
										 |  |  | static struct clk_lookup onchip_clkreg[] = { | 
					
						
							|  |  |  | 	{ .clk = &ck_13MHz,	.con_id = "ck_13MHz"	}, | 
					
						
							|  |  |  | 	{ .clk = &ck_pll1,	.con_id = "ck_pll1"	}, | 
					
						
							|  |  |  | 	{ .clk = &ck_pll4,	.con_id = "ck_pll4"	}, | 
					
						
							|  |  |  | 	{ .clk = &ck_pll5,	.con_id = "ck_pll5"	}, | 
					
						
							|  |  |  | 	{ .clk = &ck_pll3,	.con_id = "ck_pll3"	}, | 
					
						
							|  |  |  | 	{ .clk = &vfp9_ck,	.con_id = "vfp9_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &m2hclk_ck,	.con_id = "m2hclk_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &hclk_ck,	.con_id = "hclk_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &dma_ck,	.con_id = "dma_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &flash_ck,	.con_id = "flash_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &dum_ck,	.con_id = "dum_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &keyscan_ck,	.con_id = "keyscan_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &pwm1_ck,	.con_id = "pwm1_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &pwm2_ck,	.con_id = "pwm2_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &jpeg_ck,	.con_id = "jpeg_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &ms_ck,	.con_id = "ms_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &touch_ck,	.con_id = "touch_ck"	}, | 
					
						
							| 
									
										
										
										
											2009-11-20 10:46:24 +00:00
										 |  |  | 	{ .clk = &i2c0_ck,	.dev_id = "pnx-i2c.0"	}, | 
					
						
							|  |  |  | 	{ .clk = &i2c1_ck,	.dev_id = "pnx-i2c.1"	}, | 
					
						
							|  |  |  | 	{ .clk = &i2c2_ck,	.dev_id = "pnx-i2c.2"	}, | 
					
						
							| 
									
										
										
										
											2009-11-20 10:32:41 +00:00
										 |  |  | 	{ .clk = &spi0_ck,	.con_id = "spi0_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &spi1_ck,	.con_id = "spi1_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &uart3_ck,	.con_id = "uart3_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &uart4_ck,	.con_id = "uart4_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &uart5_ck,	.con_id = "uart5_ck"	}, | 
					
						
							|  |  |  | 	{ .clk = &uart6_ck,	.con_id = "uart6_ck"	}, | 
					
						
							| 
									
										
										
										
											2009-11-20 13:07:28 +00:00
										 |  |  | 	{ .clk = &wdt_ck,	.dev_id = "pnx4008-watchdog" }, | 
					
						
							| 
									
										
										
										
											2009-11-20 10:32:41 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | static void local_clk_disable(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 	if (WARN_ON(clk->usecount == 0)) | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 	if (!(--clk->usecount)) { | 
					
						
							| 
									
										
										
										
											2009-11-20 11:28:59 +00:00
										 |  |  | 		if (clk->disable) | 
					
						
							|  |  |  | 			clk->disable(clk); | 
					
						
							|  |  |  | 		else if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate) | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 			clk->set_rate(clk, 0); | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | 		if (clk->parent) | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 			local_clk_disable(clk->parent); | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | static int local_clk_enable(struct clk *clk) | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 	if (clk->usecount == 0) { | 
					
						
							|  |  |  | 		if (clk->parent) { | 
					
						
							|  |  |  | 			ret = local_clk_enable(clk->parent); | 
					
						
							|  |  |  | 			if (ret != 0) | 
					
						
							|  |  |  | 				goto out; | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 11:28:59 +00:00
										 |  |  | 		if (clk->enable) | 
					
						
							|  |  |  | 			ret = clk->enable(clk); | 
					
						
							|  |  |  | 		else if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate | 
					
						
							|  |  |  | 			    && clk->user_rate) | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 			ret = clk->set_rate(clk, clk->user_rate); | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (ret != 0 && clk->parent) { | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 			local_clk_disable(clk->parent); | 
					
						
							|  |  |  | 			goto out; | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		clk->usecount++; | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | static int local_set_rate(struct clk *clk, u32 rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -EINVAL; | 
					
						
							|  |  |  | 	if (clk->set_rate) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (clk->user_rate == clk->rate && clk->parent->rate) { | 
					
						
							|  |  |  | 			/* if clock enabled or rate not set */ | 
					
						
							|  |  |  | 			clk->user_rate = clk->round_rate(clk, rate); | 
					
						
							|  |  |  | 			ret = clk->set_rate(clk, clk->user_rate); | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			clk->user_rate = clk->round_rate(clk, rate); | 
					
						
							|  |  |  | 		ret = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int clk_set_rate(struct clk *clk, unsigned long rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (clk->flags & FIXED_RATE) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	clock_lock(); | 
					
						
							|  |  |  | 	if ((clk->flags & PARENT_SET_RATE) && clk->parent) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		clk->user_rate = clk->round_rate(clk, rate); | 
					
						
							|  |  |  | 		/* parent clock needs to be refreshed
 | 
					
						
							|  |  |  | 		   for the setting to take effect */ | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ret = local_set_rate(clk, rate); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 	clock_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EXPORT_SYMBOL(clk_set_rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned long clk_get_rate(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long ret; | 
					
						
							|  |  |  | 	clock_lock(); | 
					
						
							|  |  |  | 	ret = clk->rate; | 
					
						
							|  |  |  | 	clock_unlock(); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(clk_get_rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int clk_enable(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	clock_lock(); | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 	ret = local_clk_enable(clk); | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 	clock_unlock(); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EXPORT_SYMBOL(clk_enable); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void clk_disable(struct clk *clk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	clock_lock(); | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 	local_clk_disable(clk); | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 	clock_unlock(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-22 10:26:20 +01:00
										 |  |  | EXPORT_SYMBOL(clk_disable); | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | long clk_round_rate(struct clk *clk, unsigned long rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	long ret; | 
					
						
							|  |  |  | 	clock_lock(); | 
					
						
							|  |  |  | 	if (clk->round_rate) | 
					
						
							|  |  |  | 		ret = clk->round_rate(clk, rate); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ret = clk->rate; | 
					
						
							|  |  |  | 	clock_unlock(); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EXPORT_SYMBOL(clk_round_rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int clk_set_parent(struct clk *clk, struct clk *parent) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -ENODEV; | 
					
						
							|  |  |  | 	if (!clk->set_parent) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	clock_lock(); | 
					
						
							|  |  |  | 	ret = clk->set_parent(clk, parent); | 
					
						
							|  |  |  | 	if (!ret) | 
					
						
							|  |  |  | 		clk->parent = parent; | 
					
						
							|  |  |  | 	clock_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EXPORT_SYMBOL(clk_set_parent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init clk_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct clk **clkp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Disable autoclocking, as it doesn't seem to work */ | 
					
						
							|  |  |  | 	__raw_writel(0xff, AUTOCLK_CTRL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks); | 
					
						
							|  |  |  | 	     clkp++) { | 
					
						
							| 
									
										
										
										
											2009-11-20 11:28:59 +00:00
										 |  |  | 		struct clk *clk = *clkp; | 
					
						
							|  |  |  | 		if (clk->flags & NEEDS_INITIALIZATION) { | 
					
						
							|  |  |  | 			if (clk->set_rate) { | 
					
						
							|  |  |  | 				clk->user_rate = clk->rate; | 
					
						
							|  |  |  | 				local_set_rate(clk, clk->user_rate); | 
					
						
							|  |  |  | 				if (clk->set_parent) | 
					
						
							|  |  |  | 					clk->set_parent(clk, clk->parent); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (clk->enable && clk->usecount) | 
					
						
							|  |  |  | 				clk->enable(clk); | 
					
						
							|  |  |  | 			if (clk->disable && !clk->usecount) | 
					
						
							|  |  |  | 				clk->disable(clk); | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		pr_debug("%s: clock %s, rate %ld\n", | 
					
						
							| 
									
										
										
										
											2009-11-20 11:28:59 +00:00
										 |  |  | 			__func__, clk->name, clk->rate); | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 11:25:44 +00:00
										 |  |  | 	local_clk_enable(&ck_pll4); | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* if ck_13MHz is not used, disable it. */ | 
					
						
							|  |  |  | 	if (ck_13MHz.usecount == 0) | 
					
						
							|  |  |  | 		local_clk_disable(&ck_13MHz); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Disable autoclocking */ | 
					
						
							|  |  |  | 	__raw_writeb(0xff, AUTOCLK_CTRL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-20 10:32:41 +00:00
										 |  |  | 	clkdev_add_table(onchip_clkreg, ARRAY_SIZE(onchip_clkreg)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-16 11:54:37 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | arch_initcall(clk_init); |