diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-05-12 18:11:06 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-05-12 18:11:06 -0400 |
commit | eae0185a9677d3ff0c1781ee196f2ef42deb0ea1 (patch) | |
tree | 15ed6ba564cd04b4ac7235f85ea7489d4eeaaa9b /drivers/clk | |
parent | 93c6d8927fa692faef3d7d945bd4fe84b0185ad4 (diff) | |
parent | 5df33a62c4a028d6fc7f2dcc159827d09b7334b8 (diff) |
Merge branch 'spear/clock' into next/clock
Viresh Kumar <viresh.kumar@st.com> writes:
This is rebased over a (merge of Mike's/clk-next & SPEAr's DT) + Russell's
patch: CLKDEV: provide helpers for common clock framework rebased over them.
* spear/clock:
SPEAr: Switch to common clock framework
SPEAr: Call clk_prepare() before calling clk_enable
SPEAr: clk: Add General Purpose Timer Synthesizer clock
SPEAr: clk: Add Fractional Synthesizer clock
SPEAr: clk: Add Auxiliary Synthesizer clock
SPEAr: clk: Add VCO-PLL Synthesizer clock
Conflicts:
drivers/clk/Makefile
[Arnd: rebased again without the spear/dt branch]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/Makefile | 3 | ||||
-rw-r--r-- | drivers/clk/spear/Makefile | 8 | ||||
-rw-r--r-- | drivers/clk/spear/clk-aux-synth.c | 198 | ||||
-rw-r--r-- | drivers/clk/spear/clk-frac-synth.c | 165 | ||||
-rw-r--r-- | drivers/clk/spear/clk-gpt-synth.c | 154 | ||||
-rw-r--r-- | drivers/clk/spear/clk-vco-pll.c | 363 | ||||
-rw-r--r-- | drivers/clk/spear/clk.c | 36 | ||||
-rw-r--r-- | drivers/clk/spear/clk.h | 134 | ||||
-rw-r--r-- | drivers/clk/spear/spear3xx_clock.c | 612 | ||||
-rw-r--r-- | drivers/clk/spear/spear6xx_clock.c | 342 |
10 files changed, 2014 insertions, 1 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 4a5bdbc3038..b9a5158a30b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -2,5 +2,6 @@ | |||
2 | obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o | 2 | obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o |
3 | obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ | 3 | obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ |
4 | clk-mux.o clk-divider.o clk-fixed-factor.o | 4 | clk-mux.o clk-divider.o clk-fixed-factor.o |
5 | 5 | # SoCs specific | |
6 | obj-$(CONFIG_ARCH_MXS) += mxs/ | 6 | obj-$(CONFIG_ARCH_MXS) += mxs/ |
7 | obj-$(CONFIG_PLAT_SPEAR) += spear/ | ||
diff --git a/drivers/clk/spear/Makefile b/drivers/clk/spear/Makefile new file mode 100644 index 00000000000..335886049c8 --- /dev/null +++ b/drivers/clk/spear/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # SPEAr Clock specific Makefile | ||
3 | # | ||
4 | |||
5 | obj-y += clk.o clk-aux-synth.o clk-frac-synth.o clk-gpt-synth.o clk-vco-pll.o | ||
6 | |||
7 | obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx_clock.o | ||
8 | obj-$(CONFIG_ARCH_SPEAR6XX) += spear6xx_clock.o | ||
diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c new file mode 100644 index 00000000000..af34074e702 --- /dev/null +++ b/drivers/clk/spear/clk-aux-synth.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * Auxiliary Synthesizer clock implementation | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "clk-aux-synth: " fmt | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | /* | ||
21 | * DOC: Auxiliary Synthesizer clock | ||
22 | * | ||
23 | * Aux synth gives rate for different values of eq, x and y | ||
24 | * | ||
25 | * Fout from synthesizer can be given from two equations: | ||
26 | * Fout1 = (Fin * X/Y)/2 EQ1 | ||
27 | * Fout2 = Fin * X/Y EQ2 | ||
28 | */ | ||
29 | |||
30 | #define to_clk_aux(_hw) container_of(_hw, struct clk_aux, hw) | ||
31 | |||
32 | static struct aux_clk_masks default_aux_masks = { | ||
33 | .eq_sel_mask = AUX_EQ_SEL_MASK, | ||
34 | .eq_sel_shift = AUX_EQ_SEL_SHIFT, | ||
35 | .eq1_mask = AUX_EQ1_SEL, | ||
36 | .eq2_mask = AUX_EQ2_SEL, | ||
37 | .xscale_sel_mask = AUX_XSCALE_MASK, | ||
38 | .xscale_sel_shift = AUX_XSCALE_SHIFT, | ||
39 | .yscale_sel_mask = AUX_YSCALE_MASK, | ||
40 | .yscale_sel_shift = AUX_YSCALE_SHIFT, | ||
41 | .enable_bit = AUX_SYNT_ENB, | ||
42 | }; | ||
43 | |||
44 | static unsigned long aux_calc_rate(struct clk_hw *hw, unsigned long prate, | ||
45 | int index) | ||
46 | { | ||
47 | struct clk_aux *aux = to_clk_aux(hw); | ||
48 | struct aux_rate_tbl *rtbl = aux->rtbl; | ||
49 | u8 eq = rtbl[index].eq ? 1 : 2; | ||
50 | |||
51 | return (((prate / 10000) * rtbl[index].xscale) / | ||
52 | (rtbl[index].yscale * eq)) * 10000; | ||
53 | } | ||
54 | |||
55 | static long clk_aux_round_rate(struct clk_hw *hw, unsigned long drate, | ||
56 | unsigned long *prate) | ||
57 | { | ||
58 | struct clk_aux *aux = to_clk_aux(hw); | ||
59 | int unused; | ||
60 | |||
61 | return clk_round_rate_index(hw, drate, *prate, aux_calc_rate, | ||
62 | aux->rtbl_cnt, &unused); | ||
63 | } | ||
64 | |||
65 | static unsigned long clk_aux_recalc_rate(struct clk_hw *hw, | ||
66 | unsigned long parent_rate) | ||
67 | { | ||
68 | struct clk_aux *aux = to_clk_aux(hw); | ||
69 | unsigned int num = 1, den = 1, val, eqn; | ||
70 | unsigned long flags = 0; | ||
71 | |||
72 | if (aux->lock) | ||
73 | spin_lock_irqsave(aux->lock, flags); | ||
74 | |||
75 | val = readl_relaxed(aux->reg); | ||
76 | |||
77 | if (aux->lock) | ||
78 | spin_unlock_irqrestore(aux->lock, flags); | ||
79 | |||
80 | eqn = (val >> aux->masks->eq_sel_shift) & aux->masks->eq_sel_mask; | ||
81 | if (eqn == aux->masks->eq1_mask) | ||
82 | den = 2; | ||
83 | |||
84 | /* calculate numerator */ | ||
85 | num = (val >> aux->masks->xscale_sel_shift) & | ||
86 | aux->masks->xscale_sel_mask; | ||
87 | |||
88 | /* calculate denominator */ | ||
89 | den *= (val >> aux->masks->yscale_sel_shift) & | ||
90 | aux->masks->yscale_sel_mask; | ||
91 | |||
92 | if (!den) | ||
93 | return 0; | ||
94 | |||
95 | return (((parent_rate / 10000) * num) / den) * 10000; | ||
96 | } | ||
97 | |||
98 | /* Configures new clock rate of aux */ | ||
99 | static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate, | ||
100 | unsigned long prate) | ||
101 | { | ||
102 | struct clk_aux *aux = to_clk_aux(hw); | ||
103 | struct aux_rate_tbl *rtbl = aux->rtbl; | ||
104 | unsigned long val, flags = 0; | ||
105 | int i; | ||
106 | |||
107 | clk_round_rate_index(hw, drate, prate, aux_calc_rate, aux->rtbl_cnt, | ||
108 | &i); | ||
109 | |||
110 | if (aux->lock) | ||
111 | spin_lock_irqsave(aux->lock, flags); | ||
112 | |||
113 | val = readl_relaxed(aux->reg) & | ||
114 | ~(aux->masks->eq_sel_mask << aux->masks->eq_sel_shift); | ||
115 | val |= (rtbl[i].eq & aux->masks->eq_sel_mask) << | ||
116 | aux->masks->eq_sel_shift; | ||
117 | val &= ~(aux->masks->xscale_sel_mask << aux->masks->xscale_sel_shift); | ||
118 | val |= (rtbl[i].xscale & aux->masks->xscale_sel_mask) << | ||
119 | aux->masks->xscale_sel_shift; | ||
120 | val &= ~(aux->masks->yscale_sel_mask << aux->masks->yscale_sel_shift); | ||
121 | val |= (rtbl[i].yscale & aux->masks->yscale_sel_mask) << | ||
122 | aux->masks->yscale_sel_shift; | ||
123 | writel_relaxed(val, aux->reg); | ||
124 | |||
125 | if (aux->lock) | ||
126 | spin_unlock_irqrestore(aux->lock, flags); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static struct clk_ops clk_aux_ops = { | ||
132 | .recalc_rate = clk_aux_recalc_rate, | ||
133 | .round_rate = clk_aux_round_rate, | ||
134 | .set_rate = clk_aux_set_rate, | ||
135 | }; | ||
136 | |||
137 | struct clk *clk_register_aux(const char *aux_name, const char *gate_name, | ||
138 | const char *parent_name, unsigned long flags, void __iomem *reg, | ||
139 | struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, | ||
140 | u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk) | ||
141 | { | ||
142 | struct clk_aux *aux; | ||
143 | struct clk_init_data init; | ||
144 | struct clk *clk; | ||
145 | |||
146 | if (!aux_name || !parent_name || !reg || !rtbl || !rtbl_cnt) { | ||
147 | pr_err("Invalid arguments passed"); | ||
148 | return ERR_PTR(-EINVAL); | ||
149 | } | ||
150 | |||
151 | aux = kzalloc(sizeof(*aux), GFP_KERNEL); | ||
152 | if (!aux) { | ||
153 | pr_err("could not allocate aux clk\n"); | ||
154 | return ERR_PTR(-ENOMEM); | ||
155 | } | ||
156 | |||
157 | /* struct clk_aux assignments */ | ||
158 | if (!masks) | ||
159 | aux->masks = &default_aux_masks; | ||
160 | else | ||
161 | aux->masks = masks; | ||
162 | |||
163 | aux->reg = reg; | ||
164 | aux->rtbl = rtbl; | ||
165 | aux->rtbl_cnt = rtbl_cnt; | ||
166 | aux->lock = lock; | ||
167 | aux->hw.init = &init; | ||
168 | |||
169 | init.name = aux_name; | ||
170 | init.ops = &clk_aux_ops; | ||
171 | init.flags = flags; | ||
172 | init.parent_names = &parent_name; | ||
173 | init.num_parents = 1; | ||
174 | |||
175 | clk = clk_register(NULL, &aux->hw); | ||
176 | if (IS_ERR_OR_NULL(clk)) | ||
177 | goto free_aux; | ||
178 | |||
179 | if (gate_name) { | ||
180 | struct clk *tgate_clk; | ||
181 | |||
182 | tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 0, reg, | ||
183 | aux->masks->enable_bit, 0, lock); | ||
184 | if (IS_ERR_OR_NULL(tgate_clk)) | ||
185 | goto free_aux; | ||
186 | |||
187 | if (gate_clk) | ||
188 | *gate_clk = tgate_clk; | ||
189 | } | ||
190 | |||
191 | return clk; | ||
192 | |||
193 | free_aux: | ||
194 | kfree(aux); | ||
195 | pr_err("clk register failed\n"); | ||
196 | |||
197 | return NULL; | ||
198 | } | ||
diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c new file mode 100644 index 00000000000..4dbdb3fe18e --- /dev/null +++ b/drivers/clk/spear/clk-frac-synth.c | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * Fractional Synthesizer clock implementation | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "clk-frac-synth: " fmt | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | #define DIV_FACTOR_MASK 0x1FFFF | ||
21 | |||
22 | /* | ||
23 | * DOC: Fractional Synthesizer clock | ||
24 | * | ||
25 | * Fout from synthesizer can be given from below equation: | ||
26 | * | ||
27 | * Fout= Fin/2*div (division factor) | ||
28 | * div is 17 bits:- | ||
29 | * 0-13 (fractional part) | ||
30 | * 14-16 (integer part) | ||
31 | * div is (16-14 bits).(13-0 bits) (in binary) | ||
32 | * | ||
33 | * Fout = Fin/(2 * div) | ||
34 | * Fout = ((Fin / 10000)/(2 * div)) * 10000 | ||
35 | * Fout = (2^14 * (Fin / 10000)/(2^14 * (2 * div))) * 10000 | ||
36 | * Fout = (((Fin / 10000) << 14)/(2 * (div << 14))) * 10000 | ||
37 | * | ||
38 | * div << 14 simply 17 bit value written at register. | ||
39 | * Max error due to scaling down by 10000 is 10 KHz | ||
40 | */ | ||
41 | |||
42 | #define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw) | ||
43 | |||
44 | static unsigned long frac_calc_rate(struct clk_hw *hw, unsigned long prate, | ||
45 | int index) | ||
46 | { | ||
47 | struct clk_frac *frac = to_clk_frac(hw); | ||
48 | struct frac_rate_tbl *rtbl = frac->rtbl; | ||
49 | |||
50 | prate /= 10000; | ||
51 | prate <<= 14; | ||
52 | prate /= (2 * rtbl[index].div); | ||
53 | prate *= 10000; | ||
54 | |||
55 | return prate; | ||
56 | } | ||
57 | |||
58 | static long clk_frac_round_rate(struct clk_hw *hw, unsigned long drate, | ||
59 | unsigned long *prate) | ||
60 | { | ||
61 | struct clk_frac *frac = to_clk_frac(hw); | ||
62 | int unused; | ||
63 | |||
64 | return clk_round_rate_index(hw, drate, *prate, frac_calc_rate, | ||
65 | frac->rtbl_cnt, &unused); | ||
66 | } | ||
67 | |||
68 | static unsigned long clk_frac_recalc_rate(struct clk_hw *hw, | ||
69 | unsigned long parent_rate) | ||
70 | { | ||
71 | struct clk_frac *frac = to_clk_frac(hw); | ||
72 | unsigned long flags = 0; | ||
73 | unsigned int div = 1, val; | ||
74 | |||
75 | if (frac->lock) | ||
76 | spin_lock_irqsave(frac->lock, flags); | ||
77 | |||
78 | val = readl_relaxed(frac->reg); | ||
79 | |||
80 | if (frac->lock) | ||
81 | spin_unlock_irqrestore(frac->lock, flags); | ||
82 | |||
83 | div = val & DIV_FACTOR_MASK; | ||
84 | |||
85 | if (!div) | ||
86 | return 0; | ||
87 | |||
88 | parent_rate = parent_rate / 10000; | ||
89 | |||
90 | parent_rate = (parent_rate << 14) / (2 * div); | ||
91 | return parent_rate * 10000; | ||
92 | } | ||
93 | |||
94 | /* Configures new clock rate of frac */ | ||
95 | static int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate, | ||
96 | unsigned long prate) | ||
97 | { | ||
98 | struct clk_frac *frac = to_clk_frac(hw); | ||
99 | struct frac_rate_tbl *rtbl = frac->rtbl; | ||
100 | unsigned long flags = 0, val; | ||
101 | int i; | ||
102 | |||
103 | clk_round_rate_index(hw, drate, prate, frac_calc_rate, frac->rtbl_cnt, | ||
104 | &i); | ||
105 | |||
106 | if (frac->lock) | ||
107 | spin_lock_irqsave(frac->lock, flags); | ||
108 | |||
109 | val = readl_relaxed(frac->reg) & ~DIV_FACTOR_MASK; | ||
110 | val |= rtbl[i].div & DIV_FACTOR_MASK; | ||
111 | writel_relaxed(val, frac->reg); | ||
112 | |||
113 | if (frac->lock) | ||
114 | spin_unlock_irqrestore(frac->lock, flags); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | struct clk_ops clk_frac_ops = { | ||
120 | .recalc_rate = clk_frac_recalc_rate, | ||
121 | .round_rate = clk_frac_round_rate, | ||
122 | .set_rate = clk_frac_set_rate, | ||
123 | }; | ||
124 | |||
125 | struct clk *clk_register_frac(const char *name, const char *parent_name, | ||
126 | unsigned long flags, void __iomem *reg, | ||
127 | struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock) | ||
128 | { | ||
129 | struct clk_init_data init; | ||
130 | struct clk_frac *frac; | ||
131 | struct clk *clk; | ||
132 | |||
133 | if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { | ||
134 | pr_err("Invalid arguments passed"); | ||
135 | return ERR_PTR(-EINVAL); | ||
136 | } | ||
137 | |||
138 | frac = kzalloc(sizeof(*frac), GFP_KERNEL); | ||
139 | if (!frac) { | ||
140 | pr_err("could not allocate frac clk\n"); | ||
141 | return ERR_PTR(-ENOMEM); | ||
142 | } | ||
143 | |||
144 | /* struct clk_frac assignments */ | ||
145 | frac->reg = reg; | ||
146 | frac->rtbl = rtbl; | ||
147 | frac->rtbl_cnt = rtbl_cnt; | ||
148 | frac->lock = lock; | ||
149 | frac->hw.init = &init; | ||
150 | |||
151 | init.name = name; | ||
152 | init.ops = &clk_frac_ops; | ||
153 | init.flags = flags; | ||
154 | init.parent_names = &parent_name; | ||
155 | init.num_parents = 1; | ||
156 | |||
157 | clk = clk_register(NULL, &frac->hw); | ||
158 | if (!IS_ERR_OR_NULL(clk)) | ||
159 | return clk; | ||
160 | |||
161 | pr_err("clk register failed\n"); | ||
162 | kfree(frac); | ||
163 | |||
164 | return NULL; | ||
165 | } | ||
diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c new file mode 100644 index 00000000000..b471c9762a9 --- /dev/null +++ b/drivers/clk/spear/clk-gpt-synth.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * General Purpose Timer Synthesizer clock implementation | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "clk-gpt-synth: " fmt | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | #define GPT_MSCALE_MASK 0xFFF | ||
21 | #define GPT_NSCALE_SHIFT 12 | ||
22 | #define GPT_NSCALE_MASK 0xF | ||
23 | |||
24 | /* | ||
25 | * DOC: General Purpose Timer Synthesizer clock | ||
26 | * | ||
27 | * Calculates gpt synth clk rate for different values of mscale and nscale | ||
28 | * | ||
29 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) | ||
30 | */ | ||
31 | |||
32 | #define to_clk_gpt(_hw) container_of(_hw, struct clk_gpt, hw) | ||
33 | |||
34 | static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate, | ||
35 | int index) | ||
36 | { | ||
37 | struct clk_gpt *gpt = to_clk_gpt(hw); | ||
38 | struct gpt_rate_tbl *rtbl = gpt->rtbl; | ||
39 | |||
40 | prate /= ((1 << (rtbl[index].nscale + 1)) * (rtbl[index].mscale + 1)); | ||
41 | |||
42 | return prate; | ||
43 | } | ||
44 | |||
45 | static long clk_gpt_round_rate(struct clk_hw *hw, unsigned long drate, | ||
46 | unsigned long *prate) | ||
47 | { | ||
48 | struct clk_gpt *gpt = to_clk_gpt(hw); | ||
49 | int unused; | ||
50 | |||
51 | return clk_round_rate_index(hw, drate, *prate, gpt_calc_rate, | ||
52 | gpt->rtbl_cnt, &unused); | ||
53 | } | ||
54 | |||
55 | static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw, | ||
56 | unsigned long parent_rate) | ||
57 | { | ||
58 | struct clk_gpt *gpt = to_clk_gpt(hw); | ||
59 | unsigned long flags = 0; | ||
60 | unsigned int div = 1, val; | ||
61 | |||
62 | if (gpt->lock) | ||
63 | spin_lock_irqsave(gpt->lock, flags); | ||
64 | |||
65 | val = readl_relaxed(gpt->reg); | ||
66 | |||
67 | if (gpt->lock) | ||
68 | spin_unlock_irqrestore(gpt->lock, flags); | ||
69 | |||
70 | div += val & GPT_MSCALE_MASK; | ||
71 | div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1); | ||
72 | |||
73 | if (!div) | ||
74 | return 0; | ||
75 | |||
76 | return parent_rate / div; | ||
77 | } | ||
78 | |||
79 | /* Configures new clock rate of gpt */ | ||
80 | static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate, | ||
81 | unsigned long prate) | ||
82 | { | ||
83 | struct clk_gpt *gpt = to_clk_gpt(hw); | ||
84 | struct gpt_rate_tbl *rtbl = gpt->rtbl; | ||
85 | unsigned long flags = 0, val; | ||
86 | int i; | ||
87 | |||
88 | clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt, | ||
89 | &i); | ||
90 | |||
91 | if (gpt->lock) | ||
92 | spin_lock_irqsave(gpt->lock, flags); | ||
93 | |||
94 | val = readl(gpt->reg) & ~GPT_MSCALE_MASK; | ||
95 | val &= ~(GPT_NSCALE_MASK << GPT_NSCALE_SHIFT); | ||
96 | |||
97 | val |= rtbl[i].mscale & GPT_MSCALE_MASK; | ||
98 | val |= (rtbl[i].nscale & GPT_NSCALE_MASK) << GPT_NSCALE_SHIFT; | ||
99 | |||
100 | writel_relaxed(val, gpt->reg); | ||
101 | |||
102 | if (gpt->lock) | ||
103 | spin_unlock_irqrestore(gpt->lock, flags); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static struct clk_ops clk_gpt_ops = { | ||
109 | .recalc_rate = clk_gpt_recalc_rate, | ||
110 | .round_rate = clk_gpt_round_rate, | ||
111 | .set_rate = clk_gpt_set_rate, | ||
112 | }; | ||
113 | |||
114 | struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned | ||
115 | long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8 | ||
116 | rtbl_cnt, spinlock_t *lock) | ||
117 | { | ||
118 | struct clk_init_data init; | ||
119 | struct clk_gpt *gpt; | ||
120 | struct clk *clk; | ||
121 | |||
122 | if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { | ||
123 | pr_err("Invalid arguments passed"); | ||
124 | return ERR_PTR(-EINVAL); | ||
125 | } | ||
126 | |||
127 | gpt = kzalloc(sizeof(*gpt), GFP_KERNEL); | ||
128 | if (!gpt) { | ||
129 | pr_err("could not allocate gpt clk\n"); | ||
130 | return ERR_PTR(-ENOMEM); | ||
131 | } | ||
132 | |||
133 | /* struct clk_gpt assignments */ | ||
134 | gpt->reg = reg; | ||
135 | gpt->rtbl = rtbl; | ||
136 | gpt->rtbl_cnt = rtbl_cnt; | ||
137 | gpt->lock = lock; | ||
138 | gpt->hw.init = &init; | ||
139 | |||
140 | init.name = name; | ||
141 | init.ops = &clk_gpt_ops; | ||
142 | init.flags = flags; | ||
143 | init.parent_names = &parent_name; | ||
144 | init.num_parents = 1; | ||
145 | |||
146 | clk = clk_register(NULL, &gpt->hw); | ||
147 | if (!IS_ERR_OR_NULL(clk)) | ||
148 | return clk; | ||
149 | |||
150 | pr_err("clk register failed\n"); | ||
151 | kfree(gpt); | ||
152 | |||
153 | return NULL; | ||
154 | } | ||
diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c new file mode 100644 index 00000000000..dcd4bdf4b0d --- /dev/null +++ b/drivers/clk/spear/clk-vco-pll.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * VCO-PLL clock implementation | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "clk-vco-pll: " fmt | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | /* | ||
21 | * DOC: VCO-PLL clock | ||
22 | * | ||
23 | * VCO and PLL rate are derived from following equations: | ||
24 | * | ||
25 | * In normal mode | ||
26 | * vco = (2 * M[15:8] * Fin)/N | ||
27 | * | ||
28 | * In Dithered mode | ||
29 | * vco = (2 * M[15:0] * Fin)/(256 * N) | ||
30 | * | ||
31 | * pll_rate = pll/2^p | ||
32 | * | ||
33 | * vco and pll are very closely bound to each other, "vco needs to program: | ||
34 | * mode, m & n" and "pll needs to program p", both share common enable/disable | ||
35 | * logic. | ||
36 | * | ||
37 | * clk_register_vco_pll() registers instances of both vco & pll. | ||
38 | * CLK_SET_RATE_PARENT flag is forced for pll, as it will always pass its | ||
39 | * set_rate to vco. A single rate table exists for both the clocks, which | ||
40 | * configures m, n and p. | ||
41 | */ | ||
42 | |||
43 | /* PLL_CTR register masks */ | ||
44 | #define PLL_MODE_NORMAL 0 | ||
45 | #define PLL_MODE_FRACTION 1 | ||
46 | #define PLL_MODE_DITH_DSM 2 | ||
47 | #define PLL_MODE_DITH_SSM 3 | ||
48 | #define PLL_MODE_MASK 3 | ||
49 | #define PLL_MODE_SHIFT 3 | ||
50 | #define PLL_ENABLE 2 | ||
51 | |||
52 | #define PLL_LOCK_SHIFT 0 | ||
53 | #define PLL_LOCK_MASK 1 | ||
54 | |||
55 | /* PLL FRQ register masks */ | ||
56 | #define PLL_NORM_FDBK_M_MASK 0xFF | ||
57 | #define PLL_NORM_FDBK_M_SHIFT 24 | ||
58 | #define PLL_DITH_FDBK_M_MASK 0xFFFF | ||
59 | #define PLL_DITH_FDBK_M_SHIFT 16 | ||
60 | #define PLL_DIV_P_MASK 0x7 | ||
61 | #define PLL_DIV_P_SHIFT 8 | ||
62 | #define PLL_DIV_N_MASK 0xFF | ||
63 | #define PLL_DIV_N_SHIFT 0 | ||
64 | |||
65 | #define to_clk_vco(_hw) container_of(_hw, struct clk_vco, hw) | ||
66 | #define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw) | ||
67 | |||
68 | /* Calculates pll clk rate for specific value of mode, m, n and p */ | ||
69 | static unsigned long pll_calc_rate(struct pll_rate_tbl *rtbl, | ||
70 | unsigned long prate, int index, unsigned long *pll_rate) | ||
71 | { | ||
72 | unsigned long rate = prate; | ||
73 | unsigned int mode; | ||
74 | |||
75 | mode = rtbl[index].mode ? 256 : 1; | ||
76 | rate = (((2 * rate / 10000) * rtbl[index].m) / (mode * rtbl[index].n)); | ||
77 | |||
78 | if (pll_rate) | ||
79 | *pll_rate = (rate / (1 << rtbl[index].p)) * 10000; | ||
80 | |||
81 | return rate * 10000; | ||
82 | } | ||
83 | |||
84 | static long clk_pll_round_rate_index(struct clk_hw *hw, unsigned long drate, | ||
85 | unsigned long *prate, int *index) | ||
86 | { | ||
87 | struct clk_pll *pll = to_clk_pll(hw); | ||
88 | unsigned long prev_rate, vco_prev_rate, rate = 0; | ||
89 | unsigned long vco_parent_rate = | ||
90 | __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk))); | ||
91 | |||
92 | if (!prate) { | ||
93 | pr_err("%s: prate is must for pll clk\n", __func__); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | for (*index = 0; *index < pll->vco->rtbl_cnt; (*index)++) { | ||
98 | prev_rate = rate; | ||
99 | vco_prev_rate = *prate; | ||
100 | *prate = pll_calc_rate(pll->vco->rtbl, vco_parent_rate, *index, | ||
101 | &rate); | ||
102 | if (drate < rate) { | ||
103 | /* previous clock was best */ | ||
104 | if (*index) { | ||
105 | rate = prev_rate; | ||
106 | *prate = vco_prev_rate; | ||
107 | (*index)--; | ||
108 | } | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | return rate; | ||
114 | } | ||
115 | |||
116 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long drate, | ||
117 | unsigned long *prate) | ||
118 | { | ||
119 | int unused; | ||
120 | |||
121 | return clk_pll_round_rate_index(hw, drate, prate, &unused); | ||
122 | } | ||
123 | |||
124 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long | ||
125 | parent_rate) | ||
126 | { | ||
127 | struct clk_pll *pll = to_clk_pll(hw); | ||
128 | unsigned long flags = 0; | ||
129 | unsigned int p; | ||
130 | |||
131 | if (pll->vco->lock) | ||
132 | spin_lock_irqsave(pll->vco->lock, flags); | ||
133 | |||
134 | p = readl_relaxed(pll->vco->cfg_reg); | ||
135 | |||
136 | if (pll->vco->lock) | ||
137 | spin_unlock_irqrestore(pll->vco->lock, flags); | ||
138 | |||
139 | p = (p >> PLL_DIV_P_SHIFT) & PLL_DIV_P_MASK; | ||
140 | |||
141 | return parent_rate / (1 << p); | ||
142 | } | ||
143 | |||
144 | static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, | ||
145 | unsigned long prate) | ||
146 | { | ||
147 | struct clk_pll *pll = to_clk_pll(hw); | ||
148 | struct pll_rate_tbl *rtbl = pll->vco->rtbl; | ||
149 | unsigned long flags = 0, val; | ||
150 | int i; | ||
151 | |||
152 | clk_pll_round_rate_index(hw, drate, NULL, &i); | ||
153 | |||
154 | if (pll->vco->lock) | ||
155 | spin_lock_irqsave(pll->vco->lock, flags); | ||
156 | |||
157 | val = readl_relaxed(pll->vco->cfg_reg); | ||
158 | val &= ~(PLL_DIV_P_MASK << PLL_DIV_P_SHIFT); | ||
159 | val |= (rtbl[i].p & PLL_DIV_P_MASK) << PLL_DIV_P_SHIFT; | ||
160 | writel_relaxed(val, pll->vco->cfg_reg); | ||
161 | |||
162 | if (pll->vco->lock) | ||
163 | spin_unlock_irqrestore(pll->vco->lock, flags); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static struct clk_ops clk_pll_ops = { | ||
169 | .recalc_rate = clk_pll_recalc_rate, | ||
170 | .round_rate = clk_pll_round_rate, | ||
171 | .set_rate = clk_pll_set_rate, | ||
172 | }; | ||
173 | |||
174 | static inline unsigned long vco_calc_rate(struct clk_hw *hw, | ||
175 | unsigned long prate, int index) | ||
176 | { | ||
177 | struct clk_vco *vco = to_clk_vco(hw); | ||
178 | |||
179 | return pll_calc_rate(vco->rtbl, prate, index, NULL); | ||
180 | } | ||
181 | |||
182 | static long clk_vco_round_rate(struct clk_hw *hw, unsigned long drate, | ||
183 | unsigned long *prate) | ||
184 | { | ||
185 | struct clk_vco *vco = to_clk_vco(hw); | ||
186 | int unused; | ||
187 | |||
188 | return clk_round_rate_index(hw, drate, *prate, vco_calc_rate, | ||
189 | vco->rtbl_cnt, &unused); | ||
190 | } | ||
191 | |||
192 | static unsigned long clk_vco_recalc_rate(struct clk_hw *hw, | ||
193 | unsigned long parent_rate) | ||
194 | { | ||
195 | struct clk_vco *vco = to_clk_vco(hw); | ||
196 | unsigned long flags = 0; | ||
197 | unsigned int num = 2, den = 0, val, mode = 0; | ||
198 | |||
199 | if (vco->lock) | ||
200 | spin_lock_irqsave(vco->lock, flags); | ||
201 | |||
202 | mode = (readl_relaxed(vco->mode_reg) >> PLL_MODE_SHIFT) & PLL_MODE_MASK; | ||
203 | |||
204 | val = readl_relaxed(vco->cfg_reg); | ||
205 | |||
206 | if (vco->lock) | ||
207 | spin_unlock_irqrestore(vco->lock, flags); | ||
208 | |||
209 | den = (val >> PLL_DIV_N_SHIFT) & PLL_DIV_N_MASK; | ||
210 | |||
211 | /* calculate numerator & denominator */ | ||
212 | if (!mode) { | ||
213 | /* Normal mode */ | ||
214 | num *= (val >> PLL_NORM_FDBK_M_SHIFT) & PLL_NORM_FDBK_M_MASK; | ||
215 | } else { | ||
216 | /* Dithered mode */ | ||
217 | num *= (val >> PLL_DITH_FDBK_M_SHIFT) & PLL_DITH_FDBK_M_MASK; | ||
218 | den *= 256; | ||
219 | } | ||
220 | |||
221 | if (!den) { | ||
222 | WARN(1, "%s: denominator can't be zero\n", __func__); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | return (((parent_rate / 10000) * num) / den) * 10000; | ||
227 | } | ||
228 | |||
229 | /* Configures new clock rate of vco */ | ||
230 | static int clk_vco_set_rate(struct clk_hw *hw, unsigned long drate, | ||
231 | unsigned long prate) | ||
232 | { | ||
233 | struct clk_vco *vco = to_clk_vco(hw); | ||
234 | struct pll_rate_tbl *rtbl = vco->rtbl; | ||
235 | unsigned long flags = 0, val; | ||
236 | int i; | ||
237 | |||
238 | clk_round_rate_index(hw, drate, prate, vco_calc_rate, vco->rtbl_cnt, | ||
239 | &i); | ||
240 | |||
241 | if (vco->lock) | ||
242 | spin_lock_irqsave(vco->lock, flags); | ||
243 | |||
244 | val = readl_relaxed(vco->mode_reg); | ||
245 | val &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT); | ||
246 | val |= (rtbl[i].mode & PLL_MODE_MASK) << PLL_MODE_SHIFT; | ||
247 | writel_relaxed(val, vco->mode_reg); | ||
248 | |||
249 | val = readl_relaxed(vco->cfg_reg); | ||
250 | val &= ~(PLL_DIV_N_MASK << PLL_DIV_N_SHIFT); | ||
251 | val |= (rtbl[i].n & PLL_DIV_N_MASK) << PLL_DIV_N_SHIFT; | ||
252 | |||
253 | val &= ~(PLL_DITH_FDBK_M_MASK << PLL_DITH_FDBK_M_SHIFT); | ||
254 | if (rtbl[i].mode) | ||
255 | val |= (rtbl[i].m & PLL_DITH_FDBK_M_MASK) << | ||
256 | PLL_DITH_FDBK_M_SHIFT; | ||
257 | else | ||
258 | val |= (rtbl[i].m & PLL_NORM_FDBK_M_MASK) << | ||
259 | PLL_NORM_FDBK_M_SHIFT; | ||
260 | |||
261 | writel_relaxed(val, vco->cfg_reg); | ||
262 | |||
263 | if (vco->lock) | ||
264 | spin_unlock_irqrestore(vco->lock, flags); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static struct clk_ops clk_vco_ops = { | ||
270 | .recalc_rate = clk_vco_recalc_rate, | ||
271 | .round_rate = clk_vco_round_rate, | ||
272 | .set_rate = clk_vco_set_rate, | ||
273 | }; | ||
274 | |||
275 | struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, | ||
276 | const char *vco_gate_name, const char *parent_name, | ||
277 | unsigned long flags, void __iomem *mode_reg, void __iomem | ||
278 | *cfg_reg, struct pll_rate_tbl *rtbl, u8 rtbl_cnt, | ||
279 | spinlock_t *lock, struct clk **pll_clk, | ||
280 | struct clk **vco_gate_clk) | ||
281 | { | ||
282 | struct clk_vco *vco; | ||
283 | struct clk_pll *pll; | ||
284 | struct clk *vco_clk, *tpll_clk, *tvco_gate_clk; | ||
285 | struct clk_init_data vco_init, pll_init; | ||
286 | const char **vco_parent_name; | ||
287 | |||
288 | if (!vco_name || !pll_name || !parent_name || !mode_reg || !cfg_reg || | ||
289 | !rtbl || !rtbl_cnt) { | ||
290 | pr_err("Invalid arguments passed"); | ||
291 | return ERR_PTR(-EINVAL); | ||
292 | } | ||
293 | |||
294 | vco = kzalloc(sizeof(*vco), GFP_KERNEL); | ||
295 | if (!vco) { | ||
296 | pr_err("could not allocate vco clk\n"); | ||
297 | return ERR_PTR(-ENOMEM); | ||
298 | } | ||
299 | |||
300 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | ||
301 | if (!pll) { | ||
302 | pr_err("could not allocate pll clk\n"); | ||
303 | goto free_vco; | ||
304 | } | ||
305 | |||
306 | /* struct clk_vco assignments */ | ||
307 | vco->mode_reg = mode_reg; | ||
308 | vco->cfg_reg = cfg_reg; | ||
309 | vco->rtbl = rtbl; | ||
310 | vco->rtbl_cnt = rtbl_cnt; | ||
311 | vco->lock = lock; | ||
312 | vco->hw.init = &vco_init; | ||
313 | |||
314 | pll->vco = vco; | ||
315 | pll->hw.init = &pll_init; | ||
316 | |||
317 | if (vco_gate_name) { | ||
318 | tvco_gate_clk = clk_register_gate(NULL, vco_gate_name, | ||
319 | parent_name, 0, mode_reg, PLL_ENABLE, 0, lock); | ||
320 | if (IS_ERR_OR_NULL(tvco_gate_clk)) | ||
321 | goto free_pll; | ||
322 | |||
323 | if (vco_gate_clk) | ||
324 | *vco_gate_clk = tvco_gate_clk; | ||
325 | vco_parent_name = &vco_gate_name; | ||
326 | } else { | ||
327 | vco_parent_name = &parent_name; | ||
328 | } | ||
329 | |||
330 | vco_init.name = vco_name; | ||
331 | vco_init.ops = &clk_vco_ops; | ||
332 | vco_init.flags = flags; | ||
333 | vco_init.parent_names = vco_parent_name; | ||
334 | vco_init.num_parents = 1; | ||
335 | |||
336 | pll_init.name = pll_name; | ||
337 | pll_init.ops = &clk_pll_ops; | ||
338 | pll_init.flags = CLK_SET_RATE_PARENT; | ||
339 | pll_init.parent_names = &vco_name; | ||
340 | pll_init.num_parents = 1; | ||
341 | |||
342 | vco_clk = clk_register(NULL, &vco->hw); | ||
343 | if (IS_ERR_OR_NULL(vco_clk)) | ||
344 | goto free_pll; | ||
345 | |||
346 | tpll_clk = clk_register(NULL, &pll->hw); | ||
347 | if (IS_ERR_OR_NULL(tpll_clk)) | ||
348 | goto free_pll; | ||
349 | |||
350 | if (pll_clk) | ||
351 | *pll_clk = tpll_clk; | ||
352 | |||
353 | return vco_clk; | ||
354 | |||
355 | free_pll: | ||
356 | kfree(pll); | ||
357 | free_vco: | ||
358 | kfree(vco); | ||
359 | |||
360 | pr_err("Failed to register vco pll clock\n"); | ||
361 | |||
362 | return ERR_PTR(-ENOMEM); | ||
363 | } | ||
diff --git a/drivers/clk/spear/clk.c b/drivers/clk/spear/clk.c new file mode 100644 index 00000000000..376d4e5ff32 --- /dev/null +++ b/drivers/clk/spear/clk.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * SPEAr clk - Common routines | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk-provider.h> | ||
13 | #include <linux/types.h> | ||
14 | #include "clk.h" | ||
15 | |||
16 | long clk_round_rate_index(struct clk_hw *hw, unsigned long drate, | ||
17 | unsigned long parent_rate, clk_calc_rate calc_rate, u8 rtbl_cnt, | ||
18 | int *index) | ||
19 | { | ||
20 | unsigned long prev_rate, rate = 0; | ||
21 | |||
22 | for (*index = 0; *index < rtbl_cnt; (*index)++) { | ||
23 | prev_rate = rate; | ||
24 | rate = calc_rate(hw, parent_rate, *index); | ||
25 | if (drate < rate) { | ||
26 | /* previous clock was best */ | ||
27 | if (*index) { | ||
28 | rate = prev_rate; | ||
29 | (*index)--; | ||
30 | } | ||
31 | break; | ||
32 | } | ||
33 | } | ||
34 | |||
35 | return rate; | ||
36 | } | ||
diff --git a/drivers/clk/spear/clk.h b/drivers/clk/spear/clk.h new file mode 100644 index 00000000000..3321c46a071 --- /dev/null +++ b/drivers/clk/spear/clk.h | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Clock framework definitions for SPEAr platform | ||
3 | * | ||
4 | * Copyright (C) 2012 ST Microelectronics | ||
5 | * Viresh Kumar <viresh.kumar@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #ifndef __SPEAR_CLK_H | ||
13 | #define __SPEAR_CLK_H | ||
14 | |||
15 | #include <linux/clk-provider.h> | ||
16 | #include <linux/spinlock_types.h> | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | /* Auxiliary Synth clk */ | ||
20 | /* Default masks */ | ||
21 | #define AUX_EQ_SEL_SHIFT 30 | ||
22 | #define AUX_EQ_SEL_MASK 1 | ||
23 | #define AUX_EQ1_SEL 0 | ||
24 | #define AUX_EQ2_SEL 1 | ||
25 | #define AUX_XSCALE_SHIFT 16 | ||
26 | #define AUX_XSCALE_MASK 0xFFF | ||
27 | #define AUX_YSCALE_SHIFT 0 | ||
28 | #define AUX_YSCALE_MASK 0xFFF | ||
29 | #define AUX_SYNT_ENB 31 | ||
30 | |||
31 | struct aux_clk_masks { | ||
32 | u32 eq_sel_mask; | ||
33 | u32 eq_sel_shift; | ||
34 | u32 eq1_mask; | ||
35 | u32 eq2_mask; | ||
36 | u32 xscale_sel_mask; | ||
37 | u32 xscale_sel_shift; | ||
38 | u32 yscale_sel_mask; | ||
39 | u32 yscale_sel_shift; | ||
40 | u32 enable_bit; | ||
41 | }; | ||
42 | |||
43 | struct aux_rate_tbl { | ||
44 | u16 xscale; | ||
45 | u16 yscale; | ||
46 | u8 eq; | ||
47 | }; | ||
48 | |||
49 | struct clk_aux { | ||
50 | struct clk_hw hw; | ||
51 | void __iomem *reg; | ||
52 | struct aux_clk_masks *masks; | ||
53 | struct aux_rate_tbl *rtbl; | ||
54 | u8 rtbl_cnt; | ||
55 | spinlock_t *lock; | ||
56 | }; | ||
57 | |||
58 | /* Fractional Synth clk */ | ||
59 | struct frac_rate_tbl { | ||
60 | u32 div; | ||
61 | }; | ||
62 | |||
63 | struct clk_frac { | ||
64 | struct clk_hw hw; | ||
65 | void __iomem *reg; | ||
66 | struct frac_rate_tbl *rtbl; | ||
67 | u8 rtbl_cnt; | ||
68 | spinlock_t *lock; | ||
69 | }; | ||
70 | |||
71 | /* GPT clk */ | ||
72 | struct gpt_rate_tbl { | ||
73 | u16 mscale; | ||
74 | u16 nscale; | ||
75 | }; | ||
76 | |||
77 | struct clk_gpt { | ||
78 | struct clk_hw hw; | ||
79 | void __iomem *reg; | ||
80 | struct gpt_rate_tbl *rtbl; | ||
81 | u8 rtbl_cnt; | ||
82 | spinlock_t *lock; | ||
83 | }; | ||
84 | |||
85 | /* VCO-PLL clk */ | ||
86 | struct pll_rate_tbl { | ||
87 | u8 mode; | ||
88 | u16 m; | ||
89 | u8 n; | ||
90 | u8 p; | ||
91 | }; | ||
92 | |||
93 | struct clk_vco { | ||
94 | struct clk_hw hw; | ||
95 | void __iomem *mode_reg; | ||
96 | void __iomem *cfg_reg; | ||
97 | struct pll_rate_tbl *rtbl; | ||
98 | u8 rtbl_cnt; | ||
99 | spinlock_t *lock; | ||
100 | }; | ||
101 | |||
102 | struct clk_pll { | ||
103 | struct clk_hw hw; | ||
104 | struct clk_vco *vco; | ||
105 | const char *parent[1]; | ||
106 | spinlock_t *lock; | ||
107 | }; | ||
108 | |||
109 | typedef unsigned long (*clk_calc_rate)(struct clk_hw *hw, unsigned long prate, | ||
110 | int index); | ||
111 | |||
112 | /* clk register routines */ | ||
113 | struct clk *clk_register_aux(const char *aux_name, const char *gate_name, | ||
114 | const char *parent_name, unsigned long flags, void __iomem *reg, | ||
115 | struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, | ||
116 | u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk); | ||
117 | struct clk *clk_register_frac(const char *name, const char *parent_name, | ||
118 | unsigned long flags, void __iomem *reg, | ||
119 | struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock); | ||
120 | struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned | ||
121 | long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8 | ||
122 | rtbl_cnt, spinlock_t *lock); | ||
123 | struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, | ||
124 | const char *vco_gate_name, const char *parent_name, | ||
125 | unsigned long flags, void __iomem *mode_reg, void __iomem | ||
126 | *cfg_reg, struct pll_rate_tbl *rtbl, u8 rtbl_cnt, | ||
127 | spinlock_t *lock, struct clk **pll_clk, | ||
128 | struct clk **vco_gate_clk); | ||
129 | |||
130 | long clk_round_rate_index(struct clk_hw *hw, unsigned long drate, | ||
131 | unsigned long parent_rate, clk_calc_rate calc_rate, u8 rtbl_cnt, | ||
132 | int *index); | ||
133 | |||
134 | #endif /* __SPEAR_CLK_H */ | ||
diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c new file mode 100644 index 00000000000..440bb3e4c97 --- /dev/null +++ b/drivers/clk/spear/spear3xx_clock.c | |||
@@ -0,0 +1,612 @@ | |||
1 | /* | ||
2 | * SPEAr3xx machines clock framework source file | ||
3 | * | ||
4 | * Copyright (C) 2012 ST Microelectronics | ||
5 | * Viresh Kumar <viresh.kumar@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clkdev.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/of_platform.h> | ||
17 | #include <linux/spinlock_types.h> | ||
18 | #include <mach/misc_regs.h> | ||
19 | #include "clk.h" | ||
20 | |||
21 | static DEFINE_SPINLOCK(_lock); | ||
22 | |||
23 | #define PLL1_CTR (MISC_BASE + 0x008) | ||
24 | #define PLL1_FRQ (MISC_BASE + 0x00C) | ||
25 | #define PLL2_CTR (MISC_BASE + 0x014) | ||
26 | #define PLL2_FRQ (MISC_BASE + 0x018) | ||
27 | #define PLL_CLK_CFG (MISC_BASE + 0x020) | ||
28 | /* PLL_CLK_CFG register masks */ | ||
29 | #define MCTR_CLK_SHIFT 28 | ||
30 | #define MCTR_CLK_MASK 3 | ||
31 | |||
32 | #define CORE_CLK_CFG (MISC_BASE + 0x024) | ||
33 | /* CORE CLK CFG register masks */ | ||
34 | #define GEN_SYNTH2_3_CLK_SHIFT 18 | ||
35 | #define GEN_SYNTH2_3_CLK_MASK 1 | ||
36 | |||
37 | #define HCLK_RATIO_SHIFT 10 | ||
38 | #define HCLK_RATIO_MASK 2 | ||
39 | #define PCLK_RATIO_SHIFT 8 | ||
40 | #define PCLK_RATIO_MASK 2 | ||
41 | |||
42 | #define PERIP_CLK_CFG (MISC_BASE + 0x028) | ||
43 | /* PERIP_CLK_CFG register masks */ | ||
44 | #define UART_CLK_SHIFT 4 | ||
45 | #define UART_CLK_MASK 1 | ||
46 | #define FIRDA_CLK_SHIFT 5 | ||
47 | #define FIRDA_CLK_MASK 2 | ||
48 | #define GPT0_CLK_SHIFT 8 | ||
49 | #define GPT1_CLK_SHIFT 11 | ||
50 | #define GPT2_CLK_SHIFT 12 | ||
51 | #define GPT_CLK_MASK 1 | ||
52 | |||
53 | #define PERIP1_CLK_ENB (MISC_BASE + 0x02C) | ||
54 | /* PERIP1_CLK_ENB register masks */ | ||
55 | #define UART_CLK_ENB 3 | ||
56 | #define SSP_CLK_ENB 5 | ||
57 | #define I2C_CLK_ENB 7 | ||
58 | #define JPEG_CLK_ENB 8 | ||
59 | #define FIRDA_CLK_ENB 10 | ||
60 | #define GPT1_CLK_ENB 11 | ||
61 | #define GPT2_CLK_ENB 12 | ||
62 | #define ADC_CLK_ENB 15 | ||
63 | #define RTC_CLK_ENB 17 | ||
64 | #define GPIO_CLK_ENB 18 | ||
65 | #define DMA_CLK_ENB 19 | ||
66 | #define SMI_CLK_ENB 21 | ||
67 | #define GMAC_CLK_ENB 23 | ||
68 | #define USBD_CLK_ENB 24 | ||
69 | #define USBH_CLK_ENB 25 | ||
70 | #define C3_CLK_ENB 31 | ||
71 | |||
72 | #define RAS_CLK_ENB (MISC_BASE + 0x034) | ||
73 | #define RAS_AHB_CLK_ENB 0 | ||
74 | #define RAS_PLL1_CLK_ENB 1 | ||
75 | #define RAS_APB_CLK_ENB 2 | ||
76 | #define RAS_32K_CLK_ENB 3 | ||
77 | #define RAS_24M_CLK_ENB 4 | ||
78 | #define RAS_48M_CLK_ENB 5 | ||
79 | #define RAS_PLL2_CLK_ENB 7 | ||
80 | #define RAS_SYNT0_CLK_ENB 8 | ||
81 | #define RAS_SYNT1_CLK_ENB 9 | ||
82 | #define RAS_SYNT2_CLK_ENB 10 | ||
83 | #define RAS_SYNT3_CLK_ENB 11 | ||
84 | |||
85 | #define PRSC0_CLK_CFG (MISC_BASE + 0x044) | ||
86 | #define PRSC1_CLK_CFG (MISC_BASE + 0x048) | ||
87 | #define PRSC2_CLK_CFG (MISC_BASE + 0x04C) | ||
88 | #define AMEM_CLK_CFG (MISC_BASE + 0x050) | ||
89 | #define AMEM_CLK_ENB 0 | ||
90 | |||
91 | #define CLCD_CLK_SYNT (MISC_BASE + 0x05C) | ||
92 | #define FIRDA_CLK_SYNT (MISC_BASE + 0x060) | ||
93 | #define UART_CLK_SYNT (MISC_BASE + 0x064) | ||
94 | #define GMAC_CLK_SYNT (MISC_BASE + 0x068) | ||
95 | #define GEN0_CLK_SYNT (MISC_BASE + 0x06C) | ||
96 | #define GEN1_CLK_SYNT (MISC_BASE + 0x070) | ||
97 | #define GEN2_CLK_SYNT (MISC_BASE + 0x074) | ||
98 | #define GEN3_CLK_SYNT (MISC_BASE + 0x078) | ||
99 | |||
100 | /* pll rate configuration table, in ascending order of rates */ | ||
101 | static struct pll_rate_tbl pll_rtbl[] = { | ||
102 | {.mode = 0, .m = 0x53, .n = 0x0C, .p = 0x1}, /* vco 332 & pll 166 MHz */ | ||
103 | {.mode = 0, .m = 0x85, .n = 0x0C, .p = 0x1}, /* vco 532 & pll 266 MHz */ | ||
104 | {.mode = 0, .m = 0xA6, .n = 0x0C, .p = 0x1}, /* vco 664 & pll 332 MHz */ | ||
105 | }; | ||
106 | |||
107 | /* aux rate configuration table, in ascending order of rates */ | ||
108 | static struct aux_rate_tbl aux_rtbl[] = { | ||
109 | /* For PLL1 = 332 MHz */ | ||
110 | {.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */ | ||
111 | {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ | ||
112 | {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ | ||
113 | {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ | ||
114 | }; | ||
115 | |||
116 | /* gpt rate configuration table, in ascending order of rates */ | ||
117 | static struct gpt_rate_tbl gpt_rtbl[] = { | ||
118 | /* For pll1 = 332 MHz */ | ||
119 | {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ | ||
120 | {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ | ||
121 | {.mscale = 1, .nscale = 0}, /* 83 MHz */ | ||
122 | }; | ||
123 | |||
124 | /* clock parents */ | ||
125 | static const char *uart0_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", }; | ||
126 | static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk", | ||
127 | }; | ||
128 | static const char *gpt0_parents[] = { "pll3_48m_clk", "gpt0_synth_clk", }; | ||
129 | static const char *gpt1_parents[] = { "pll3_48m_clk", "gpt1_synth_clk", }; | ||
130 | static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", }; | ||
131 | static const char *gen2_3_parents[] = { "pll1_clk", "pll2_clk", }; | ||
132 | static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none", | ||
133 | "pll2_clk", }; | ||
134 | |||
135 | #ifdef CONFIG_MACH_SPEAR300 | ||
136 | static void __init spear300_clk_init(void) | ||
137 | { | ||
138 | struct clk *clk; | ||
139 | |||
140 | clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0, | ||
141 | 1, 1); | ||
142 | clk_register_clkdev(clk, NULL, "60000000.clcd"); | ||
143 | |||
144 | clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, | ||
145 | 1); | ||
146 | clk_register_clkdev(clk, NULL, "94000000.flash"); | ||
147 | |||
148 | clk = clk_register_fixed_factor(NULL, "sdhci_clk", "ras_ahb_clk", 0, 1, | ||
149 | 1); | ||
150 | clk_register_clkdev(clk, NULL, "70000000.sdhci"); | ||
151 | |||
152 | clk = clk_register_fixed_factor(NULL, "gpio1_clk", "ras_apb_clk", 0, 1, | ||
153 | 1); | ||
154 | clk_register_clkdev(clk, NULL, "a9000000.gpio"); | ||
155 | |||
156 | clk = clk_register_fixed_factor(NULL, "kbd_clk", "ras_apb_clk", 0, 1, | ||
157 | 1); | ||
158 | clk_register_clkdev(clk, NULL, "a0000000.kbd"); | ||
159 | } | ||
160 | #endif | ||
161 | |||
162 | /* array of all spear 310 clock lookups */ | ||
163 | #ifdef CONFIG_MACH_SPEAR310 | ||
164 | static void __init spear310_clk_init(void) | ||
165 | { | ||
166 | struct clk *clk; | ||
167 | |||
168 | clk = clk_register_fixed_factor(NULL, "emi_clk", "ras_ahb_clk", 0, 1, | ||
169 | 1); | ||
170 | clk_register_clkdev(clk, "emi", NULL); | ||
171 | |||
172 | clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, | ||
173 | 1); | ||
174 | clk_register_clkdev(clk, NULL, "44000000.flash"); | ||
175 | |||
176 | clk = clk_register_fixed_factor(NULL, "tdm_clk", "ras_ahb_clk", 0, 1, | ||
177 | 1); | ||
178 | clk_register_clkdev(clk, NULL, "tdm"); | ||
179 | |||
180 | clk = clk_register_fixed_factor(NULL, "uart1_clk", "ras_apb_clk", 0, 1, | ||
181 | 1); | ||
182 | clk_register_clkdev(clk, NULL, "b2000000.serial"); | ||
183 | |||
184 | clk = clk_register_fixed_factor(NULL, "uart2_clk", "ras_apb_clk", 0, 1, | ||
185 | 1); | ||
186 | clk_register_clkdev(clk, NULL, "b2080000.serial"); | ||
187 | |||
188 | clk = clk_register_fixed_factor(NULL, "uart3_clk", "ras_apb_clk", 0, 1, | ||
189 | 1); | ||
190 | clk_register_clkdev(clk, NULL, "b2100000.serial"); | ||
191 | |||
192 | clk = clk_register_fixed_factor(NULL, "uart4_clk", "ras_apb_clk", 0, 1, | ||
193 | 1); | ||
194 | clk_register_clkdev(clk, NULL, "b2180000.serial"); | ||
195 | |||
196 | clk = clk_register_fixed_factor(NULL, "uart5_clk", "ras_apb_clk", 0, 1, | ||
197 | 1); | ||
198 | clk_register_clkdev(clk, NULL, "b2200000.serial"); | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | /* array of all spear 320 clock lookups */ | ||
203 | #ifdef CONFIG_MACH_SPEAR320 | ||
204 | #define SMII_PCLK_SHIFT 18 | ||
205 | #define SMII_PCLK_MASK 2 | ||
206 | #define SMII_PCLK_VAL_PAD 0x0 | ||
207 | #define SMII_PCLK_VAL_PLL2 0x1 | ||
208 | #define SMII_PCLK_VAL_SYNTH0 0x2 | ||
209 | #define SDHCI_PCLK_SHIFT 15 | ||
210 | #define SDHCI_PCLK_MASK 1 | ||
211 | #define SDHCI_PCLK_VAL_48M 0x0 | ||
212 | #define SDHCI_PCLK_VAL_SYNTH3 0x1 | ||
213 | #define I2S_REF_PCLK_SHIFT 8 | ||
214 | #define I2S_REF_PCLK_MASK 1 | ||
215 | #define I2S_REF_PCLK_SYNTH_VAL 0x1 | ||
216 | #define I2S_REF_PCLK_PLL2_VAL 0x0 | ||
217 | #define UART1_PCLK_SHIFT 6 | ||
218 | #define UART1_PCLK_MASK 1 | ||
219 | #define SPEAR320_UARTX_PCLK_VAL_SYNTH1 0x0 | ||
220 | #define SPEAR320_UARTX_PCLK_VAL_APB 0x1 | ||
221 | |||
222 | static const char *i2s_ref_parents[] = { "ras_pll2_clk", | ||
223 | "ras_gen2_synth_gate_clk", }; | ||
224 | static const char *sdhci_parents[] = { "ras_pll3_48m_clk", | ||
225 | "ras_gen3_synth_gate_clk", | ||
226 | }; | ||
227 | static const char *smii0_parents[] = { "smii_125m_pad", "ras_pll2_clk", | ||
228 | "ras_gen0_synth_gate_clk", }; | ||
229 | static const char *uartx_parents[] = { "ras_gen1_synth_gate_clk", "ras_apb_clk", | ||
230 | }; | ||
231 | |||
232 | static void __init spear320_clk_init(void) | ||
233 | { | ||
234 | struct clk *clk; | ||
235 | |||
236 | clk = clk_register_fixed_rate(NULL, "smii_125m_pad_clk", NULL, | ||
237 | CLK_IS_ROOT, 125000000); | ||
238 | clk_register_clkdev(clk, "smii_125m_pad", NULL); | ||
239 | |||
240 | clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0, | ||
241 | 1, 1); | ||
242 | clk_register_clkdev(clk, NULL, "90000000.clcd"); | ||
243 | |||
244 | clk = clk_register_fixed_factor(NULL, "emi_clk", "ras_ahb_clk", 0, 1, | ||
245 | 1); | ||
246 | clk_register_clkdev(clk, "emi", NULL); | ||
247 | |||
248 | clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, | ||
249 | 1); | ||
250 | clk_register_clkdev(clk, NULL, "4c000000.flash"); | ||
251 | |||
252 | clk = clk_register_fixed_factor(NULL, "i2c1_clk", "ras_ahb_clk", 0, 1, | ||
253 | 1); | ||
254 | clk_register_clkdev(clk, NULL, "a7000000.i2c"); | ||
255 | |||
256 | clk = clk_register_fixed_factor(NULL, "pwm_clk", "ras_ahb_clk", 0, 1, | ||
257 | 1); | ||
258 | clk_register_clkdev(clk, "pwm", NULL); | ||
259 | |||
260 | clk = clk_register_fixed_factor(NULL, "ssp1_clk", "ras_ahb_clk", 0, 1, | ||
261 | 1); | ||
262 | clk_register_clkdev(clk, NULL, "a5000000.spi"); | ||
263 | |||
264 | clk = clk_register_fixed_factor(NULL, "ssp2_clk", "ras_ahb_clk", 0, 1, | ||
265 | 1); | ||
266 | clk_register_clkdev(clk, NULL, "a6000000.spi"); | ||
267 | |||
268 | clk = clk_register_fixed_factor(NULL, "can0_clk", "ras_apb_clk", 0, 1, | ||
269 | 1); | ||
270 | clk_register_clkdev(clk, NULL, "c_can_platform.0"); | ||
271 | |||
272 | clk = clk_register_fixed_factor(NULL, "can1_clk", "ras_apb_clk", 0, 1, | ||
273 | 1); | ||
274 | clk_register_clkdev(clk, NULL, "c_can_platform.1"); | ||
275 | |||
276 | clk = clk_register_fixed_factor(NULL, "i2s_clk", "ras_apb_clk", 0, 1, | ||
277 | 1); | ||
278 | clk_register_clkdev(clk, NULL, "i2s"); | ||
279 | |||
280 | clk = clk_register_mux(NULL, "i2s_ref_clk", i2s_ref_parents, | ||
281 | ARRAY_SIZE(i2s_ref_parents), 0, SPEAR320_CONTROL_REG, | ||
282 | I2S_REF_PCLK_SHIFT, I2S_REF_PCLK_MASK, 0, &_lock); | ||
283 | clk_register_clkdev(clk, "i2s_ref_clk", NULL); | ||
284 | |||
285 | clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk", 0, 1, | ||
286 | 4); | ||
287 | clk_register_clkdev(clk, "i2s_sclk", NULL); | ||
288 | |||
289 | clk = clk_register_mux(NULL, "rs485_clk", uartx_parents, | ||
290 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
291 | SPEAR320_RS485_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
292 | &_lock); | ||
293 | clk_register_clkdev(clk, NULL, "a9300000.serial"); | ||
294 | |||
295 | clk = clk_register_mux(NULL, "sdhci_clk", sdhci_parents, | ||
296 | ARRAY_SIZE(sdhci_parents), 0, SPEAR320_CONTROL_REG, | ||
297 | SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK, 0, &_lock); | ||
298 | clk_register_clkdev(clk, NULL, "70000000.sdhci"); | ||
299 | |||
300 | clk = clk_register_mux(NULL, "smii_pclk", smii0_parents, | ||
301 | ARRAY_SIZE(smii0_parents), 0, SPEAR320_CONTROL_REG, | ||
302 | SMII_PCLK_SHIFT, SMII_PCLK_MASK, 0, &_lock); | ||
303 | clk_register_clkdev(clk, NULL, "smii_pclk"); | ||
304 | |||
305 | clk = clk_register_fixed_factor(NULL, "smii_clk", "smii_pclk", 0, 1, 1); | ||
306 | clk_register_clkdev(clk, NULL, "smii"); | ||
307 | |||
308 | clk = clk_register_mux(NULL, "uart1_clk", uartx_parents, | ||
309 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_CONTROL_REG, | ||
310 | UART1_PCLK_SHIFT, UART1_PCLK_MASK, 0, &_lock); | ||
311 | clk_register_clkdev(clk, NULL, "a3000000.serial"); | ||
312 | |||
313 | clk = clk_register_mux(NULL, "uart2_clk", uartx_parents, | ||
314 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
315 | SPEAR320_UART2_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
316 | &_lock); | ||
317 | clk_register_clkdev(clk, NULL, "a4000000.serial"); | ||
318 | |||
319 | clk = clk_register_mux(NULL, "uart3_clk", uartx_parents, | ||
320 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
321 | SPEAR320_UART3_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
322 | &_lock); | ||
323 | clk_register_clkdev(clk, NULL, "a9100000.serial"); | ||
324 | |||
325 | clk = clk_register_mux(NULL, "uart4_clk", uartx_parents, | ||
326 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
327 | SPEAR320_UART4_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
328 | &_lock); | ||
329 | clk_register_clkdev(clk, NULL, "a9200000.serial"); | ||
330 | |||
331 | clk = clk_register_mux(NULL, "uart5_clk", uartx_parents, | ||
332 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
333 | SPEAR320_UART5_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
334 | &_lock); | ||
335 | clk_register_clkdev(clk, NULL, "60000000.serial"); | ||
336 | |||
337 | clk = clk_register_mux(NULL, "uart6_clk", uartx_parents, | ||
338 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
339 | SPEAR320_UART6_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
340 | &_lock); | ||
341 | clk_register_clkdev(clk, NULL, "60100000.serial"); | ||
342 | } | ||
343 | #endif | ||
344 | |||
345 | void __init spear3xx_clk_init(void) | ||
346 | { | ||
347 | struct clk *clk, *clk1; | ||
348 | |||
349 | clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); | ||
350 | clk_register_clkdev(clk, "apb_pclk", NULL); | ||
351 | |||
352 | clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, | ||
353 | 32000); | ||
354 | clk_register_clkdev(clk, "osc_32k_clk", NULL); | ||
355 | |||
356 | clk = clk_register_fixed_rate(NULL, "osc_24m_clk", NULL, CLK_IS_ROOT, | ||
357 | 24000000); | ||
358 | clk_register_clkdev(clk, "osc_24m_clk", NULL); | ||
359 | |||
360 | /* clock derived from 32 KHz osc clk */ | ||
361 | clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0, | ||
362 | PERIP1_CLK_ENB, RTC_CLK_ENB, 0, &_lock); | ||
363 | clk_register_clkdev(clk, NULL, "fc900000.rtc"); | ||
364 | |||
365 | /* clock derived from 24 MHz osc clk */ | ||
366 | clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0, | ||
367 | 48000000); | ||
368 | clk_register_clkdev(clk, "pll3_48m_clk", NULL); | ||
369 | |||
370 | clk = clk_register_fixed_factor(NULL, "wdt_clk", "osc_24m_clk", 0, 1, | ||
371 | 1); | ||
372 | clk_register_clkdev(clk, NULL, "fc880000.wdt"); | ||
373 | |||
374 | clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, | ||
375 | "osc_24m_clk", 0, PLL1_CTR, PLL1_FRQ, pll_rtbl, | ||
376 | ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); | ||
377 | clk_register_clkdev(clk, "vco1_clk", NULL); | ||
378 | clk_register_clkdev(clk1, "pll1_clk", NULL); | ||
379 | |||
380 | clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, | ||
381 | "osc_24m_clk", 0, PLL2_CTR, PLL2_FRQ, pll_rtbl, | ||
382 | ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); | ||
383 | clk_register_clkdev(clk, "vco2_clk", NULL); | ||
384 | clk_register_clkdev(clk1, "pll2_clk", NULL); | ||
385 | |||
386 | /* clock derived from pll1 clk */ | ||
387 | clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); | ||
388 | clk_register_clkdev(clk, "cpu_clk", NULL); | ||
389 | |||
390 | clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", | ||
391 | CLK_SET_RATE_PARENT, CORE_CLK_CFG, HCLK_RATIO_SHIFT, | ||
392 | HCLK_RATIO_MASK, 0, &_lock); | ||
393 | clk_register_clkdev(clk, "ahb_clk", NULL); | ||
394 | |||
395 | clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", | ||
396 | "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl, | ||
397 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
398 | clk_register_clkdev(clk, "uart_synth_clk", NULL); | ||
399 | clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); | ||
400 | |||
401 | clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents, | ||
402 | ARRAY_SIZE(uart0_parents), 0, PERIP_CLK_CFG, | ||
403 | UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); | ||
404 | clk_register_clkdev(clk, "uart0_mux_clk", NULL); | ||
405 | |||
406 | clk = clk_register_gate(NULL, "uart0", "uart0_mux_clk", 0, | ||
407 | PERIP1_CLK_ENB, UART_CLK_ENB, 0, &_lock); | ||
408 | clk_register_clkdev(clk, NULL, "d0000000.serial"); | ||
409 | |||
410 | clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk", | ||
411 | "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, | ||
412 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
413 | clk_register_clkdev(clk, "firda_synth_clk", NULL); | ||
414 | clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL); | ||
415 | |||
416 | clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents, | ||
417 | ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, | ||
418 | FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); | ||
419 | clk_register_clkdev(clk, "firda_mux_clk", NULL); | ||
420 | |||
421 | clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0, | ||
422 | PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); | ||
423 | clk_register_clkdev(clk, NULL, "firda"); | ||
424 | |||
425 | /* gpt clocks */ | ||
426 | clk_register_gpt("gpt0_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG, | ||
427 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
428 | clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents, | ||
429 | ARRAY_SIZE(gpt0_parents), 0, PERIP_CLK_CFG, | ||
430 | GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
431 | clk_register_clkdev(clk, NULL, "gpt0"); | ||
432 | |||
433 | clk_register_gpt("gpt1_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG, | ||
434 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
435 | clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt1_parents, | ||
436 | ARRAY_SIZE(gpt1_parents), 0, PERIP_CLK_CFG, | ||
437 | GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
438 | clk_register_clkdev(clk, "gpt1_mux_clk", NULL); | ||
439 | clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, | ||
440 | PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); | ||
441 | clk_register_clkdev(clk, NULL, "gpt1"); | ||
442 | |||
443 | clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG, | ||
444 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
445 | clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents, | ||
446 | ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, | ||
447 | GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
448 | clk_register_clkdev(clk, "gpt2_mux_clk", NULL); | ||
449 | clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, | ||
450 | PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); | ||
451 | clk_register_clkdev(clk, NULL, "gpt2"); | ||
452 | |||
453 | /* general synths clocks */ | ||
454 | clk = clk_register_aux("gen0_synth_clk", "gen0_synth_gate_clk", | ||
455 | "pll1_clk", 0, GEN0_CLK_SYNT, NULL, aux_rtbl, | ||
456 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
457 | clk_register_clkdev(clk, "gen0_synth_clk", NULL); | ||
458 | clk_register_clkdev(clk1, "gen0_synth_gate_clk", NULL); | ||
459 | |||
460 | clk = clk_register_aux("gen1_synth_clk", "gen1_synth_gate_clk", | ||
461 | "pll1_clk", 0, GEN1_CLK_SYNT, NULL, aux_rtbl, | ||
462 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
463 | clk_register_clkdev(clk, "gen1_synth_clk", NULL); | ||
464 | clk_register_clkdev(clk1, "gen1_synth_gate_clk", NULL); | ||
465 | |||
466 | clk = clk_register_mux(NULL, "gen2_3_parent_clk", gen2_3_parents, | ||
467 | ARRAY_SIZE(gen2_3_parents), 0, CORE_CLK_CFG, | ||
468 | GEN_SYNTH2_3_CLK_SHIFT, GEN_SYNTH2_3_CLK_MASK, 0, | ||
469 | &_lock); | ||
470 | clk_register_clkdev(clk, "gen2_3_parent_clk", NULL); | ||
471 | |||
472 | clk = clk_register_aux("gen2_synth_clk", "gen2_synth_gate_clk", | ||
473 | "gen2_3_parent_clk", 0, GEN2_CLK_SYNT, NULL, aux_rtbl, | ||
474 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
475 | clk_register_clkdev(clk, "gen2_synth_clk", NULL); | ||
476 | clk_register_clkdev(clk1, "gen2_synth_gate_clk", NULL); | ||
477 | |||
478 | clk = clk_register_aux("gen3_synth_clk", "gen3_synth_gate_clk", | ||
479 | "gen2_3_parent_clk", 0, GEN3_CLK_SYNT, NULL, aux_rtbl, | ||
480 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
481 | clk_register_clkdev(clk, "gen3_synth_clk", NULL); | ||
482 | clk_register_clkdev(clk1, "gen3_synth_gate_clk", NULL); | ||
483 | |||
484 | /* clock derived from pll3 clk */ | ||
485 | clk = clk_register_gate(NULL, "usbh_clk", "pll3_48m_clk", 0, | ||
486 | PERIP1_CLK_ENB, USBH_CLK_ENB, 0, &_lock); | ||
487 | clk_register_clkdev(clk, "usbh_clk", NULL); | ||
488 | |||
489 | clk = clk_register_fixed_factor(NULL, "usbh.0_clk", "usbh_clk", 0, 1, | ||
490 | 1); | ||
491 | clk_register_clkdev(clk, "usbh.0_clk", NULL); | ||
492 | |||
493 | clk = clk_register_fixed_factor(NULL, "usbh.1_clk", "usbh_clk", 0, 1, | ||
494 | 1); | ||
495 | clk_register_clkdev(clk, "usbh.1_clk", NULL); | ||
496 | |||
497 | clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0, | ||
498 | PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); | ||
499 | clk_register_clkdev(clk, NULL, "designware_udc"); | ||
500 | |||
501 | /* clock derived from ahb clk */ | ||
502 | clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2, | ||
503 | 1); | ||
504 | clk_register_clkdev(clk, "ahbmult2_clk", NULL); | ||
505 | |||
506 | clk = clk_register_mux(NULL, "ddr_clk", ddr_parents, | ||
507 | ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT, | ||
508 | MCTR_CLK_MASK, 0, &_lock); | ||
509 | clk_register_clkdev(clk, "ddr_clk", NULL); | ||
510 | |||
511 | clk = clk_register_divider(NULL, "apb_clk", "ahb_clk", | ||
512 | CLK_SET_RATE_PARENT, CORE_CLK_CFG, PCLK_RATIO_SHIFT, | ||
513 | PCLK_RATIO_MASK, 0, &_lock); | ||
514 | clk_register_clkdev(clk, "apb_clk", NULL); | ||
515 | |||
516 | clk = clk_register_gate(NULL, "amem_clk", "ahb_clk", 0, AMEM_CLK_CFG, | ||
517 | AMEM_CLK_ENB, 0, &_lock); | ||
518 | clk_register_clkdev(clk, "amem_clk", NULL); | ||
519 | |||
520 | clk = clk_register_gate(NULL, "c3_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
521 | C3_CLK_ENB, 0, &_lock); | ||
522 | clk_register_clkdev(clk, NULL, "c3_clk"); | ||
523 | |||
524 | clk = clk_register_gate(NULL, "dma_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
525 | DMA_CLK_ENB, 0, &_lock); | ||
526 | clk_register_clkdev(clk, NULL, "fc400000.dma"); | ||
527 | |||
528 | clk = clk_register_gate(NULL, "gmac_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
529 | GMAC_CLK_ENB, 0, &_lock); | ||
530 | clk_register_clkdev(clk, NULL, "e0800000.eth"); | ||
531 | |||
532 | clk = clk_register_gate(NULL, "i2c0_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
533 | I2C_CLK_ENB, 0, &_lock); | ||
534 | clk_register_clkdev(clk, NULL, "d0180000.i2c"); | ||
535 | |||
536 | clk = clk_register_gate(NULL, "jpeg_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
537 | JPEG_CLK_ENB, 0, &_lock); | ||
538 | clk_register_clkdev(clk, NULL, "jpeg"); | ||
539 | |||
540 | clk = clk_register_gate(NULL, "smi_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
541 | SMI_CLK_ENB, 0, &_lock); | ||
542 | clk_register_clkdev(clk, NULL, "fc000000.flash"); | ||
543 | |||
544 | /* clock derived from apb clk */ | ||
545 | clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
546 | ADC_CLK_ENB, 0, &_lock); | ||
547 | clk_register_clkdev(clk, NULL, "adc"); | ||
548 | |||
549 | clk = clk_register_gate(NULL, "gpio0_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
550 | GPIO_CLK_ENB, 0, &_lock); | ||
551 | clk_register_clkdev(clk, NULL, "fc980000.gpio"); | ||
552 | |||
553 | clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
554 | SSP_CLK_ENB, 0, &_lock); | ||
555 | clk_register_clkdev(clk, NULL, "d0100000.spi"); | ||
556 | |||
557 | /* RAS clk enable */ | ||
558 | clk = clk_register_gate(NULL, "ras_ahb_clk", "ahb_clk", 0, RAS_CLK_ENB, | ||
559 | RAS_AHB_CLK_ENB, 0, &_lock); | ||
560 | clk_register_clkdev(clk, "ras_ahb_clk", NULL); | ||
561 | |||
562 | clk = clk_register_gate(NULL, "ras_apb_clk", "apb_clk", 0, RAS_CLK_ENB, | ||
563 | RAS_APB_CLK_ENB, 0, &_lock); | ||
564 | clk_register_clkdev(clk, "ras_apb_clk", NULL); | ||
565 | |||
566 | clk = clk_register_gate(NULL, "ras_32k_clk", "osc_32k_clk", 0, | ||
567 | RAS_CLK_ENB, RAS_32K_CLK_ENB, 0, &_lock); | ||
568 | clk_register_clkdev(clk, "ras_32k_clk", NULL); | ||
569 | |||
570 | clk = clk_register_gate(NULL, "ras_24m_clk", "osc_24m_clk", 0, | ||
571 | RAS_CLK_ENB, RAS_24M_CLK_ENB, 0, &_lock); | ||
572 | clk_register_clkdev(clk, "ras_24m_clk", NULL); | ||
573 | |||
574 | clk = clk_register_gate(NULL, "ras_pll1_clk", "pll1_clk", 0, | ||
575 | RAS_CLK_ENB, RAS_PLL1_CLK_ENB, 0, &_lock); | ||
576 | clk_register_clkdev(clk, "ras_pll1_clk", NULL); | ||
577 | |||
578 | clk = clk_register_gate(NULL, "ras_pll2_clk", "pll2_clk", 0, | ||
579 | RAS_CLK_ENB, RAS_PLL2_CLK_ENB, 0, &_lock); | ||
580 | clk_register_clkdev(clk, "ras_pll2_clk", NULL); | ||
581 | |||
582 | clk = clk_register_gate(NULL, "ras_pll3_48m_clk", "pll3_48m_clk", 0, | ||
583 | RAS_CLK_ENB, RAS_48M_CLK_ENB, 0, &_lock); | ||
584 | clk_register_clkdev(clk, "ras_pll3_48m_clk", NULL); | ||
585 | |||
586 | clk = clk_register_gate(NULL, "ras_gen0_synth_gate_clk", | ||
587 | "gen0_synth_gate_clk", 0, RAS_CLK_ENB, | ||
588 | RAS_SYNT0_CLK_ENB, 0, &_lock); | ||
589 | clk_register_clkdev(clk, "ras_gen0_synth_gate_clk", NULL); | ||
590 | |||
591 | clk = clk_register_gate(NULL, "ras_gen1_synth_gate_clk", | ||
592 | "gen1_synth_gate_clk", 0, RAS_CLK_ENB, | ||
593 | RAS_SYNT1_CLK_ENB, 0, &_lock); | ||
594 | clk_register_clkdev(clk, "ras_gen1_synth_gate_clk", NULL); | ||
595 | |||
596 | clk = clk_register_gate(NULL, "ras_gen2_synth_gate_clk", | ||
597 | "gen2_synth_gate_clk", 0, RAS_CLK_ENB, | ||
598 | RAS_SYNT2_CLK_ENB, 0, &_lock); | ||
599 | clk_register_clkdev(clk, "ras_gen2_synth_gate_clk", NULL); | ||
600 | |||
601 | clk = clk_register_gate(NULL, "ras_gen3_synth_gate_clk", | ||
602 | "gen3_synth_gate_clk", 0, RAS_CLK_ENB, | ||
603 | RAS_SYNT3_CLK_ENB, 0, &_lock); | ||
604 | clk_register_clkdev(clk, "ras_gen3_synth_gate_clk", NULL); | ||
605 | |||
606 | if (of_machine_is_compatible("st,spear300")) | ||
607 | spear300_clk_init(); | ||
608 | else if (of_machine_is_compatible("st,spear310")) | ||
609 | spear310_clk_init(); | ||
610 | else if (of_machine_is_compatible("st,spear320")) | ||
611 | spear320_clk_init(); | ||
612 | } | ||
diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c new file mode 100644 index 00000000000..f9a20b38230 --- /dev/null +++ b/drivers/clk/spear/spear6xx_clock.c | |||
@@ -0,0 +1,342 @@ | |||
1 | /* | ||
2 | * SPEAr6xx machines clock framework source file | ||
3 | * | ||
4 | * Copyright (C) 2012 ST Microelectronics | ||
5 | * Viresh Kumar <viresh.kumar@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clkdev.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/spinlock_types.h> | ||
16 | #include <mach/misc_regs.h> | ||
17 | #include "clk.h" | ||
18 | |||
19 | static DEFINE_SPINLOCK(_lock); | ||
20 | |||
21 | #define PLL1_CTR (MISC_BASE + 0x008) | ||
22 | #define PLL1_FRQ (MISC_BASE + 0x00C) | ||
23 | #define PLL2_CTR (MISC_BASE + 0x014) | ||
24 | #define PLL2_FRQ (MISC_BASE + 0x018) | ||
25 | #define PLL_CLK_CFG (MISC_BASE + 0x020) | ||
26 | /* PLL_CLK_CFG register masks */ | ||
27 | #define MCTR_CLK_SHIFT 28 | ||
28 | #define MCTR_CLK_MASK 3 | ||
29 | |||
30 | #define CORE_CLK_CFG (MISC_BASE + 0x024) | ||
31 | /* CORE CLK CFG register masks */ | ||
32 | #define HCLK_RATIO_SHIFT 10 | ||
33 | #define HCLK_RATIO_MASK 2 | ||
34 | #define PCLK_RATIO_SHIFT 8 | ||
35 | #define PCLK_RATIO_MASK 2 | ||
36 | |||
37 | #define PERIP_CLK_CFG (MISC_BASE + 0x028) | ||
38 | /* PERIP_CLK_CFG register masks */ | ||
39 | #define CLCD_CLK_SHIFT 2 | ||
40 | #define CLCD_CLK_MASK 2 | ||
41 | #define UART_CLK_SHIFT 4 | ||
42 | #define UART_CLK_MASK 1 | ||
43 | #define FIRDA_CLK_SHIFT 5 | ||
44 | #define FIRDA_CLK_MASK 2 | ||
45 | #define GPT0_CLK_SHIFT 8 | ||
46 | #define GPT1_CLK_SHIFT 10 | ||
47 | #define GPT2_CLK_SHIFT 11 | ||
48 | #define GPT3_CLK_SHIFT 12 | ||
49 | #define GPT_CLK_MASK 1 | ||
50 | |||
51 | #define PERIP1_CLK_ENB (MISC_BASE + 0x02C) | ||
52 | /* PERIP1_CLK_ENB register masks */ | ||
53 | #define UART0_CLK_ENB 3 | ||
54 | #define UART1_CLK_ENB 4 | ||
55 | #define SSP0_CLK_ENB 5 | ||
56 | #define SSP1_CLK_ENB 6 | ||
57 | #define I2C_CLK_ENB 7 | ||
58 | #define JPEG_CLK_ENB 8 | ||
59 | #define FSMC_CLK_ENB 9 | ||
60 | #define FIRDA_CLK_ENB 10 | ||
61 | #define GPT2_CLK_ENB 11 | ||
62 | #define GPT3_CLK_ENB 12 | ||
63 | #define GPIO2_CLK_ENB 13 | ||
64 | #define SSP2_CLK_ENB 14 | ||
65 | #define ADC_CLK_ENB 15 | ||
66 | #define GPT1_CLK_ENB 11 | ||
67 | #define RTC_CLK_ENB 17 | ||
68 | #define GPIO1_CLK_ENB 18 | ||
69 | #define DMA_CLK_ENB 19 | ||
70 | #define SMI_CLK_ENB 21 | ||
71 | #define CLCD_CLK_ENB 22 | ||
72 | #define GMAC_CLK_ENB 23 | ||
73 | #define USBD_CLK_ENB 24 | ||
74 | #define USBH0_CLK_ENB 25 | ||
75 | #define USBH1_CLK_ENB 26 | ||
76 | |||
77 | #define PRSC0_CLK_CFG (MISC_BASE + 0x044) | ||
78 | #define PRSC1_CLK_CFG (MISC_BASE + 0x048) | ||
79 | #define PRSC2_CLK_CFG (MISC_BASE + 0x04C) | ||
80 | |||
81 | #define CLCD_CLK_SYNT (MISC_BASE + 0x05C) | ||
82 | #define FIRDA_CLK_SYNT (MISC_BASE + 0x060) | ||
83 | #define UART_CLK_SYNT (MISC_BASE + 0x064) | ||
84 | |||
85 | /* vco rate configuration table, in ascending order of rates */ | ||
86 | static struct pll_rate_tbl pll_rtbl[] = { | ||
87 | {.mode = 0, .m = 0x53, .n = 0x0F, .p = 0x1}, /* vco 332 & pll 166 MHz */ | ||
88 | {.mode = 0, .m = 0x85, .n = 0x0F, .p = 0x1}, /* vco 532 & pll 266 MHz */ | ||
89 | {.mode = 0, .m = 0xA6, .n = 0x0F, .p = 0x1}, /* vco 664 & pll 332 MHz */ | ||
90 | }; | ||
91 | |||
92 | /* aux rate configuration table, in ascending order of rates */ | ||
93 | static struct aux_rate_tbl aux_rtbl[] = { | ||
94 | /* For PLL1 = 332 MHz */ | ||
95 | {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ | ||
96 | {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ | ||
97 | {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ | ||
98 | }; | ||
99 | |||
100 | static const char *clcd_parents[] = { "pll3_48m_clk", "clcd_synth_gate_clk", }; | ||
101 | static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk", | ||
102 | }; | ||
103 | static const char *uart_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", }; | ||
104 | static const char *gpt0_1_parents[] = { "pll3_48m_clk", "gpt0_1_synth_clk", }; | ||
105 | static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", }; | ||
106 | static const char *gpt3_parents[] = { "pll3_48m_clk", "gpt3_synth_clk", }; | ||
107 | static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none", | ||
108 | "pll2_clk", }; | ||
109 | |||
110 | /* gpt rate configuration table, in ascending order of rates */ | ||
111 | static struct gpt_rate_tbl gpt_rtbl[] = { | ||
112 | /* For pll1 = 332 MHz */ | ||
113 | {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ | ||
114 | {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ | ||
115 | {.mscale = 1, .nscale = 0}, /* 83 MHz */ | ||
116 | }; | ||
117 | |||
118 | void __init spear6xx_clk_init(void) | ||
119 | { | ||
120 | struct clk *clk, *clk1; | ||
121 | |||
122 | clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); | ||
123 | clk_register_clkdev(clk, "apb_pclk", NULL); | ||
124 | |||
125 | clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, | ||
126 | 32000); | ||
127 | clk_register_clkdev(clk, "osc_32k_clk", NULL); | ||
128 | |||
129 | clk = clk_register_fixed_rate(NULL, "osc_30m_clk", NULL, CLK_IS_ROOT, | ||
130 | 30000000); | ||
131 | clk_register_clkdev(clk, "osc_30m_clk", NULL); | ||
132 | |||
133 | /* clock derived from 32 KHz osc clk */ | ||
134 | clk = clk_register_gate(NULL, "rtc_spear", "osc_32k_clk", 0, | ||
135 | PERIP1_CLK_ENB, RTC_CLK_ENB, 0, &_lock); | ||
136 | clk_register_clkdev(clk, NULL, "rtc-spear"); | ||
137 | |||
138 | /* clock derived from 30 MHz osc clk */ | ||
139 | clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0, | ||
140 | 48000000); | ||
141 | clk_register_clkdev(clk, "pll3_48m_clk", NULL); | ||
142 | |||
143 | clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "osc_30m_clk", | ||
144 | 0, PLL1_CTR, PLL1_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), | ||
145 | &_lock, &clk1, NULL); | ||
146 | clk_register_clkdev(clk, "vco1_clk", NULL); | ||
147 | clk_register_clkdev(clk1, "pll1_clk", NULL); | ||
148 | |||
149 | clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, | ||
150 | "osc_30m_clk", 0, PLL2_CTR, PLL2_FRQ, pll_rtbl, | ||
151 | ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); | ||
152 | clk_register_clkdev(clk, "vco2_clk", NULL); | ||
153 | clk_register_clkdev(clk1, "pll2_clk", NULL); | ||
154 | |||
155 | clk = clk_register_fixed_factor(NULL, "wdt_clk", "osc_30m_clk", 0, 1, | ||
156 | 1); | ||
157 | clk_register_clkdev(clk, NULL, "wdt"); | ||
158 | |||
159 | /* clock derived from pll1 clk */ | ||
160 | clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); | ||
161 | clk_register_clkdev(clk, "cpu_clk", NULL); | ||
162 | |||
163 | clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", | ||
164 | CLK_SET_RATE_PARENT, CORE_CLK_CFG, HCLK_RATIO_SHIFT, | ||
165 | HCLK_RATIO_MASK, 0, &_lock); | ||
166 | clk_register_clkdev(clk, "ahb_clk", NULL); | ||
167 | |||
168 | clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", | ||
169 | "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl, | ||
170 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
171 | clk_register_clkdev(clk, "uart_synth_clk", NULL); | ||
172 | clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); | ||
173 | |||
174 | clk = clk_register_mux(NULL, "uart_mux_clk", uart_parents, | ||
175 | ARRAY_SIZE(uart_parents), 0, PERIP_CLK_CFG, | ||
176 | UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); | ||
177 | clk_register_clkdev(clk, "uart_mux_clk", NULL); | ||
178 | |||
179 | clk = clk_register_gate(NULL, "uart0", "uart_mux_clk", 0, | ||
180 | PERIP1_CLK_ENB, UART0_CLK_ENB, 0, &_lock); | ||
181 | clk_register_clkdev(clk, NULL, "d0000000.serial"); | ||
182 | |||
183 | clk = clk_register_gate(NULL, "uart1", "uart_mux_clk", 0, | ||
184 | PERIP1_CLK_ENB, UART1_CLK_ENB, 0, &_lock); | ||
185 | clk_register_clkdev(clk, NULL, "d0080000.serial"); | ||
186 | |||
187 | clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk", | ||
188 | "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, | ||
189 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
190 | clk_register_clkdev(clk, "firda_synth_clk", NULL); | ||
191 | clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL); | ||
192 | |||
193 | clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents, | ||
194 | ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, | ||
195 | FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); | ||
196 | clk_register_clkdev(clk, "firda_mux_clk", NULL); | ||
197 | |||
198 | clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0, | ||
199 | PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); | ||
200 | clk_register_clkdev(clk, NULL, "firda"); | ||
201 | |||
202 | clk = clk_register_aux("clcd_synth_clk", "clcd_synth_gate_clk", | ||
203 | "pll1_clk", 0, CLCD_CLK_SYNT, NULL, aux_rtbl, | ||
204 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
205 | clk_register_clkdev(clk, "clcd_synth_clk", NULL); | ||
206 | clk_register_clkdev(clk1, "clcd_synth_gate_clk", NULL); | ||
207 | |||
208 | clk = clk_register_mux(NULL, "clcd_mux_clk", clcd_parents, | ||
209 | ARRAY_SIZE(clcd_parents), 0, PERIP_CLK_CFG, | ||
210 | CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0, &_lock); | ||
211 | clk_register_clkdev(clk, "clcd_mux_clk", NULL); | ||
212 | |||
213 | clk = clk_register_gate(NULL, "clcd_clk", "clcd_mux_clk", 0, | ||
214 | PERIP1_CLK_ENB, CLCD_CLK_ENB, 0, &_lock); | ||
215 | clk_register_clkdev(clk, NULL, "clcd"); | ||
216 | |||
217 | /* gpt clocks */ | ||
218 | clk = clk_register_gpt("gpt0_1_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG, | ||
219 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
220 | clk_register_clkdev(clk, "gpt0_1_synth_clk", NULL); | ||
221 | |||
222 | clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt0_1_parents, | ||
223 | ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG, | ||
224 | GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
225 | clk_register_clkdev(clk, NULL, "gpt0"); | ||
226 | |||
227 | clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt0_1_parents, | ||
228 | ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG, | ||
229 | GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
230 | clk_register_clkdev(clk, "gpt1_mux_clk", NULL); | ||
231 | |||
232 | clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, | ||
233 | PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); | ||
234 | clk_register_clkdev(clk, NULL, "gpt1"); | ||
235 | |||
236 | clk = clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG, | ||
237 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
238 | clk_register_clkdev(clk, "gpt2_synth_clk", NULL); | ||
239 | |||
240 | clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents, | ||
241 | ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, | ||
242 | GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
243 | clk_register_clkdev(clk, "gpt2_mux_clk", NULL); | ||
244 | |||
245 | clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, | ||
246 | PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); | ||
247 | clk_register_clkdev(clk, NULL, "gpt2"); | ||
248 | |||
249 | clk = clk_register_gpt("gpt3_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG, | ||
250 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
251 | clk_register_clkdev(clk, "gpt3_synth_clk", NULL); | ||
252 | |||
253 | clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt3_parents, | ||
254 | ARRAY_SIZE(gpt3_parents), 0, PERIP_CLK_CFG, | ||
255 | GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
256 | clk_register_clkdev(clk, "gpt3_mux_clk", NULL); | ||
257 | |||
258 | clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0, | ||
259 | PERIP1_CLK_ENB, GPT3_CLK_ENB, 0, &_lock); | ||
260 | clk_register_clkdev(clk, NULL, "gpt3"); | ||
261 | |||
262 | /* clock derived from pll3 clk */ | ||
263 | clk = clk_register_gate(NULL, "usbh0_clk", "pll3_48m_clk", 0, | ||
264 | PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock); | ||
265 | clk_register_clkdev(clk, NULL, "usbh.0_clk"); | ||
266 | |||
267 | clk = clk_register_gate(NULL, "usbh1_clk", "pll3_48m_clk", 0, | ||
268 | PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock); | ||
269 | clk_register_clkdev(clk, NULL, "usbh.1_clk"); | ||
270 | |||
271 | clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0, | ||
272 | PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); | ||
273 | clk_register_clkdev(clk, NULL, "designware_udc"); | ||
274 | |||
275 | /* clock derived from ahb clk */ | ||
276 | clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2, | ||
277 | 1); | ||
278 | clk_register_clkdev(clk, "ahbmult2_clk", NULL); | ||
279 | |||
280 | clk = clk_register_mux(NULL, "ddr_clk", ddr_parents, | ||
281 | ARRAY_SIZE(ddr_parents), | ||
282 | 0, PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0, | ||
283 | &_lock); | ||
284 | clk_register_clkdev(clk, "ddr_clk", NULL); | ||
285 | |||
286 | clk = clk_register_divider(NULL, "apb_clk", "ahb_clk", | ||
287 | CLK_SET_RATE_PARENT, CORE_CLK_CFG, PCLK_RATIO_SHIFT, | ||
288 | PCLK_RATIO_MASK, 0, &_lock); | ||
289 | clk_register_clkdev(clk, "apb_clk", NULL); | ||
290 | |||
291 | clk = clk_register_gate(NULL, "dma_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
292 | DMA_CLK_ENB, 0, &_lock); | ||
293 | clk_register_clkdev(clk, NULL, "fc400000.dma"); | ||
294 | |||
295 | clk = clk_register_gate(NULL, "fsmc_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
296 | FSMC_CLK_ENB, 0, &_lock); | ||
297 | clk_register_clkdev(clk, NULL, "d1800000.flash"); | ||
298 | |||
299 | clk = clk_register_gate(NULL, "gmac_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
300 | GMAC_CLK_ENB, 0, &_lock); | ||
301 | clk_register_clkdev(clk, NULL, "gmac"); | ||
302 | |||
303 | clk = clk_register_gate(NULL, "i2c_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
304 | I2C_CLK_ENB, 0, &_lock); | ||
305 | clk_register_clkdev(clk, NULL, "d0200000.i2c"); | ||
306 | |||
307 | clk = clk_register_gate(NULL, "jpeg_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
308 | JPEG_CLK_ENB, 0, &_lock); | ||
309 | clk_register_clkdev(clk, NULL, "jpeg"); | ||
310 | |||
311 | clk = clk_register_gate(NULL, "smi_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
312 | SMI_CLK_ENB, 0, &_lock); | ||
313 | clk_register_clkdev(clk, NULL, "fc000000.flash"); | ||
314 | |||
315 | /* clock derived from apb clk */ | ||
316 | clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
317 | ADC_CLK_ENB, 0, &_lock); | ||
318 | clk_register_clkdev(clk, NULL, "adc"); | ||
319 | |||
320 | clk = clk_register_fixed_factor(NULL, "gpio0_clk", "apb_clk", 0, 1, 1); | ||
321 | clk_register_clkdev(clk, NULL, "f0100000.gpio"); | ||
322 | |||
323 | clk = clk_register_gate(NULL, "gpio1_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
324 | GPIO1_CLK_ENB, 0, &_lock); | ||
325 | clk_register_clkdev(clk, NULL, "fc980000.gpio"); | ||
326 | |||
327 | clk = clk_register_gate(NULL, "gpio2_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
328 | GPIO2_CLK_ENB, 0, &_lock); | ||
329 | clk_register_clkdev(clk, NULL, "d8100000.gpio"); | ||
330 | |||
331 | clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
332 | SSP0_CLK_ENB, 0, &_lock); | ||
333 | clk_register_clkdev(clk, NULL, "ssp-pl022.0"); | ||
334 | |||
335 | clk = clk_register_gate(NULL, "ssp1_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
336 | SSP1_CLK_ENB, 0, &_lock); | ||
337 | clk_register_clkdev(clk, NULL, "ssp-pl022.1"); | ||
338 | |||
339 | clk = clk_register_gate(NULL, "ssp2_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
340 | SSP2_CLK_ENB, 0, &_lock); | ||
341 | clk_register_clkdev(clk, NULL, "ssp-pl022.2"); | ||
342 | } | ||