diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2012-04-04 04:20:56 -0400 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2012-05-02 06:08:26 -0400 |
commit | 32af7a830fe1625fa93900606f82c541f3b3de94 (patch) | |
tree | 8db8f84fbdfcf0fb769278ecfbe9d72fe9ef812e /arch/arm/mach-imx | |
parent | a10bd67f1905b394f5a9bd610dfc8b9b9befac0e (diff) |
ARM: imx: add common clock support for clk busy
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-imx')
-rw-r--r-- | arch/arm/mach-imx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/clk-busy.c | 189 | ||||
-rw-r--r-- | arch/arm/mach-imx/clk.h | 8 |
3 files changed, 198 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 4d6be8d33a26..ae0a77960c22 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
@@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o pm-i | |||
12 | obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o | 12 | obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o |
13 | 13 | ||
14 | obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ | 14 | obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ |
15 | clk-pfd.o | 15 | clk-pfd.o clk-busy.o |
16 | 16 | ||
17 | # Support for CMOS sensor interface | 17 | # Support for CMOS sensor interface |
18 | obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o | 18 | obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o |
diff --git a/arch/arm/mach-imx/clk-busy.c b/arch/arm/mach-imx/clk-busy.c new file mode 100644 index 000000000000..1a7a8dd045a1 --- /dev/null +++ b/arch/arm/mach-imx/clk-busy.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * Copyright 2012 Linaro Ltd. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/jiffies.h> | ||
18 | #include <linux/err.h> | ||
19 | #include "clk.h" | ||
20 | |||
21 | static int clk_busy_wait(void __iomem *reg, u8 shift) | ||
22 | { | ||
23 | unsigned long timeout = jiffies + msecs_to_jiffies(10); | ||
24 | |||
25 | while (readl_relaxed(reg) & (1 << shift)) | ||
26 | if (time_after(jiffies, timeout)) | ||
27 | return -ETIMEDOUT; | ||
28 | |||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | struct clk_busy_divider { | ||
33 | struct clk_divider div; | ||
34 | const struct clk_ops *div_ops; | ||
35 | void __iomem *reg; | ||
36 | u8 shift; | ||
37 | }; | ||
38 | |||
39 | static inline struct clk_busy_divider *to_clk_busy_divider(struct clk_hw *hw) | ||
40 | { | ||
41 | struct clk_divider *div = container_of(hw, struct clk_divider, hw); | ||
42 | |||
43 | return container_of(div, struct clk_busy_divider, div); | ||
44 | } | ||
45 | |||
46 | static unsigned long clk_busy_divider_recalc_rate(struct clk_hw *hw, | ||
47 | unsigned long parent_rate) | ||
48 | { | ||
49 | struct clk_busy_divider *busy = to_clk_busy_divider(hw); | ||
50 | |||
51 | return busy->div_ops->recalc_rate(&busy->div.hw, parent_rate); | ||
52 | } | ||
53 | |||
54 | static long clk_busy_divider_round_rate(struct clk_hw *hw, unsigned long rate, | ||
55 | unsigned long *prate) | ||
56 | { | ||
57 | struct clk_busy_divider *busy = to_clk_busy_divider(hw); | ||
58 | |||
59 | return busy->div_ops->round_rate(&busy->div.hw, rate, prate); | ||
60 | } | ||
61 | |||
62 | static int clk_busy_divider_set_rate(struct clk_hw *hw, unsigned long rate, | ||
63 | unsigned long parent_rate) | ||
64 | { | ||
65 | struct clk_busy_divider *busy = to_clk_busy_divider(hw); | ||
66 | int ret; | ||
67 | |||
68 | ret = busy->div_ops->set_rate(&busy->div.hw, rate, parent_rate); | ||
69 | if (!ret) | ||
70 | ret = clk_busy_wait(busy->reg, busy->shift); | ||
71 | |||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static struct clk_ops clk_busy_divider_ops = { | ||
76 | .recalc_rate = clk_busy_divider_recalc_rate, | ||
77 | .round_rate = clk_busy_divider_round_rate, | ||
78 | .set_rate = clk_busy_divider_set_rate, | ||
79 | }; | ||
80 | |||
81 | struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, | ||
82 | void __iomem *reg, u8 shift, u8 width, | ||
83 | void __iomem *busy_reg, u8 busy_shift) | ||
84 | { | ||
85 | struct clk_busy_divider *busy; | ||
86 | struct clk *clk; | ||
87 | struct clk_init_data init; | ||
88 | |||
89 | busy = kzalloc(sizeof(*busy), GFP_KERNEL); | ||
90 | if (!busy) | ||
91 | return ERR_PTR(-ENOMEM); | ||
92 | |||
93 | busy->reg = busy_reg; | ||
94 | busy->shift = busy_shift; | ||
95 | |||
96 | busy->div.reg = reg; | ||
97 | busy->div.shift = shift; | ||
98 | busy->div.width = width; | ||
99 | busy->div.lock = &imx_ccm_lock; | ||
100 | busy->div_ops = &clk_divider_ops; | ||
101 | |||
102 | init.name = name; | ||
103 | init.ops = &clk_busy_divider_ops; | ||
104 | init.flags = CLK_SET_RATE_PARENT; | ||
105 | init.parent_names = &parent_name; | ||
106 | init.num_parents = 1; | ||
107 | |||
108 | busy->div.hw.init = &init; | ||
109 | |||
110 | clk = clk_register(NULL, &busy->div.hw); | ||
111 | if (!clk) | ||
112 | kfree(busy); | ||
113 | |||
114 | return clk; | ||
115 | } | ||
116 | |||
117 | struct clk_busy_mux { | ||
118 | struct clk_mux mux; | ||
119 | const struct clk_ops *mux_ops; | ||
120 | void __iomem *reg; | ||
121 | u8 shift; | ||
122 | }; | ||
123 | |||
124 | static inline struct clk_busy_mux *to_clk_busy_mux(struct clk_hw *hw) | ||
125 | { | ||
126 | struct clk_mux *mux = container_of(hw, struct clk_mux, hw); | ||
127 | |||
128 | return container_of(mux, struct clk_busy_mux, mux); | ||
129 | } | ||
130 | |||
131 | static u8 clk_busy_mux_get_parent(struct clk_hw *hw) | ||
132 | { | ||
133 | struct clk_busy_mux *busy = to_clk_busy_mux(hw); | ||
134 | |||
135 | return busy->mux_ops->get_parent(&busy->mux.hw); | ||
136 | } | ||
137 | |||
138 | static int clk_busy_mux_set_parent(struct clk_hw *hw, u8 index) | ||
139 | { | ||
140 | struct clk_busy_mux *busy = to_clk_busy_mux(hw); | ||
141 | int ret; | ||
142 | |||
143 | ret = busy->mux_ops->set_parent(&busy->mux.hw, index); | ||
144 | if (!ret) | ||
145 | ret = clk_busy_wait(busy->reg, busy->shift); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | struct clk_ops clk_busy_mux_ops = { | ||
151 | .get_parent = clk_busy_mux_get_parent, | ||
152 | .set_parent = clk_busy_mux_set_parent, | ||
153 | }; | ||
154 | |||
155 | struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, | ||
156 | u8 width, void __iomem *busy_reg, u8 busy_shift, | ||
157 | const char **parent_names, int num_parents) | ||
158 | { | ||
159 | struct clk_busy_mux *busy; | ||
160 | struct clk *clk; | ||
161 | struct clk_init_data init; | ||
162 | |||
163 | busy = kzalloc(sizeof(*busy), GFP_KERNEL); | ||
164 | if (!busy) | ||
165 | return ERR_PTR(-ENOMEM); | ||
166 | |||
167 | busy->reg = busy_reg; | ||
168 | busy->shift = busy_shift; | ||
169 | |||
170 | busy->mux.reg = reg; | ||
171 | busy->mux.shift = shift; | ||
172 | busy->mux.width = width; | ||
173 | busy->mux.lock = &imx_ccm_lock; | ||
174 | busy->mux_ops = &clk_mux_ops; | ||
175 | |||
176 | init.name = name; | ||
177 | init.ops = &clk_busy_mux_ops; | ||
178 | init.flags = 0; | ||
179 | init.parent_names = parent_names; | ||
180 | init.num_parents = num_parents; | ||
181 | |||
182 | busy->mux.hw.init = &init; | ||
183 | |||
184 | clk = clk_register(NULL, &busy->mux.hw); | ||
185 | if (IS_ERR(clk)) | ||
186 | kfree(busy); | ||
187 | |||
188 | return clk; | ||
189 | } | ||
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 52970996f39a..1bf64fe2523c 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h | |||
@@ -39,6 +39,14 @@ static inline struct clk *imx_clk_gate2(const char *name, const char *parent, | |||
39 | struct clk *imx_clk_pfd(const char *name, const char *parent_name, | 39 | struct clk *imx_clk_pfd(const char *name, const char *parent_name, |
40 | void __iomem *reg, u8 idx); | 40 | void __iomem *reg, u8 idx); |
41 | 41 | ||
42 | struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, | ||
43 | void __iomem *reg, u8 shift, u8 width, | ||
44 | void __iomem *busy_reg, u8 busy_shift); | ||
45 | |||
46 | struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, | ||
47 | u8 width, void __iomem *busy_reg, u8 busy_shift, | ||
48 | const char **parent_names, int num_parents); | ||
49 | |||
42 | static inline struct clk *imx_clk_fixed(const char *name, int rate) | 50 | static inline struct clk *imx_clk_fixed(const char *name, int rate) |
43 | { | 51 | { |
44 | return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); | 52 | return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); |