diff options
-rw-r--r-- | arch/arm/mach-imx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/clk-cpu.c | 107 | ||||
-rw-r--r-- | arch/arm/mach-imx/clk.h | 4 |
3 files changed, 112 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 6e4fcd8339cd..b8580f363e51 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
@@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci- | |||
12 | obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o | 12 | obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o |
13 | 13 | ||
14 | imx5-pm-$(CONFIG_PM) += pm-imx5.o | 14 | imx5-pm-$(CONFIG_PM) += pm-imx5.o |
15 | obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o $(imx5-pm-y) | 15 | obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y) |
16 | 16 | ||
17 | obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ | 17 | obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ |
18 | clk-pfd.o clk-busy.o clk.o \ | 18 | clk-pfd.o clk-busy.o clk.o \ |
diff --git a/arch/arm/mach-imx/clk-cpu.c b/arch/arm/mach-imx/clk-cpu.c new file mode 100644 index 000000000000..aa1c345e2a19 --- /dev/null +++ b/arch/arm/mach-imx/clk-cpu.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/slab.h> | ||
15 | |||
16 | struct clk_cpu { | ||
17 | struct clk_hw hw; | ||
18 | struct clk *div; | ||
19 | struct clk *mux; | ||
20 | struct clk *pll; | ||
21 | struct clk *step; | ||
22 | }; | ||
23 | |||
24 | static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw) | ||
25 | { | ||
26 | return container_of(hw, struct clk_cpu, hw); | ||
27 | } | ||
28 | |||
29 | static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw, | ||
30 | unsigned long parent_rate) | ||
31 | { | ||
32 | struct clk_cpu *cpu = to_clk_cpu(hw); | ||
33 | |||
34 | return clk_get_rate(cpu->div); | ||
35 | } | ||
36 | |||
37 | static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, | ||
38 | unsigned long *prate) | ||
39 | { | ||
40 | struct clk_cpu *cpu = to_clk_cpu(hw); | ||
41 | |||
42 | return clk_round_rate(cpu->pll, rate); | ||
43 | } | ||
44 | |||
45 | static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, | ||
46 | unsigned long parent_rate) | ||
47 | { | ||
48 | struct clk_cpu *cpu = to_clk_cpu(hw); | ||
49 | int ret; | ||
50 | |||
51 | /* switch to PLL bypass clock */ | ||
52 | ret = clk_set_parent(cpu->mux, cpu->step); | ||
53 | if (ret) | ||
54 | return ret; | ||
55 | |||
56 | /* reprogram PLL */ | ||
57 | ret = clk_set_rate(cpu->pll, rate); | ||
58 | if (ret) { | ||
59 | clk_set_parent(cpu->mux, cpu->pll); | ||
60 | return ret; | ||
61 | } | ||
62 | /* switch back to PLL clock */ | ||
63 | clk_set_parent(cpu->mux, cpu->pll); | ||
64 | |||
65 | /* Ensure the divider is what we expect */ | ||
66 | clk_set_rate(cpu->div, rate); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static const struct clk_ops clk_cpu_ops = { | ||
72 | .recalc_rate = clk_cpu_recalc_rate, | ||
73 | .round_rate = clk_cpu_round_rate, | ||
74 | .set_rate = clk_cpu_set_rate, | ||
75 | }; | ||
76 | |||
77 | struct clk *imx_clk_cpu(const char *name, const char *parent_name, | ||
78 | struct clk *div, struct clk *mux, struct clk *pll, | ||
79 | struct clk *step) | ||
80 | { | ||
81 | struct clk_cpu *cpu; | ||
82 | struct clk *clk; | ||
83 | struct clk_init_data init; | ||
84 | |||
85 | cpu = kzalloc(sizeof(*cpu), GFP_KERNEL); | ||
86 | if (!cpu) | ||
87 | return ERR_PTR(-ENOMEM); | ||
88 | |||
89 | cpu->div = div; | ||
90 | cpu->mux = mux; | ||
91 | cpu->pll = pll; | ||
92 | cpu->step = step; | ||
93 | |||
94 | init.name = name; | ||
95 | init.ops = &clk_cpu_ops; | ||
96 | init.flags = 0; | ||
97 | init.parent_names = &parent_name; | ||
98 | init.num_parents = 1; | ||
99 | |||
100 | cpu->hw.init = &init; | ||
101 | |||
102 | clk = clk_register(NULL, &cpu->hw); | ||
103 | if (IS_ERR(clk)) | ||
104 | kfree(cpu); | ||
105 | |||
106 | return clk; | ||
107 | } | ||
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 4cdf8b6a74e8..5ef82e2f8fc5 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h | |||
@@ -131,4 +131,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name, | |||
131 | CLK_SET_RATE_PARENT, mult, div); | 131 | CLK_SET_RATE_PARENT, mult, div); |
132 | } | 132 | } |
133 | 133 | ||
134 | struct clk *imx_clk_cpu(const char *name, const char *parent_name, | ||
135 | struct clk *div, struct clk *mux, struct clk *pll, | ||
136 | struct clk *step); | ||
137 | |||
134 | #endif | 138 | #endif |