|  | @@ -121,3 +121,136 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	rate = clk->parent->get_rate(clk->parent);
 | 
	
		
			
				|  |  |  	rate = (rate + div / 2) / div;
 | 
	
		
			
				|  |  | +	rate *= mul;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return rate;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static long pll_set_rate(struct clk *clk, unsigned long rate,
 | 
	
		
			
				|  |  | +			 u32 *pll_ctrl)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	unsigned long mul;
 | 
	
		
			
				|  |  | +	unsigned long mul_best_fit = 0;
 | 
	
		
			
				|  |  | +	unsigned long div;
 | 
	
		
			
				|  |  | +	unsigned long div_min;
 | 
	
		
			
				|  |  | +	unsigned long div_max;
 | 
	
		
			
				|  |  | +	unsigned long div_best_fit = 0;
 | 
	
		
			
				|  |  | +	unsigned long base;
 | 
	
		
			
				|  |  | +	unsigned long pll_in;
 | 
	
		
			
				|  |  | +	unsigned long actual = 0;
 | 
	
		
			
				|  |  | +	unsigned long rate_error;
 | 
	
		
			
				|  |  | +	unsigned long rate_error_prev = ~0UL;
 | 
	
		
			
				|  |  | +	u32 ctrl;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Rate must be between 80 MHz and 200 Mhz. */
 | 
	
		
			
				|  |  | +	if (rate < 80000000UL || rate > 200000000UL)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ctrl = PM_BF(PLLOPT, 4);
 | 
	
		
			
				|  |  | +	base = clk->parent->get_rate(clk->parent);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* PLL input frequency must be between 6 MHz and 32 MHz. */
 | 
	
		
			
				|  |  | +	div_min = DIV_ROUND_UP(base, 32000000UL);
 | 
	
		
			
				|  |  | +	div_max = base / 6000000UL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (div_max < div_min)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (div = div_min; div <= div_max; div++) {
 | 
	
		
			
				|  |  | +		pll_in = (base + div / 2) / div;
 | 
	
		
			
				|  |  | +		mul = (rate + pll_in / 2) / pll_in;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (mul == 0)
 | 
	
		
			
				|  |  | +			continue;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		actual = pll_in * mul;
 | 
	
		
			
				|  |  | +		rate_error = abs(actual - rate);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (rate_error < rate_error_prev) {
 | 
	
		
			
				|  |  | +			mul_best_fit = mul;
 | 
	
		
			
				|  |  | +			div_best_fit = div;
 | 
	
		
			
				|  |  | +			rate_error_prev = rate_error;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (rate_error == 0)
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (div_best_fit == 0)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ctrl |= PM_BF(PLLMUL, mul_best_fit - 1);
 | 
	
		
			
				|  |  | +	ctrl |= PM_BF(PLLDIV, div_best_fit - 1);
 | 
	
		
			
				|  |  | +	ctrl |= PM_BF(PLLCOUNT, 16);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (clk->parent == &osc1)
 | 
	
		
			
				|  |  | +		ctrl |= PM_BIT(PLLOSC);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	*pll_ctrl = ctrl;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return actual;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static unsigned long pll0_get_rate(struct clk *clk)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	u32 control;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	control = pm_readl(PLL0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return pll_get_rate(clk, control);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void pll1_mode(struct clk *clk, int enabled)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	unsigned long timeout;
 | 
	
		
			
				|  |  | +	u32 status;
 | 
	
		
			
				|  |  | +	u32 ctrl;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ctrl = pm_readl(PLL1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (enabled) {
 | 
	
		
			
				|  |  | +		if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) {
 | 
	
		
			
				|  |  | +			pr_debug("clk %s: failed to enable, rate not set\n",
 | 
	
		
			
				|  |  | +					clk->name);
 | 
	
		
			
				|  |  | +			return;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		ctrl |= PM_BIT(PLLEN);
 | 
	
		
			
				|  |  | +		pm_writel(PLL1, ctrl);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		/* Wait for PLL lock. */
 | 
	
		
			
				|  |  | +		for (timeout = 10000; timeout; timeout--) {
 | 
	
		
			
				|  |  | +			status = pm_readl(ISR);
 | 
	
		
			
				|  |  | +			if (status & PM_BIT(LOCK1))
 | 
	
		
			
				|  |  | +				break;
 | 
	
		
			
				|  |  | +			udelay(10);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (!(status & PM_BIT(LOCK1)))
 | 
	
		
			
				|  |  | +			printk(KERN_ERR "clk %s: timeout waiting for lock\n",
 | 
	
		
			
				|  |  | +					clk->name);
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		ctrl &= ~PM_BIT(PLLEN);
 | 
	
		
			
				|  |  | +		pm_writel(PLL1, ctrl);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static unsigned long pll1_get_rate(struct clk *clk)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	u32 control;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	control = pm_readl(PLL1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return pll_get_rate(clk, control);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	u32 ctrl = 0;
 | 
	
		
			
				|  |  | +	unsigned long actual_rate;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	actual_rate = pll_set_rate(clk, rate, &ctrl);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (apply) {
 | 
	
		
			
				|  |  | +		if (actual_rate != rate)
 | 
	
		
			
				|  |  | +			return -EINVAL;
 |