forked from mirrors/linux
		
	clk: meson: fractional pll support
Fractional MPLLs are a superset of the existing AmLogic MPLLs. They add in a couple of new bitfields for further dividing the clock rate to achieve rates with fractional hertz. Tested-by: Kevin Hilman <khilman@baylibre.com> Signed-off-by: Michael Turquette <mturquette@baylibre.com>
This commit is contained in:
		
							parent
							
								
									1c50da4f27
								
							
						
					
					
						commit
						4a47295144
					
				
					 2 changed files with 45 additions and 2 deletions
				
			
		|  | @ -53,7 +53,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, | |||
| 	struct parm *p; | ||||
| 	unsigned long parent_rate_mhz = parent_rate / 1000000; | ||||
| 	unsigned long rate_mhz; | ||||
| 	u16 n, m, od; | ||||
| 	u16 n, m, frac = 0, od, od2 = 0; | ||||
| 	u32 reg; | ||||
| 
 | ||||
| 	p = &pll->n; | ||||
|  | @ -68,7 +68,21 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, | |||
| 	reg = readl(pll->base + p->reg_off); | ||||
| 	od = PARM_GET(p->width, p->shift, reg); | ||||
| 
 | ||||
| 	rate_mhz = (parent_rate_mhz * m / n) >> od; | ||||
| 	p = &pll->od2; | ||||
| 	if (p->width) { | ||||
| 		reg = readl(pll->base + p->reg_off); | ||||
| 		od2 = PARM_GET(p->width, p->shift, reg); | ||||
| 	} | ||||
| 
 | ||||
| 	p = &pll->frac; | ||||
| 	if (p->width) { | ||||
| 		reg = readl(pll->base + p->reg_off); | ||||
| 		frac = PARM_GET(p->width, p->shift, reg); | ||||
| 		rate_mhz = (parent_rate_mhz * m + \ | ||||
| 				(parent_rate_mhz * frac >> 12)) * 2 / n; | ||||
| 		rate_mhz = rate_mhz >> od >> od2; | ||||
| 	} else | ||||
| 		rate_mhz = (parent_rate_mhz * m / n) >> od >> od2; | ||||
| 
 | ||||
| 	return rate_mhz * 1000000; | ||||
| } | ||||
|  | @ -155,6 +169,20 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, | |||
| 	reg = PARM_SET(p->width, p->shift, reg, rate_set->od); | ||||
| 	writel(reg, pll->base + p->reg_off); | ||||
| 
 | ||||
| 	p = &pll->od2; | ||||
| 	if (p->width) { | ||||
| 		reg = readl(pll->base + p->reg_off); | ||||
| 		reg = PARM_SET(p->width, p->shift, reg, rate_set->od2); | ||||
| 		writel(reg, pll->base + p->reg_off); | ||||
| 	} | ||||
| 
 | ||||
| 	p = &pll->frac; | ||||
| 	if (p->width) { | ||||
| 		reg = readl(pll->base + p->reg_off); | ||||
| 		reg = PARM_SET(p->width, p->shift, reg, rate_set->frac); | ||||
| 		writel(reg, pll->base + p->reg_off); | ||||
| 	} | ||||
| 
 | ||||
| 	p = &pll->n; | ||||
| 	ret = meson_clk_pll_wait_lock(pll, p); | ||||
| 	if (ret) { | ||||
|  |  | |||
|  | @ -40,7 +40,10 @@ struct pll_rate_table { | |||
| 	u16		m; | ||||
| 	u16		n; | ||||
| 	u16		od; | ||||
| 	u16		od2; | ||||
| 	u16		frac; | ||||
| }; | ||||
| 
 | ||||
| #define PLL_RATE(_r, _m, _n, _od)					\ | ||||
| 	{								\ | ||||
| 		.rate		= (_r),					\ | ||||
|  | @ -49,12 +52,24 @@ struct pll_rate_table { | |||
| 		.od		= (_od),				\ | ||||
| 	}								\ | ||||
| 
 | ||||
| #define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac)			\ | ||||
| 	{								\ | ||||
| 		.rate		= (_r),					\ | ||||
| 		.m		= (_m),					\ | ||||
| 		.n		= (_n),					\ | ||||
| 		.od		= (_od),				\ | ||||
| 		.od2		= (_od2),				\ | ||||
| 		.frac		= (_frac),				\ | ||||
| 	}								\ | ||||
| 
 | ||||
| struct meson_clk_pll { | ||||
| 	struct clk_hw hw; | ||||
| 	void __iomem *base; | ||||
| 	struct parm m; | ||||
| 	struct parm n; | ||||
| 	struct parm frac; | ||||
| 	struct parm od; | ||||
| 	struct parm od2; | ||||
| 	const struct pll_rate_table *rate_table; | ||||
| 	unsigned int rate_count; | ||||
| 	spinlock_t *lock; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Michael Turquette
						Michael Turquette