diff options
author | Tero Kristo <t-kristo@ti.com> | 2013-06-12 09:04:34 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-01-17 15:34:55 -0500 |
commit | f38b0dd63f0d0cca753bf0997eefdfb23dcc9518 (patch) | |
tree | 9945b442a5015de45cefcf9d3d91bcd8c2a28016 | |
parent | 819b4861c18d602463cfe815041d11fd81002654 (diff) |
CLK: TI: Add DPLL clock support
The OMAP clock driver now supports DPLL clock type. This patch also
adds support for DT DPLL nodes.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | Documentation/devicetree/bindings/clock/ti/dpll.txt | 75 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock.h | 164 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock3xxx.h | 2 | ||||
-rw-r--r-- | drivers/clk/ti/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/ti/dpll.c | 558 | ||||
-rw-r--r-- | include/linux/clk/ti.h | 172 |
6 files changed, 807 insertions, 165 deletions
diff --git a/Documentation/devicetree/bindings/clock/ti/dpll.txt b/Documentation/devicetree/bindings/clock/ti/dpll.txt new file mode 100644 index 000000000000..30bfdb7c9f18 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/dpll.txt | |||
@@ -0,0 +1,75 @@ | |||
1 | Binding for Texas Instruments DPLL clock. | ||
2 | |||
3 | Binding status: Unstable - ABI compatibility may be broken in the future | ||
4 | |||
5 | This binding uses the common clock binding[1]. It assumes a | ||
6 | register-mapped DPLL with usually two selectable input clocks | ||
7 | (reference clock and bypass clock), with digital phase locked | ||
8 | loop logic for multiplying the input clock to a desired output | ||
9 | clock. This clock also typically supports different operation | ||
10 | modes (locked, low power stop etc.) This binding has several | ||
11 | sub-types, which effectively result in slightly different setup | ||
12 | for the actual DPLL clock. | ||
13 | |||
14 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt | ||
15 | |||
16 | Required properties: | ||
17 | - compatible : shall be one of: | ||
18 | "ti,omap3-dpll-clock", | ||
19 | "ti,omap3-dpll-core-clock", | ||
20 | "ti,omap3-dpll-per-clock", | ||
21 | "ti,omap3-dpll-per-j-type-clock", | ||
22 | "ti,omap4-dpll-clock", | ||
23 | "ti,omap4-dpll-x2-clock", | ||
24 | "ti,omap4-dpll-core-clock", | ||
25 | "ti,omap4-dpll-m4xen-clock", | ||
26 | "ti,omap4-dpll-j-type-clock", | ||
27 | "ti,am3-dpll-no-gate-clock", | ||
28 | "ti,am3-dpll-j-type-clock", | ||
29 | "ti,am3-dpll-no-gate-j-type-clock", | ||
30 | "ti,am3-dpll-clock", | ||
31 | "ti,am3-dpll-core-clock", | ||
32 | "ti,am3-dpll-x2-clock", | ||
33 | |||
34 | - #clock-cells : from common clock binding; shall be set to 0. | ||
35 | - clocks : link phandles of parent clocks, first entry lists reference clock | ||
36 | and second entry bypass clock | ||
37 | - reg : offsets for the register set for controlling the DPLL. | ||
38 | Registers are listed in following order: | ||
39 | "control" - contains the control register base address | ||
40 | "idlest" - contains the idle status register base address | ||
41 | "mult-div1" - contains the multiplier / divider register base address | ||
42 | "autoidle" - contains the autoidle register base address (optional) | ||
43 | ti,am3-* dpll types do not have autoidle register | ||
44 | |||
45 | Optional properties: | ||
46 | - DPLL mode setting - defining any one or more of the following overrides | ||
47 | default setting. | ||
48 | - ti,low-power-stop : DPLL supports low power stop mode, gating output | ||
49 | - ti,low-power-bypass : DPLL output matches rate of parent bypass clock | ||
50 | - ti,lock : DPLL locks in programmed rate | ||
51 | |||
52 | Examples: | ||
53 | dpll_core_ck: dpll_core_ck@44e00490 { | ||
54 | #clock-cells = <0>; | ||
55 | compatible = "ti,omap4-dpll-core-clock"; | ||
56 | clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; | ||
57 | reg = <0x490>, <0x45c>, <0x488>, <0x468>; | ||
58 | }; | ||
59 | |||
60 | dpll2_ck: dpll2_ck@48004004 { | ||
61 | #clock-cells = <0>; | ||
62 | compatible = "ti,omap3-dpll-clock"; | ||
63 | clocks = <&sys_ck>, <&dpll2_fck>; | ||
64 | ti,low-power-stop; | ||
65 | ti,low-power-bypass; | ||
66 | ti,lock; | ||
67 | reg = <0x4>, <0x24>, <0x34>, <0x40>; | ||
68 | }; | ||
69 | |||
70 | dpll_core_ck: dpll_core_ck@44e00490 { | ||
71 | #clock-cells = <0>; | ||
72 | compatible = "ti,am3-dpll-core-clock"; | ||
73 | clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; | ||
74 | reg = <0x90>, <0x5c>, <0x68>; | ||
75 | }; | ||
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 82916cc82c92..b345f3ea8617 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include <linux/clkdev.h> | 22 | #include <linux/clkdev.h> |
23 | #include <linux/clk-provider.h> | 23 | #include <linux/clk-provider.h> |
24 | #include <linux/clk/ti.h> | ||
24 | 25 | ||
25 | struct omap_clk { | 26 | struct omap_clk { |
26 | u16 cpu; | 27 | u16 cpu; |
@@ -37,7 +38,6 @@ struct omap_clk { | |||
37 | } | 38 | } |
38 | 39 | ||
39 | struct clockdomain; | 40 | struct clockdomain; |
40 | #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) | ||
41 | 41 | ||
42 | #define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \ | 42 | #define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \ |
43 | static struct clk _name = { \ | 43 | static struct clk _name = { \ |
@@ -178,141 +178,6 @@ struct clksel { | |||
178 | const struct clksel_rate *rates; | 178 | const struct clksel_rate *rates; |
179 | }; | 179 | }; |
180 | 180 | ||
181 | /** | ||
182 | * struct dpll_data - DPLL registers and integration data | ||
183 | * @mult_div1_reg: register containing the DPLL M and N bitfields | ||
184 | * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg | ||
185 | * @div1_mask: mask of the DPLL N bitfield in @mult_div1_reg | ||
186 | * @clk_bypass: struct clk pointer to the clock's bypass clock input | ||
187 | * @clk_ref: struct clk pointer to the clock's reference clock input | ||
188 | * @control_reg: register containing the DPLL mode bitfield | ||
189 | * @enable_mask: mask of the DPLL mode bitfield in @control_reg | ||
190 | * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate() | ||
191 | * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate() | ||
192 | * @last_rounded_m4xen: cache of the last M4X result of | ||
193 | * omap4_dpll_regm4xen_round_rate() | ||
194 | * @last_rounded_lpmode: cache of the last lpmode result of | ||
195 | * omap4_dpll_lpmode_recalc() | ||
196 | * @max_multiplier: maximum valid non-bypass multiplier value (actual) | ||
197 | * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate() | ||
198 | * @min_divider: minimum valid non-bypass divider value (actual) | ||
199 | * @max_divider: maximum valid non-bypass divider value (actual) | ||
200 | * @modes: possible values of @enable_mask | ||
201 | * @autoidle_reg: register containing the DPLL autoidle mode bitfield | ||
202 | * @idlest_reg: register containing the DPLL idle status bitfield | ||
203 | * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg | ||
204 | * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg | ||
205 | * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg | ||
206 | * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg | ||
207 | * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg | ||
208 | * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg | ||
209 | * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs | ||
210 | * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs | ||
211 | * @flags: DPLL type/features (see below) | ||
212 | * | ||
213 | * Possible values for @flags: | ||
214 | * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs) | ||
215 | * | ||
216 | * @freqsel_mask is only used on the OMAP34xx family and AM35xx. | ||
217 | * | ||
218 | * XXX Some DPLLs have multiple bypass inputs, so it's not technically | ||
219 | * correct to only have one @clk_bypass pointer. | ||
220 | * | ||
221 | * XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m, | ||
222 | * @last_rounded_n) should be separated from the runtime-fixed fields | ||
223 | * and placed into a different structure, so that the runtime-fixed data | ||
224 | * can be placed into read-only space. | ||
225 | */ | ||
226 | struct dpll_data { | ||
227 | void __iomem *mult_div1_reg; | ||
228 | u32 mult_mask; | ||
229 | u32 div1_mask; | ||
230 | struct clk *clk_bypass; | ||
231 | struct clk *clk_ref; | ||
232 | void __iomem *control_reg; | ||
233 | u32 enable_mask; | ||
234 | unsigned long last_rounded_rate; | ||
235 | u16 last_rounded_m; | ||
236 | u8 last_rounded_m4xen; | ||
237 | u8 last_rounded_lpmode; | ||
238 | u16 max_multiplier; | ||
239 | u8 last_rounded_n; | ||
240 | u8 min_divider; | ||
241 | u16 max_divider; | ||
242 | u8 modes; | ||
243 | void __iomem *autoidle_reg; | ||
244 | void __iomem *idlest_reg; | ||
245 | u32 autoidle_mask; | ||
246 | u32 freqsel_mask; | ||
247 | u32 idlest_mask; | ||
248 | u32 dco_mask; | ||
249 | u32 sddiv_mask; | ||
250 | u32 lpmode_mask; | ||
251 | u32 m4xen_mask; | ||
252 | u8 auto_recal_bit; | ||
253 | u8 recal_en_bit; | ||
254 | u8 recal_st_bit; | ||
255 | u8 flags; | ||
256 | }; | ||
257 | |||
258 | /* | ||
259 | * struct clk.flags possibilities | ||
260 | * | ||
261 | * XXX document the rest of the clock flags here | ||
262 | * | ||
263 | * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL | ||
264 | * bits share the same register. This flag allows the | ||
265 | * omap4_dpllmx*() code to determine which GATE_CTRL bit field | ||
266 | * should be used. This is a temporary solution - a better approach | ||
267 | * would be to associate clock type-specific data with the clock, | ||
268 | * similar to the struct dpll_data approach. | ||
269 | */ | ||
270 | #define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */ | ||
271 | #define CLOCK_IDLE_CONTROL (1 << 1) | ||
272 | #define CLOCK_NO_IDLE_PARENT (1 << 2) | ||
273 | #define ENABLE_ON_INIT (1 << 3) /* Enable upon framework init */ | ||
274 | #define INVERT_ENABLE (1 << 4) /* 0 enables, 1 disables */ | ||
275 | #define CLOCK_CLKOUTX2 (1 << 5) | ||
276 | |||
277 | /** | ||
278 | * struct clk_hw_omap - OMAP struct clk | ||
279 | * @node: list_head connecting this clock into the full clock list | ||
280 | * @enable_reg: register to write to enable the clock (see @enable_bit) | ||
281 | * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg) | ||
282 | * @flags: see "struct clk.flags possibilities" above | ||
283 | * @clksel_reg: for clksel clks, register va containing src/divisor select | ||
284 | * @clksel_mask: bitmask in @clksel_reg for the src/divisor selector | ||
285 | * @clksel: for clksel clks, pointer to struct clksel for this clock | ||
286 | * @dpll_data: for DPLLs, pointer to struct dpll_data for this clock | ||
287 | * @clkdm_name: clockdomain name that this clock is contained in | ||
288 | * @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime | ||
289 | * @rate_offset: bitshift for rate selection bitfield (OMAP1 only) | ||
290 | * @src_offset: bitshift for source selection bitfield (OMAP1 only) | ||
291 | * | ||
292 | * XXX @rate_offset, @src_offset should probably be removed and OMAP1 | ||
293 | * clock code converted to use clksel. | ||
294 | * | ||
295 | */ | ||
296 | |||
297 | struct clk_hw_omap_ops; | ||
298 | |||
299 | struct clk_hw_omap { | ||
300 | struct clk_hw hw; | ||
301 | struct list_head node; | ||
302 | unsigned long fixed_rate; | ||
303 | u8 fixed_div; | ||
304 | void __iomem *enable_reg; | ||
305 | u8 enable_bit; | ||
306 | u8 flags; | ||
307 | void __iomem *clksel_reg; | ||
308 | u32 clksel_mask; | ||
309 | const struct clksel *clksel; | ||
310 | struct dpll_data *dpll_data; | ||
311 | const char *clkdm_name; | ||
312 | struct clockdomain *clkdm; | ||
313 | const struct clk_hw_omap_ops *ops; | ||
314 | }; | ||
315 | |||
316 | struct clk_hw_omap_ops { | 181 | struct clk_hw_omap_ops { |
317 | void (*find_idlest)(struct clk_hw_omap *oclk, | 182 | void (*find_idlest)(struct clk_hw_omap *oclk, |
318 | void __iomem **idlest_reg, | 183 | void __iomem **idlest_reg, |
@@ -348,36 +213,13 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, | |||
348 | #define OMAP4XXX_EN_DPLL_FRBYPASS 0x6 | 213 | #define OMAP4XXX_EN_DPLL_FRBYPASS 0x6 |
349 | #define OMAP4XXX_EN_DPLL_LOCKED 0x7 | 214 | #define OMAP4XXX_EN_DPLL_LOCKED 0x7 |
350 | 215 | ||
351 | /* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */ | ||
352 | #define DPLL_LOW_POWER_STOP 0x1 | ||
353 | #define DPLL_LOW_POWER_BYPASS 0x5 | ||
354 | #define DPLL_LOCKED 0x7 | ||
355 | |||
356 | /* DPLL Type and DCO Selection Flags */ | ||
357 | #define DPLL_J_TYPE 0x1 | ||
358 | |||
359 | long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, | ||
360 | unsigned long *parent_rate); | ||
361 | unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); | ||
362 | int omap3_noncore_dpll_enable(struct clk_hw *hw); | ||
363 | void omap3_noncore_dpll_disable(struct clk_hw *hw); | ||
364 | int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, | ||
365 | unsigned long parent_rate); | ||
366 | u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); | 216 | u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); |
367 | void omap3_dpll_allow_idle(struct clk_hw_omap *clk); | 217 | void omap3_dpll_allow_idle(struct clk_hw_omap *clk); |
368 | void omap3_dpll_deny_idle(struct clk_hw_omap *clk); | 218 | void omap3_dpll_deny_idle(struct clk_hw_omap *clk); |
369 | unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, | ||
370 | unsigned long parent_rate); | ||
371 | int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk); | 219 | int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk); |
372 | void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk); | 220 | void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk); |
373 | void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk); | 221 | void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk); |
374 | unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, | ||
375 | unsigned long parent_rate); | ||
376 | long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, | ||
377 | unsigned long target_rate, | ||
378 | unsigned long *parent_rate); | ||
379 | 222 | ||
380 | void omap2_init_clk_clkdm(struct clk_hw *clk); | ||
381 | void __init omap2_clk_disable_clkdm_control(void); | 223 | void __init omap2_clk_disable_clkdm_control(void); |
382 | 224 | ||
383 | /* clkt_clksel.c public functions */ | 225 | /* clkt_clksel.c public functions */ |
@@ -396,7 +238,6 @@ int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val); | |||
396 | extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); | 238 | extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); |
397 | extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); | 239 | extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); |
398 | 240 | ||
399 | u8 omap2_init_dpll_parent(struct clk_hw *hw); | ||
400 | unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); | 241 | unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); |
401 | 242 | ||
402 | int omap2_dflt_clk_enable(struct clk_hw *hw); | 243 | int omap2_dflt_clk_enable(struct clk_hw *hw); |
@@ -408,7 +249,6 @@ void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, | |||
408 | void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, | 249 | void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, |
409 | void __iomem **idlest_reg, | 250 | void __iomem **idlest_reg, |
410 | u8 *idlest_bit, u8 *idlest_val); | 251 | u8 *idlest_bit, u8 *idlest_val); |
411 | void omap2_init_clk_hw_omap_clocks(struct clk *clk); | ||
412 | int omap2_clk_enable_autoidle_all(void); | 252 | int omap2_clk_enable_autoidle_all(void); |
413 | int omap2_clk_disable_autoidle_all(void); | 253 | int omap2_clk_disable_autoidle_all(void); |
414 | int omap2_clk_allow_idle(struct clk *clk); | 254 | int omap2_clk_allow_idle(struct clk *clk); |
@@ -433,10 +273,8 @@ extern const struct clksel_rate gfx_l3_rates[]; | |||
433 | extern const struct clksel_rate dsp_ick_rates[]; | 273 | extern const struct clksel_rate dsp_ick_rates[]; |
434 | extern struct clk dummy_ck; | 274 | extern struct clk dummy_ck; |
435 | 275 | ||
436 | extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; | ||
437 | extern const struct clk_hw_omap_ops clkhwops_iclk_wait; | 276 | extern const struct clk_hw_omap_ops clkhwops_iclk_wait; |
438 | extern const struct clk_hw_omap_ops clkhwops_wait; | 277 | extern const struct clk_hw_omap_ops clkhwops_wait; |
439 | extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; | ||
440 | extern const struct clk_hw_omap_ops clkhwops_iclk; | 278 | extern const struct clk_hw_omap_ops clkhwops_iclk; |
441 | extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait; | 279 | extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait; |
442 | extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; | 280 | extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; |
diff --git a/arch/arm/mach-omap2/clock3xxx.h b/arch/arm/mach-omap2/clock3xxx.h index 8cd4b0a882ae..dab90e281aeb 100644 --- a/arch/arm/mach-omap2/clock3xxx.h +++ b/arch/arm/mach-omap2/clock3xxx.h | |||
@@ -9,8 +9,6 @@ | |||
9 | #define __ARCH_ARM_MACH_OMAP2_CLOCK3XXX_H | 9 | #define __ARCH_ARM_MACH_OMAP2_CLOCK3XXX_H |
10 | 10 | ||
11 | int omap3xxx_clk_init(void); | 11 | int omap3xxx_clk_init(void); |
12 | int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, | ||
13 | unsigned long parent_rate); | ||
14 | int omap3_core_dpll_m2_set_rate(struct clk_hw *clk, unsigned long rate, | 12 | int omap3_core_dpll_m2_set_rate(struct clk_hw *clk, unsigned long rate, |
15 | unsigned long parent_rate); | 13 | unsigned long parent_rate); |
16 | void omap3_clk_lock_dpll5(void); | 14 | void omap3_clk_lock_dpll5(void); |
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 1825f7f4bdc0..3dbb78dc9fca 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | ifneq ($(CONFIG_OF),) | 1 | ifneq ($(CONFIG_OF),) |
2 | obj-y += clk.o | 2 | obj-y += clk.o |
3 | clk-common = dpll.o | ||
3 | endif | 4 | endif |
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c new file mode 100644 index 000000000000..7e498a44f97d --- /dev/null +++ b/drivers/clk/ti/dpll.c | |||
@@ -0,0 +1,558 @@ | |||
1 | /* | ||
2 | * OMAP DPLL clock support | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments, Inc. | ||
5 | * | ||
6 | * Tero Kristo <t-kristo@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
13 | * kind, whether express or implied; without even the implied warranty | ||
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk-provider.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/of_address.h> | ||
23 | #include <linux/clk/ti.h> | ||
24 | |||
25 | #undef pr_fmt | ||
26 | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||
27 | |||
28 | #define DPLL_HAS_AUTOIDLE 0x1 | ||
29 | |||
30 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ | ||
31 | defined(CONFIG_SOC_DRA7XX) | ||
32 | static const struct clk_ops dpll_m4xen_ck_ops = { | ||
33 | .enable = &omap3_noncore_dpll_enable, | ||
34 | .disable = &omap3_noncore_dpll_disable, | ||
35 | .recalc_rate = &omap4_dpll_regm4xen_recalc, | ||
36 | .round_rate = &omap4_dpll_regm4xen_round_rate, | ||
37 | .set_rate = &omap3_noncore_dpll_set_rate, | ||
38 | .get_parent = &omap2_init_dpll_parent, | ||
39 | }; | ||
40 | #endif | ||
41 | |||
42 | static const struct clk_ops dpll_core_ck_ops = { | ||
43 | .recalc_rate = &omap3_dpll_recalc, | ||
44 | .get_parent = &omap2_init_dpll_parent, | ||
45 | }; | ||
46 | |||
47 | #ifdef CONFIG_ARCH_OMAP3 | ||
48 | static const struct clk_ops omap3_dpll_core_ck_ops = { | ||
49 | .get_parent = &omap2_init_dpll_parent, | ||
50 | .recalc_rate = &omap3_dpll_recalc, | ||
51 | .round_rate = &omap2_dpll_round_rate, | ||
52 | }; | ||
53 | #endif | ||
54 | |||
55 | static const struct clk_ops dpll_ck_ops = { | ||
56 | .enable = &omap3_noncore_dpll_enable, | ||
57 | .disable = &omap3_noncore_dpll_disable, | ||
58 | .recalc_rate = &omap3_dpll_recalc, | ||
59 | .round_rate = &omap2_dpll_round_rate, | ||
60 | .set_rate = &omap3_noncore_dpll_set_rate, | ||
61 | .get_parent = &omap2_init_dpll_parent, | ||
62 | }; | ||
63 | |||
64 | static const struct clk_ops dpll_no_gate_ck_ops = { | ||
65 | .recalc_rate = &omap3_dpll_recalc, | ||
66 | .get_parent = &omap2_init_dpll_parent, | ||
67 | .round_rate = &omap2_dpll_round_rate, | ||
68 | .set_rate = &omap3_noncore_dpll_set_rate, | ||
69 | }; | ||
70 | |||
71 | #ifdef CONFIG_ARCH_OMAP3 | ||
72 | static const struct clk_ops omap3_dpll_ck_ops = { | ||
73 | .enable = &omap3_noncore_dpll_enable, | ||
74 | .disable = &omap3_noncore_dpll_disable, | ||
75 | .get_parent = &omap2_init_dpll_parent, | ||
76 | .recalc_rate = &omap3_dpll_recalc, | ||
77 | .set_rate = &omap3_noncore_dpll_set_rate, | ||
78 | .round_rate = &omap2_dpll_round_rate, | ||
79 | }; | ||
80 | |||
81 | static const struct clk_ops omap3_dpll_per_ck_ops = { | ||
82 | .enable = &omap3_noncore_dpll_enable, | ||
83 | .disable = &omap3_noncore_dpll_disable, | ||
84 | .get_parent = &omap2_init_dpll_parent, | ||
85 | .recalc_rate = &omap3_dpll_recalc, | ||
86 | .set_rate = &omap3_dpll4_set_rate, | ||
87 | .round_rate = &omap2_dpll_round_rate, | ||
88 | }; | ||
89 | #endif | ||
90 | |||
91 | static const struct clk_ops dpll_x2_ck_ops = { | ||
92 | .recalc_rate = &omap3_clkoutx2_recalc, | ||
93 | }; | ||
94 | |||
95 | /** | ||
96 | * ti_clk_register_dpll - low level registration of a DPLL clock | ||
97 | * @hw: hardware clock definition for the clock | ||
98 | * @node: device node for the clock | ||
99 | * | ||
100 | * Finalizes DPLL registration process. In case a failure (clk-ref or | ||
101 | * clk-bypass is missing), the clock is added to retry list and | ||
102 | * the initialization is retried on later stage. | ||
103 | */ | ||
104 | static void __init ti_clk_register_dpll(struct clk_hw *hw, | ||
105 | struct device_node *node) | ||
106 | { | ||
107 | struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); | ||
108 | struct dpll_data *dd = clk_hw->dpll_data; | ||
109 | struct clk *clk; | ||
110 | |||
111 | dd->clk_ref = of_clk_get(node, 0); | ||
112 | dd->clk_bypass = of_clk_get(node, 1); | ||
113 | |||
114 | if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) { | ||
115 | pr_debug("clk-ref or clk-bypass missing for %s, retry later\n", | ||
116 | node->name); | ||
117 | if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll)) | ||
118 | return; | ||
119 | |||
120 | goto cleanup; | ||
121 | } | ||
122 | |||
123 | /* register the clock */ | ||
124 | clk = clk_register(NULL, &clk_hw->hw); | ||
125 | |||
126 | if (!IS_ERR(clk)) { | ||
127 | omap2_init_clk_hw_omap_clocks(clk); | ||
128 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
129 | kfree(clk_hw->hw.init->parent_names); | ||
130 | kfree(clk_hw->hw.init); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | cleanup: | ||
135 | kfree(clk_hw->dpll_data); | ||
136 | kfree(clk_hw->hw.init->parent_names); | ||
137 | kfree(clk_hw->hw.init); | ||
138 | kfree(clk_hw); | ||
139 | } | ||
140 | |||
141 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ | ||
142 | defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) | ||
143 | /** | ||
144 | * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock | ||
145 | * @node: device node for this clock | ||
146 | * @ops: clk_ops for this clock | ||
147 | * @hw_ops: clk_hw_ops for this clock | ||
148 | * | ||
149 | * Initializes a DPLL x 2 clock from device tree data. | ||
150 | */ | ||
151 | static void ti_clk_register_dpll_x2(struct device_node *node, | ||
152 | const struct clk_ops *ops, | ||
153 | const struct clk_hw_omap_ops *hw_ops) | ||
154 | { | ||
155 | struct clk *clk; | ||
156 | struct clk_init_data init = { NULL }; | ||
157 | struct clk_hw_omap *clk_hw; | ||
158 | const char *name = node->name; | ||
159 | const char *parent_name; | ||
160 | |||
161 | parent_name = of_clk_get_parent_name(node, 0); | ||
162 | if (!parent_name) { | ||
163 | pr_err("%s must have parent\n", node->name); | ||
164 | return; | ||
165 | } | ||
166 | |||
167 | clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); | ||
168 | if (!clk_hw) | ||
169 | return; | ||
170 | |||
171 | clk_hw->ops = hw_ops; | ||
172 | clk_hw->hw.init = &init; | ||
173 | |||
174 | init.name = name; | ||
175 | init.ops = ops; | ||
176 | init.parent_names = &parent_name; | ||
177 | init.num_parents = 1; | ||
178 | |||
179 | /* register the clock */ | ||
180 | clk = clk_register(NULL, &clk_hw->hw); | ||
181 | |||
182 | if (IS_ERR(clk)) { | ||
183 | kfree(clk_hw); | ||
184 | } else { | ||
185 | omap2_init_clk_hw_omap_clocks(clk); | ||
186 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
187 | } | ||
188 | } | ||
189 | #endif | ||
190 | |||
191 | /** | ||
192 | * of_ti_dpll_setup - Setup function for OMAP DPLL clocks | ||
193 | * @node: device node containing the DPLL info | ||
194 | * @ops: ops for the DPLL | ||
195 | * @ddt: DPLL data template to use | ||
196 | * @init_flags: flags for controlling init types | ||
197 | * | ||
198 | * Initializes a DPLL clock from device tree data. | ||
199 | */ | ||
200 | static void __init of_ti_dpll_setup(struct device_node *node, | ||
201 | const struct clk_ops *ops, | ||
202 | const struct dpll_data *ddt, | ||
203 | u8 init_flags) | ||
204 | { | ||
205 | struct clk_hw_omap *clk_hw = NULL; | ||
206 | struct clk_init_data *init = NULL; | ||
207 | const char **parent_names = NULL; | ||
208 | struct dpll_data *dd = NULL; | ||
209 | int i; | ||
210 | u8 dpll_mode = 0; | ||
211 | |||
212 | dd = kzalloc(sizeof(*dd), GFP_KERNEL); | ||
213 | clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); | ||
214 | init = kzalloc(sizeof(*init), GFP_KERNEL); | ||
215 | if (!dd || !clk_hw || !init) | ||
216 | goto cleanup; | ||
217 | |||
218 | memcpy(dd, ddt, sizeof(*dd)); | ||
219 | |||
220 | clk_hw->dpll_data = dd; | ||
221 | clk_hw->ops = &clkhwops_omap3_dpll; | ||
222 | clk_hw->hw.init = init; | ||
223 | clk_hw->flags = MEMMAP_ADDRESSING; | ||
224 | |||
225 | init->name = node->name; | ||
226 | init->ops = ops; | ||
227 | |||
228 | init->num_parents = of_clk_get_parent_count(node); | ||
229 | if (init->num_parents < 1) { | ||
230 | pr_err("%s must have parent(s)\n", node->name); | ||
231 | goto cleanup; | ||
232 | } | ||
233 | |||
234 | parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); | ||
235 | if (!parent_names) | ||
236 | goto cleanup; | ||
237 | |||
238 | for (i = 0; i < init->num_parents; i++) | ||
239 | parent_names[i] = of_clk_get_parent_name(node, i); | ||
240 | |||
241 | init->parent_names = parent_names; | ||
242 | |||
243 | dd->control_reg = ti_clk_get_reg_addr(node, 0); | ||
244 | dd->idlest_reg = ti_clk_get_reg_addr(node, 1); | ||
245 | dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2); | ||
246 | |||
247 | if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg) | ||
248 | goto cleanup; | ||
249 | |||
250 | if (init_flags & DPLL_HAS_AUTOIDLE) { | ||
251 | dd->autoidle_reg = ti_clk_get_reg_addr(node, 3); | ||
252 | if (!dd->autoidle_reg) | ||
253 | goto cleanup; | ||
254 | } | ||
255 | |||
256 | if (of_property_read_bool(node, "ti,low-power-stop")) | ||
257 | dpll_mode |= 1 << DPLL_LOW_POWER_STOP; | ||
258 | |||
259 | if (of_property_read_bool(node, "ti,low-power-bypass")) | ||
260 | dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS; | ||
261 | |||
262 | if (of_property_read_bool(node, "ti,lock")) | ||
263 | dpll_mode |= 1 << DPLL_LOCKED; | ||
264 | |||
265 | if (dpll_mode) | ||
266 | dd->modes = dpll_mode; | ||
267 | |||
268 | ti_clk_register_dpll(&clk_hw->hw, node); | ||
269 | return; | ||
270 | |||
271 | cleanup: | ||
272 | kfree(dd); | ||
273 | kfree(parent_names); | ||
274 | kfree(init); | ||
275 | kfree(clk_hw); | ||
276 | } | ||
277 | |||
278 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ | ||
279 | defined(CONFIG_SOC_DRA7XX) | ||
280 | static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node) | ||
281 | { | ||
282 | ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx); | ||
283 | } | ||
284 | CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", | ||
285 | of_ti_omap4_dpll_x2_setup); | ||
286 | #endif | ||
287 | |||
288 | #ifdef CONFIG_SOC_AM33XX | ||
289 | static void __init of_ti_am3_dpll_x2_setup(struct device_node *node) | ||
290 | { | ||
291 | ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL); | ||
292 | } | ||
293 | CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock", | ||
294 | of_ti_am3_dpll_x2_setup); | ||
295 | #endif | ||
296 | |||
297 | #ifdef CONFIG_ARCH_OMAP3 | ||
298 | static void __init of_ti_omap3_dpll_setup(struct device_node *node) | ||
299 | { | ||
300 | const struct dpll_data dd = { | ||
301 | .idlest_mask = 0x1, | ||
302 | .enable_mask = 0x7, | ||
303 | .autoidle_mask = 0x7, | ||
304 | .mult_mask = 0x7ff << 8, | ||
305 | .div1_mask = 0x7f, | ||
306 | .max_multiplier = 2047, | ||
307 | .max_divider = 128, | ||
308 | .min_divider = 1, | ||
309 | .freqsel_mask = 0xf0, | ||
310 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
311 | }; | ||
312 | |||
313 | of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); | ||
314 | } | ||
315 | CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock", | ||
316 | of_ti_omap3_dpll_setup); | ||
317 | |||
318 | static void __init of_ti_omap3_core_dpll_setup(struct device_node *node) | ||
319 | { | ||
320 | const struct dpll_data dd = { | ||
321 | .idlest_mask = 0x1, | ||
322 | .enable_mask = 0x7, | ||
323 | .autoidle_mask = 0x7, | ||
324 | .mult_mask = 0x7ff << 16, | ||
325 | .div1_mask = 0x7f << 8, | ||
326 | .max_multiplier = 2047, | ||
327 | .max_divider = 128, | ||
328 | .min_divider = 1, | ||
329 | .freqsel_mask = 0xf0, | ||
330 | }; | ||
331 | |||
332 | of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); | ||
333 | } | ||
334 | CLK_OF_DECLARE(ti_omap3_core_dpll_clock, "ti,omap3-dpll-core-clock", | ||
335 | of_ti_omap3_core_dpll_setup); | ||
336 | |||
337 | static void __init of_ti_omap3_per_dpll_setup(struct device_node *node) | ||
338 | { | ||
339 | const struct dpll_data dd = { | ||
340 | .idlest_mask = 0x1 << 1, | ||
341 | .enable_mask = 0x7 << 16, | ||
342 | .autoidle_mask = 0x7 << 3, | ||
343 | .mult_mask = 0x7ff << 8, | ||
344 | .div1_mask = 0x7f, | ||
345 | .max_multiplier = 2047, | ||
346 | .max_divider = 128, | ||
347 | .min_divider = 1, | ||
348 | .freqsel_mask = 0xf00000, | ||
349 | .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), | ||
350 | }; | ||
351 | |||
352 | of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); | ||
353 | } | ||
354 | CLK_OF_DECLARE(ti_omap3_per_dpll_clock, "ti,omap3-dpll-per-clock", | ||
355 | of_ti_omap3_per_dpll_setup); | ||
356 | |||
357 | static void __init of_ti_omap3_per_jtype_dpll_setup(struct device_node *node) | ||
358 | { | ||
359 | const struct dpll_data dd = { | ||
360 | .idlest_mask = 0x1 << 1, | ||
361 | .enable_mask = 0x7 << 16, | ||
362 | .autoidle_mask = 0x7 << 3, | ||
363 | .mult_mask = 0xfff << 8, | ||
364 | .div1_mask = 0x7f, | ||
365 | .max_multiplier = 4095, | ||
366 | .max_divider = 128, | ||
367 | .min_divider = 1, | ||
368 | .sddiv_mask = 0xff << 24, | ||
369 | .dco_mask = 0xe << 20, | ||
370 | .flags = DPLL_J_TYPE, | ||
371 | .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), | ||
372 | }; | ||
373 | |||
374 | of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); | ||
375 | } | ||
376 | CLK_OF_DECLARE(ti_omap3_per_jtype_dpll_clock, "ti,omap3-dpll-per-j-type-clock", | ||
377 | of_ti_omap3_per_jtype_dpll_setup); | ||
378 | #endif | ||
379 | |||
380 | static void __init of_ti_omap4_dpll_setup(struct device_node *node) | ||
381 | { | ||
382 | const struct dpll_data dd = { | ||
383 | .idlest_mask = 0x1, | ||
384 | .enable_mask = 0x7, | ||
385 | .autoidle_mask = 0x7, | ||
386 | .mult_mask = 0x7ff << 8, | ||
387 | .div1_mask = 0x7f, | ||
388 | .max_multiplier = 2047, | ||
389 | .max_divider = 128, | ||
390 | .min_divider = 1, | ||
391 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
392 | }; | ||
393 | |||
394 | of_ti_dpll_setup(node, &dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); | ||
395 | } | ||
396 | CLK_OF_DECLARE(ti_omap4_dpll_clock, "ti,omap4-dpll-clock", | ||
397 | of_ti_omap4_dpll_setup); | ||
398 | |||
399 | static void __init of_ti_omap4_core_dpll_setup(struct device_node *node) | ||
400 | { | ||
401 | const struct dpll_data dd = { | ||
402 | .idlest_mask = 0x1, | ||
403 | .enable_mask = 0x7, | ||
404 | .autoidle_mask = 0x7, | ||
405 | .mult_mask = 0x7ff << 8, | ||
406 | .div1_mask = 0x7f, | ||
407 | .max_multiplier = 2047, | ||
408 | .max_divider = 128, | ||
409 | .min_divider = 1, | ||
410 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
411 | }; | ||
412 | |||
413 | of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); | ||
414 | } | ||
415 | CLK_OF_DECLARE(ti_omap4_core_dpll_clock, "ti,omap4-dpll-core-clock", | ||
416 | of_ti_omap4_core_dpll_setup); | ||
417 | |||
418 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ | ||
419 | defined(CONFIG_SOC_DRA7XX) | ||
420 | static void __init of_ti_omap4_m4xen_dpll_setup(struct device_node *node) | ||
421 | { | ||
422 | const struct dpll_data dd = { | ||
423 | .idlest_mask = 0x1, | ||
424 | .enable_mask = 0x7, | ||
425 | .autoidle_mask = 0x7, | ||
426 | .mult_mask = 0x7ff << 8, | ||
427 | .div1_mask = 0x7f, | ||
428 | .max_multiplier = 2047, | ||
429 | .max_divider = 128, | ||
430 | .min_divider = 1, | ||
431 | .m4xen_mask = 0x800, | ||
432 | .lpmode_mask = 1 << 10, | ||
433 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
434 | }; | ||
435 | |||
436 | of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); | ||
437 | } | ||
438 | CLK_OF_DECLARE(ti_omap4_m4xen_dpll_clock, "ti,omap4-dpll-m4xen-clock", | ||
439 | of_ti_omap4_m4xen_dpll_setup); | ||
440 | |||
441 | static void __init of_ti_omap4_jtype_dpll_setup(struct device_node *node) | ||
442 | { | ||
443 | const struct dpll_data dd = { | ||
444 | .idlest_mask = 0x1, | ||
445 | .enable_mask = 0x7, | ||
446 | .autoidle_mask = 0x7, | ||
447 | .mult_mask = 0xfff << 8, | ||
448 | .div1_mask = 0xff, | ||
449 | .max_multiplier = 4095, | ||
450 | .max_divider = 256, | ||
451 | .min_divider = 1, | ||
452 | .sddiv_mask = 0xff << 24, | ||
453 | .flags = DPLL_J_TYPE, | ||
454 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
455 | }; | ||
456 | |||
457 | of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); | ||
458 | } | ||
459 | CLK_OF_DECLARE(ti_omap4_jtype_dpll_clock, "ti,omap4-dpll-j-type-clock", | ||
460 | of_ti_omap4_jtype_dpll_setup); | ||
461 | #endif | ||
462 | |||
463 | static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node) | ||
464 | { | ||
465 | const struct dpll_data dd = { | ||
466 | .idlest_mask = 0x1, | ||
467 | .enable_mask = 0x7, | ||
468 | .autoidle_mask = 0x7, | ||
469 | .mult_mask = 0x7ff << 8, | ||
470 | .div1_mask = 0x7f, | ||
471 | .max_multiplier = 2047, | ||
472 | .max_divider = 128, | ||
473 | .min_divider = 1, | ||
474 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
475 | }; | ||
476 | |||
477 | of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); | ||
478 | } | ||
479 | CLK_OF_DECLARE(ti_am3_no_gate_dpll_clock, "ti,am3-dpll-no-gate-clock", | ||
480 | of_ti_am3_no_gate_dpll_setup); | ||
481 | |||
482 | static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node) | ||
483 | { | ||
484 | const struct dpll_data dd = { | ||
485 | .idlest_mask = 0x1, | ||
486 | .enable_mask = 0x7, | ||
487 | .autoidle_mask = 0x7, | ||
488 | .mult_mask = 0x7ff << 8, | ||
489 | .div1_mask = 0x7f, | ||
490 | .max_multiplier = 4095, | ||
491 | .max_divider = 256, | ||
492 | .min_divider = 2, | ||
493 | .flags = DPLL_J_TYPE, | ||
494 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
495 | }; | ||
496 | |||
497 | of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); | ||
498 | } | ||
499 | CLK_OF_DECLARE(ti_am3_jtype_dpll_clock, "ti,am3-dpll-j-type-clock", | ||
500 | of_ti_am3_jtype_dpll_setup); | ||
501 | |||
502 | static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node) | ||
503 | { | ||
504 | const struct dpll_data dd = { | ||
505 | .idlest_mask = 0x1, | ||
506 | .enable_mask = 0x7, | ||
507 | .autoidle_mask = 0x7, | ||
508 | .mult_mask = 0x7ff << 8, | ||
509 | .div1_mask = 0x7f, | ||
510 | .max_multiplier = 2047, | ||
511 | .max_divider = 128, | ||
512 | .min_divider = 1, | ||
513 | .flags = DPLL_J_TYPE, | ||
514 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
515 | }; | ||
516 | |||
517 | of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); | ||
518 | } | ||
519 | CLK_OF_DECLARE(ti_am3_no_gate_jtype_dpll_clock, | ||
520 | "ti,am3-dpll-no-gate-j-type-clock", | ||
521 | of_ti_am3_no_gate_jtype_dpll_setup); | ||
522 | |||
523 | static void __init of_ti_am3_dpll_setup(struct device_node *node) | ||
524 | { | ||
525 | const struct dpll_data dd = { | ||
526 | .idlest_mask = 0x1, | ||
527 | .enable_mask = 0x7, | ||
528 | .autoidle_mask = 0x7, | ||
529 | .mult_mask = 0x7ff << 8, | ||
530 | .div1_mask = 0x7f, | ||
531 | .max_multiplier = 2047, | ||
532 | .max_divider = 128, | ||
533 | .min_divider = 1, | ||
534 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
535 | }; | ||
536 | |||
537 | of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); | ||
538 | } | ||
539 | CLK_OF_DECLARE(ti_am3_dpll_clock, "ti,am3-dpll-clock", of_ti_am3_dpll_setup); | ||
540 | |||
541 | static void __init of_ti_am3_core_dpll_setup(struct device_node *node) | ||
542 | { | ||
543 | const struct dpll_data dd = { | ||
544 | .idlest_mask = 0x1, | ||
545 | .enable_mask = 0x7, | ||
546 | .autoidle_mask = 0x7, | ||
547 | .mult_mask = 0x7ff << 8, | ||
548 | .div1_mask = 0x7f, | ||
549 | .max_multiplier = 2047, | ||
550 | .max_divider = 128, | ||
551 | .min_divider = 1, | ||
552 | .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), | ||
553 | }; | ||
554 | |||
555 | of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, 0); | ||
556 | } | ||
557 | CLK_OF_DECLARE(ti_am3_core_dpll_clock, "ti,am3-dpll-core-clock", | ||
558 | of_ti_am3_core_dpll_setup); | ||
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index c6eded5eea76..3f9de3973582 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h | |||
@@ -18,6 +18,153 @@ | |||
18 | #include <linux/clkdev.h> | 18 | #include <linux/clkdev.h> |
19 | 19 | ||
20 | /** | 20 | /** |
21 | * struct dpll_data - DPLL registers and integration data | ||
22 | * @mult_div1_reg: register containing the DPLL M and N bitfields | ||
23 | * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg | ||
24 | * @div1_mask: mask of the DPLL N bitfield in @mult_div1_reg | ||
25 | * @clk_bypass: struct clk pointer to the clock's bypass clock input | ||
26 | * @clk_ref: struct clk pointer to the clock's reference clock input | ||
27 | * @control_reg: register containing the DPLL mode bitfield | ||
28 | * @enable_mask: mask of the DPLL mode bitfield in @control_reg | ||
29 | * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate() | ||
30 | * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate() | ||
31 | * @last_rounded_m4xen: cache of the last M4X result of | ||
32 | * omap4_dpll_regm4xen_round_rate() | ||
33 | * @last_rounded_lpmode: cache of the last lpmode result of | ||
34 | * omap4_dpll_lpmode_recalc() | ||
35 | * @max_multiplier: maximum valid non-bypass multiplier value (actual) | ||
36 | * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate() | ||
37 | * @min_divider: minimum valid non-bypass divider value (actual) | ||
38 | * @max_divider: maximum valid non-bypass divider value (actual) | ||
39 | * @modes: possible values of @enable_mask | ||
40 | * @autoidle_reg: register containing the DPLL autoidle mode bitfield | ||
41 | * @idlest_reg: register containing the DPLL idle status bitfield | ||
42 | * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg | ||
43 | * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg | ||
44 | * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg | ||
45 | * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg | ||
46 | * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg | ||
47 | * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg | ||
48 | * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs | ||
49 | * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs | ||
50 | * @flags: DPLL type/features (see below) | ||
51 | * | ||
52 | * Possible values for @flags: | ||
53 | * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs) | ||
54 | * | ||
55 | * @freqsel_mask is only used on the OMAP34xx family and AM35xx. | ||
56 | * | ||
57 | * XXX Some DPLLs have multiple bypass inputs, so it's not technically | ||
58 | * correct to only have one @clk_bypass pointer. | ||
59 | * | ||
60 | * XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m, | ||
61 | * @last_rounded_n) should be separated from the runtime-fixed fields | ||
62 | * and placed into a different structure, so that the runtime-fixed data | ||
63 | * can be placed into read-only space. | ||
64 | */ | ||
65 | struct dpll_data { | ||
66 | void __iomem *mult_div1_reg; | ||
67 | u32 mult_mask; | ||
68 | u32 div1_mask; | ||
69 | struct clk *clk_bypass; | ||
70 | struct clk *clk_ref; | ||
71 | void __iomem *control_reg; | ||
72 | u32 enable_mask; | ||
73 | unsigned long last_rounded_rate; | ||
74 | u16 last_rounded_m; | ||
75 | u8 last_rounded_m4xen; | ||
76 | u8 last_rounded_lpmode; | ||
77 | u16 max_multiplier; | ||
78 | u8 last_rounded_n; | ||
79 | u8 min_divider; | ||
80 | u16 max_divider; | ||
81 | u8 modes; | ||
82 | void __iomem *autoidle_reg; | ||
83 | void __iomem *idlest_reg; | ||
84 | u32 autoidle_mask; | ||
85 | u32 freqsel_mask; | ||
86 | u32 idlest_mask; | ||
87 | u32 dco_mask; | ||
88 | u32 sddiv_mask; | ||
89 | u32 lpmode_mask; | ||
90 | u32 m4xen_mask; | ||
91 | u8 auto_recal_bit; | ||
92 | u8 recal_en_bit; | ||
93 | u8 recal_st_bit; | ||
94 | u8 flags; | ||
95 | }; | ||
96 | |||
97 | struct clk_hw_omap_ops; | ||
98 | |||
99 | /** | ||
100 | * struct clk_hw_omap - OMAP struct clk | ||
101 | * @node: list_head connecting this clock into the full clock list | ||
102 | * @enable_reg: register to write to enable the clock (see @enable_bit) | ||
103 | * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg) | ||
104 | * @flags: see "struct clk.flags possibilities" above | ||
105 | * @clksel_reg: for clksel clks, register va containing src/divisor select | ||
106 | * @clksel_mask: bitmask in @clksel_reg for the src/divisor selector | ||
107 | * @clksel: for clksel clks, pointer to struct clksel for this clock | ||
108 | * @dpll_data: for DPLLs, pointer to struct dpll_data for this clock | ||
109 | * @clkdm_name: clockdomain name that this clock is contained in | ||
110 | * @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime | ||
111 | * @ops: clock ops for this clock | ||
112 | */ | ||
113 | struct clk_hw_omap { | ||
114 | struct clk_hw hw; | ||
115 | struct list_head node; | ||
116 | unsigned long fixed_rate; | ||
117 | u8 fixed_div; | ||
118 | void __iomem *enable_reg; | ||
119 | u8 enable_bit; | ||
120 | u8 flags; | ||
121 | void __iomem *clksel_reg; | ||
122 | u32 clksel_mask; | ||
123 | const struct clksel *clksel; | ||
124 | struct dpll_data *dpll_data; | ||
125 | const char *clkdm_name; | ||
126 | struct clockdomain *clkdm; | ||
127 | const struct clk_hw_omap_ops *ops; | ||
128 | }; | ||
129 | |||
130 | /* | ||
131 | * struct clk_hw_omap.flags possibilities | ||
132 | * | ||
133 | * XXX document the rest of the clock flags here | ||
134 | * | ||
135 | * ENABLE_REG_32BIT: (OMAP1 only) clock control register must be accessed | ||
136 | * with 32bit ops, by default OMAP1 uses 16bit ops. | ||
137 | * CLOCK_IDLE_CONTROL: (OMAP1 only) clock has autoidle support. | ||
138 | * CLOCK_NO_IDLE_PARENT: (OMAP1 only) when clock is enabled, its parent | ||
139 | * clock is put to no-idle mode. | ||
140 | * ENABLE_ON_INIT: Clock is enabled on init. | ||
141 | * INVERT_ENABLE: By default, clock enable bit behavior is '1' enable, '0' | ||
142 | * disable. This inverts the behavior making '0' enable and '1' disable. | ||
143 | * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL | ||
144 | * bits share the same register. This flag allows the | ||
145 | * omap4_dpllmx*() code to determine which GATE_CTRL bit field | ||
146 | * should be used. This is a temporary solution - a better approach | ||
147 | * would be to associate clock type-specific data with the clock, | ||
148 | * similar to the struct dpll_data approach. | ||
149 | * MEMMAP_ADDRESSING: Use memmap addressing to access clock registers. | ||
150 | */ | ||
151 | #define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */ | ||
152 | #define CLOCK_IDLE_CONTROL (1 << 1) | ||
153 | #define CLOCK_NO_IDLE_PARENT (1 << 2) | ||
154 | #define ENABLE_ON_INIT (1 << 3) /* Enable upon framework init */ | ||
155 | #define INVERT_ENABLE (1 << 4) /* 0 enables, 1 disables */ | ||
156 | #define CLOCK_CLKOUTX2 (1 << 5) | ||
157 | #define MEMMAP_ADDRESSING (1 << 6) | ||
158 | |||
159 | /* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */ | ||
160 | #define DPLL_LOW_POWER_STOP 0x1 | ||
161 | #define DPLL_LOW_POWER_BYPASS 0x5 | ||
162 | #define DPLL_LOCKED 0x7 | ||
163 | |||
164 | /* DPLL Type and DCO Selection Flags */ | ||
165 | #define DPLL_J_TYPE 0x1 | ||
166 | |||
167 | /** | ||
21 | * struct ti_dt_clk - OMAP DT clock alias declarations | 168 | * struct ti_dt_clk - OMAP DT clock alias declarations |
22 | * @lk: clock lookup definition | 169 | * @lk: clock lookup definition |
23 | * @node_name: clock DT node to map to | 170 | * @node_name: clock DT node to map to |
@@ -68,10 +215,35 @@ struct ti_clk_ll_ops { | |||
68 | 215 | ||
69 | extern struct ti_clk_ll_ops *ti_clk_ll_ops; | 216 | extern struct ti_clk_ll_ops *ti_clk_ll_ops; |
70 | 217 | ||
218 | #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) | ||
219 | |||
220 | void omap2_init_clk_hw_omap_clocks(struct clk *clk); | ||
221 | int omap3_noncore_dpll_enable(struct clk_hw *hw); | ||
222 | void omap3_noncore_dpll_disable(struct clk_hw *hw); | ||
223 | int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, | ||
224 | unsigned long parent_rate); | ||
225 | unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, | ||
226 | unsigned long parent_rate); | ||
227 | long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, | ||
228 | unsigned long target_rate, | ||
229 | unsigned long *parent_rate); | ||
230 | u8 omap2_init_dpll_parent(struct clk_hw *hw); | ||
231 | unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); | ||
232 | long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, | ||
233 | unsigned long *parent_rate); | ||
234 | void omap2_init_clk_clkdm(struct clk_hw *clk); | ||
235 | unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, | ||
236 | unsigned long parent_rate); | ||
237 | int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, | ||
238 | unsigned long parent_rate); | ||
239 | |||
71 | void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); | 240 | void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); |
72 | void ti_dt_clocks_register(struct ti_dt_clk *oclks); | 241 | void ti_dt_clocks_register(struct ti_dt_clk *oclks); |
73 | void ti_dt_clk_init_provider(struct device_node *np, int index); | 242 | void ti_dt_clk_init_provider(struct device_node *np, int index); |
74 | int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, | 243 | int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, |
75 | ti_of_clk_init_cb_t func); | 244 | ti_of_clk_init_cb_t func); |
76 | 245 | ||
246 | extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; | ||
247 | extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; | ||
248 | |||
77 | #endif | 249 | #endif |