| Sascha Hauer | 2af9e6d | 2012-03-09 09:11:55 +0100 | [diff] [blame] | 1 | #include <linux/clk.h> | 
 | 2 | #include <linux/clk-provider.h> | 
 | 3 | #include <linux/io.h> | 
 | 4 | #include <linux/slab.h> | 
 | 5 | #include <linux/kernel.h> | 
 | 6 | #include <linux/err.h> | 
| Sascha Hauer | 3a84d17 | 2012-09-11 08:50:00 +0200 | [diff] [blame] | 7 |  | 
| Sascha Hauer | 2af9e6d | 2012-03-09 09:11:55 +0100 | [diff] [blame] | 8 | #include "clk.h" | 
| Shawn Guo | e337247 | 2012-09-13 21:01:00 +0800 | [diff] [blame] | 9 | #include "common.h" | 
| Shawn Guo | 50f2de6 | 2012-09-14 14:14:45 +0800 | [diff] [blame] | 10 | #include "hardware.h" | 
| Sascha Hauer | 2af9e6d | 2012-03-09 09:11:55 +0100 | [diff] [blame] | 11 |  | 
 | 12 | /** | 
 | 13 |  * pll v1 | 
 | 14 |  * | 
 | 15 |  * @clk_hw	clock source | 
 | 16 |  * @parent	the parent clock name | 
 | 17 |  * @base	base address of pll registers | 
 | 18 |  * | 
 | 19 |  * PLL clock version 1, found on i.MX1/21/25/27/31/35 | 
 | 20 |  */ | 
 | 21 | struct clk_pllv1 { | 
 | 22 | 	struct clk_hw	hw; | 
 | 23 | 	void __iomem	*base; | 
 | 24 | }; | 
 | 25 |  | 
 | 26 | #define to_clk_pllv1(clk) (container_of(clk, struct clk_pllv1, clk)) | 
 | 27 |  | 
 | 28 | static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, | 
 | 29 | 		unsigned long parent_rate) | 
 | 30 | { | 
 | 31 | 	struct clk_pllv1 *pll = to_clk_pllv1(hw); | 
| Sascha Hauer | a6dd3c8 | 2012-09-11 08:40:38 +0200 | [diff] [blame] | 32 | 	long long ll; | 
 | 33 | 	int mfn_abs; | 
 | 34 | 	unsigned int mfi, mfn, mfd, pd; | 
 | 35 | 	u32 reg; | 
 | 36 | 	unsigned long rate; | 
| Sascha Hauer | 2af9e6d | 2012-03-09 09:11:55 +0100 | [diff] [blame] | 37 |  | 
| Sascha Hauer | a6dd3c8 | 2012-09-11 08:40:38 +0200 | [diff] [blame] | 38 | 	reg = readl(pll->base); | 
 | 39 |  | 
 | 40 | 	/* | 
 | 41 | 	 * Get the resulting clock rate from a PLL register value and the input | 
 | 42 | 	 * frequency. PLLs with this register layout can be found on i.MX1, | 
 | 43 | 	 * i.MX21, i.MX27 and i,MX31 | 
 | 44 | 	 * | 
 | 45 | 	 *                  mfi + mfn / (mfd + 1) | 
 | 46 | 	 *  f = 2 * f_ref * -------------------- | 
 | 47 | 	 *                        pd + 1 | 
 | 48 | 	 */ | 
 | 49 |  | 
 | 50 | 	mfi = (reg >> 10) & 0xf; | 
 | 51 | 	mfn = reg & 0x3ff; | 
 | 52 | 	mfd = (reg >> 16) & 0x3ff; | 
 | 53 | 	pd =  (reg >> 26) & 0xf; | 
 | 54 |  | 
 | 55 | 	mfi = mfi <= 5 ? 5 : mfi; | 
 | 56 |  | 
 | 57 | 	mfn_abs = mfn; | 
 | 58 |  | 
 | 59 | 	/* | 
 | 60 | 	 * On all i.MXs except i.MX1 and i.MX21 mfn is a 10bit | 
 | 61 | 	 * 2's complements number | 
 | 62 | 	 */ | 
 | 63 | 	if (!cpu_is_mx1() && !cpu_is_mx21() && mfn >= 0x200) | 
 | 64 | 		mfn_abs = 0x400 - mfn; | 
 | 65 |  | 
 | 66 | 	rate = parent_rate * 2; | 
 | 67 | 	rate /= pd + 1; | 
 | 68 |  | 
 | 69 | 	ll = (unsigned long long)rate * mfn_abs; | 
 | 70 |  | 
 | 71 | 	do_div(ll, mfd + 1); | 
 | 72 |  | 
 | 73 | 	if (!cpu_is_mx1() && !cpu_is_mx21() && mfn >= 0x200) | 
 | 74 | 		ll = -ll; | 
 | 75 |  | 
 | 76 | 	ll = (rate * mfi) + ll; | 
 | 77 |  | 
 | 78 | 	return ll; | 
| Sascha Hauer | 2af9e6d | 2012-03-09 09:11:55 +0100 | [diff] [blame] | 79 | } | 
 | 80 |  | 
| Fabio Estevam | e9d8ab8 | 2013-03-25 09:20:33 -0300 | [diff] [blame] | 81 | static struct clk_ops clk_pllv1_ops = { | 
| Sascha Hauer | 2af9e6d | 2012-03-09 09:11:55 +0100 | [diff] [blame] | 82 | 	.recalc_rate = clk_pllv1_recalc_rate, | 
 | 83 | }; | 
 | 84 |  | 
 | 85 | struct clk *imx_clk_pllv1(const char *name, const char *parent, | 
 | 86 | 		void __iomem *base) | 
 | 87 | { | 
 | 88 | 	struct clk_pllv1 *pll; | 
 | 89 | 	struct clk *clk; | 
 | 90 | 	struct clk_init_data init; | 
 | 91 |  | 
 | 92 | 	pll = kmalloc(sizeof(*pll), GFP_KERNEL); | 
 | 93 | 	if (!pll) | 
 | 94 | 		return ERR_PTR(-ENOMEM); | 
 | 95 |  | 
 | 96 | 	pll->base = base; | 
 | 97 |  | 
 | 98 | 	init.name = name; | 
 | 99 | 	init.ops = &clk_pllv1_ops; | 
 | 100 | 	init.flags = 0; | 
 | 101 | 	init.parent_names = &parent; | 
 | 102 | 	init.num_parents = 1; | 
 | 103 |  | 
 | 104 | 	pll->hw.init = &init; | 
 | 105 |  | 
 | 106 | 	clk = clk_register(NULL, &pll->hw); | 
 | 107 | 	if (IS_ERR(clk)) | 
 | 108 | 		kfree(pll); | 
 | 109 |  | 
 | 110 | 	return clk; | 
 | 111 | } |