aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2013-09-13 13:22:27 -0400
committerMike Turquette <mturquette@linaro.org>2014-01-17 15:35:17 -0500
commit6a369c584fbe98264458b9442e780f8078f2f7ad (patch)
treed80be958f33b501a128599a0e31bec400b51fa58
parent3cd4a596224565cff00b69a02d4b5fa7432ea6d3 (diff)
clk: ti: add support for basic mux clock
ti,mux-clock provides now a binding for basic mux support. This is just using the basic clock type. 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/mux.txt76
-rw-r--r--drivers/clk/ti/Makefile2
-rw-r--r--drivers/clk/ti/composite.c2
-rw-r--r--drivers/clk/ti/mux.c246
-rw-r--r--include/linux/clk/ti.h1
5 files changed, 325 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/clock/ti/mux.txt b/Documentation/devicetree/bindings/clock/ti/mux.txt
new file mode 100644
index 000000000000..2d0d170f8001
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ti/mux.txt
@@ -0,0 +1,76 @@
1Binding for TI mux clock.
2
3Binding status: Unstable - ABI compatibility may be broken in the future
4
5This binding uses the common clock binding[1]. It assumes a
6register-mapped multiplexer with multiple input clock signals or
7parents, one of which can be selected as output. This clock does not
8gate or adjust the parent rate via a divider or multiplier.
9
10By default the "clocks" property lists the parents in the same order
11as they are programmed into the regster. E.g:
12
13 clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
14
15results in programming the register as follows:
16
17register value selected parent clock
180 foo_clock
191 bar_clock
202 baz_clock
21
22Some clock controller IPs do not allow a value of zero to be programmed
23into the register, instead indexing begins at 1. The optional property
24"index-starts-at-one" modified the scheme as follows:
25
26register value selected clock parent
271 foo_clock
282 bar_clock
293 baz_clock
30
31The binding must provide the register to control the mux. Optionally
32the number of bits to shift the control field in the register can be
33supplied. If the shift value is missing it is the same as supplying
34a zero shift.
35
36[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
37
38Required properties:
39- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock".
40- #clock-cells : from common clock binding; shall be set to 0.
41- clocks : link phandles of parent clocks
42- reg : register offset for register controlling adjustable mux
43
44Optional properties:
45- ti,bit-shift : number of bits to shift the bit-mask, defaults to
46 0 if not present
47- ti,index-starts-at-one : valid input select programming starts at 1, not
48 zero
49- ti,set-rate-parent : clk_set_rate is propagated to parent clock,
50 not supported by the composite-mux-clock subtype
51
52Examples:
53
54sys_clkin_ck: sys_clkin_ck@4a306110 {
55 #clock-cells = <0>;
56 compatible = "ti,mux-clock";
57 clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
58 reg = <0x0110>;
59 ti,index-starts-at-one;
60};
61
62abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 {
63 #clock-cells = <0>;
64 compatible = "ti,mux-clock";
65 clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
66 ti,bit-shift = <24>;
67 reg = <0x0108>;
68};
69
70mcbsp5_mux_fck: mcbsp5_mux_fck {
71 #clock-cells = <0>;
72 compatible = "ti,composite-mux-clock";
73 clocks = <&core_96m_fck>, <&mcbsp_clks>;
74 ti,bit-shift = <4>;
75 reg = <0x02d8>;
76};
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index ae7cd1e91cd2..d98a47fb13a4 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -1,5 +1,5 @@
1ifneq ($(CONFIG_OF),) 1ifneq ($(CONFIG_OF),)
2obj-y += clk.o autoidle.o clockdomain.o 2obj-y += clk.o autoidle.o clockdomain.o
3clk-common = dpll.o composite.o divider.o gate.o \ 3clk-common = dpll.o composite.o divider.o gate.o \
4 fixed-factor.o 4 fixed-factor.o mux.o
5endif 5endif
diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c
index ffb8db4829bf..19d8980ba458 100644
--- a/drivers/clk/ti/composite.c
+++ b/drivers/clk/ti/composite.c
@@ -173,7 +173,7 @@ static void __init ti_clk_register_composite(struct clk_hw *hw,
173 clk = clk_register_composite(NULL, node->name, 173 clk = clk_register_composite(NULL, node->name,
174 parent_names, num_parents, 174 parent_names, num_parents,
175 _get_hw(cclk, CLK_COMPONENT_TYPE_MUX), 175 _get_hw(cclk, CLK_COMPONENT_TYPE_MUX),
176 &clk_mux_ops, 176 &ti_clk_mux_ops,
177 _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER), 177 _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER),
178 &ti_composite_divider_ops, 178 &ti_composite_divider_ops,
179 _get_hw(cclk, CLK_COMPONENT_TYPE_GATE), 179 _get_hw(cclk, CLK_COMPONENT_TYPE_GATE),
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
new file mode 100644
index 000000000000..0197a478720c
--- /dev/null
+++ b/drivers/clk/ti/mux.c
@@ -0,0 +1,246 @@
1/*
2 * TI Multiplexer Clock
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 to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
29
30static u8 ti_clk_mux_get_parent(struct clk_hw *hw)
31{
32 struct clk_mux *mux = to_clk_mux(hw);
33 int num_parents = __clk_get_num_parents(hw->clk);
34 u32 val;
35
36 /*
37 * FIXME need a mux-specific flag to determine if val is bitwise or
38 * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges
39 * from 0x1 to 0x7 (index starts at one)
40 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
41 * val = 0x4 really means "bit 2, index starts at bit 0"
42 */
43 val = ti_clk_ll_ops->clk_readl(mux->reg) >> mux->shift;
44 val &= mux->mask;
45
46 if (mux->table) {
47 int i;
48
49 for (i = 0; i < num_parents; i++)
50 if (mux->table[i] == val)
51 return i;
52 return -EINVAL;
53 }
54
55 if (val && (mux->flags & CLK_MUX_INDEX_BIT))
56 val = ffs(val) - 1;
57
58 if (val && (mux->flags & CLK_MUX_INDEX_ONE))
59 val--;
60
61 if (val >= num_parents)
62 return -EINVAL;
63
64 return val;
65}
66
67static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
68{
69 struct clk_mux *mux = to_clk_mux(hw);
70 u32 val;
71 unsigned long flags = 0;
72
73 if (mux->table) {
74 index = mux->table[index];
75 } else {
76 if (mux->flags & CLK_MUX_INDEX_BIT)
77 index = (1 << ffs(index));
78
79 if (mux->flags & CLK_MUX_INDEX_ONE)
80 index++;
81 }
82
83 if (mux->lock)
84 spin_lock_irqsave(mux->lock, flags);
85
86 if (mux->flags & CLK_MUX_HIWORD_MASK) {
87 val = mux->mask << (mux->shift + 16);
88 } else {
89 val = ti_clk_ll_ops->clk_readl(mux->reg);
90 val &= ~(mux->mask << mux->shift);
91 }
92 val |= index << mux->shift;
93 ti_clk_ll_ops->clk_writel(val, mux->reg);
94
95 if (mux->lock)
96 spin_unlock_irqrestore(mux->lock, flags);
97
98 return 0;
99}
100
101const struct clk_ops ti_clk_mux_ops = {
102 .get_parent = ti_clk_mux_get_parent,
103 .set_parent = ti_clk_mux_set_parent,
104 .determine_rate = __clk_mux_determine_rate,
105};
106
107static struct clk *_register_mux(struct device *dev, const char *name,
108 const char **parent_names, u8 num_parents,
109 unsigned long flags, void __iomem *reg,
110 u8 shift, u32 mask, u8 clk_mux_flags,
111 u32 *table, spinlock_t *lock)
112{
113 struct clk_mux *mux;
114 struct clk *clk;
115 struct clk_init_data init;
116
117 /* allocate the mux */
118 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
119 if (!mux) {
120 pr_err("%s: could not allocate mux clk\n", __func__);
121 return ERR_PTR(-ENOMEM);
122 }
123
124 init.name = name;
125 init.ops = &ti_clk_mux_ops;
126 init.flags = flags | CLK_IS_BASIC;
127 init.parent_names = parent_names;
128 init.num_parents = num_parents;
129
130 /* struct clk_mux assignments */
131 mux->reg = reg;
132 mux->shift = shift;
133 mux->mask = mask;
134 mux->flags = clk_mux_flags;
135 mux->lock = lock;
136 mux->table = table;
137 mux->hw.init = &init;
138
139 clk = clk_register(dev, &mux->hw);
140
141 if (IS_ERR(clk))
142 kfree(mux);
143
144 return clk;
145}
146
147/**
148 * of_mux_clk_setup - Setup function for simple mux rate clock
149 * @node: DT node for the clock
150 *
151 * Sets up a basic clock multiplexer.
152 */
153static void of_mux_clk_setup(struct device_node *node)
154{
155 struct clk *clk;
156 void __iomem *reg;
157 int num_parents;
158 const char **parent_names;
159 int i;
160 u8 clk_mux_flags = 0;
161 u32 mask = 0;
162 u32 shift = 0;
163 u32 flags = 0;
164
165 num_parents = of_clk_get_parent_count(node);
166 if (num_parents < 2) {
167 pr_err("mux-clock %s must have parents\n", node->name);
168 return;
169 }
170 parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
171 if (!parent_names)
172 goto cleanup;
173
174 for (i = 0; i < num_parents; i++)
175 parent_names[i] = of_clk_get_parent_name(node, i);
176
177 reg = ti_clk_get_reg_addr(node, 0);
178
179 if (!reg)
180 goto cleanup;
181
182 of_property_read_u32(node, "ti,bit-shift", &shift);
183
184 if (of_property_read_bool(node, "ti,index-starts-at-one"))
185 clk_mux_flags |= CLK_MUX_INDEX_ONE;
186
187 if (of_property_read_bool(node, "ti,set-rate-parent"))
188 flags |= CLK_SET_RATE_PARENT;
189
190 /* Generate bit-mask based on parent info */
191 mask = num_parents;
192 if (!(clk_mux_flags & CLK_MUX_INDEX_ONE))
193 mask--;
194
195 mask = (1 << fls(mask)) - 1;
196
197 clk = _register_mux(NULL, node->name, parent_names, num_parents, flags,
198 reg, shift, mask, clk_mux_flags, NULL, NULL);
199
200 if (!IS_ERR(clk))
201 of_clk_add_provider(node, of_clk_src_simple_get, clk);
202
203cleanup:
204 kfree(parent_names);
205}
206CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
207
208static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
209{
210 struct clk_mux *mux;
211 int num_parents;
212 u32 val;
213
214 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
215 if (!mux)
216 return;
217
218 mux->reg = ti_clk_get_reg_addr(node, 0);
219
220 if (!mux->reg)
221 goto cleanup;
222
223 if (!of_property_read_u32(node, "ti,bit-shift", &val))
224 mux->shift = val;
225
226 if (of_property_read_bool(node, "ti,index-starts-at-one"))
227 mux->flags |= CLK_MUX_INDEX_ONE;
228
229 num_parents = of_clk_get_parent_count(node);
230
231 if (num_parents < 2) {
232 pr_err("%s must have parents\n", node->name);
233 goto cleanup;
234 }
235
236 mux->mask = num_parents - 1;
237 mux->mask = (1 << fls(mux->mask)) - 1;
238
239 if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX))
240 return;
241
242cleanup:
243 kfree(mux);
244}
245CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock",
246 of_ti_composite_mux_clk_setup);
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index a3f89a60de07..6e205b140071 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -224,6 +224,7 @@ struct ti_clk_ll_ops {
224extern struct ti_clk_ll_ops *ti_clk_ll_ops; 224extern struct ti_clk_ll_ops *ti_clk_ll_ops;
225 225
226extern const struct clk_ops ti_clk_divider_ops; 226extern const struct clk_ops ti_clk_divider_ops;
227extern const struct clk_ops ti_clk_mux_ops;
227 228
228#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) 229#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw)
229 230