Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
4 : : * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
5 : : * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
6 : : *
7 : : * Simple multiplexer clock implementation
8 : : */
9 : :
10 : : #include <linux/clk-provider.h>
11 : : #include <linux/module.h>
12 : : #include <linux/slab.h>
13 : : #include <linux/io.h>
14 : : #include <linux/err.h>
15 : :
16 : : /*
17 : : * DOC: basic adjustable multiplexer clock that cannot gate
18 : : *
19 : : * Traits of this clock:
20 : : * prepare - clk_prepare only ensures that parents are prepared
21 : : * enable - clk_enable only ensures that parents are enabled
22 : : * rate - rate is only affected by parent switching. No clk_set_rate support
23 : : * parent - parent is adjustable through clk_set_parent
24 : : */
25 : :
26 : 0 : static inline u32 clk_mux_readl(struct clk_mux *mux)
27 : : {
28 : 0 : if (mux->flags & CLK_MUX_BIG_ENDIAN)
29 : 0 : return ioread32be(mux->reg);
30 : :
31 : 0 : return readl(mux->reg);
32 : : }
33 : :
34 : 0 : static inline void clk_mux_writel(struct clk_mux *mux, u32 val)
35 : : {
36 : 0 : if (mux->flags & CLK_MUX_BIG_ENDIAN)
37 : 0 : iowrite32be(val, mux->reg);
38 : : else
39 : 0 : writel(val, mux->reg);
40 : : }
41 : :
42 : 0 : int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
43 : : unsigned int val)
44 : : {
45 : 0 : int num_parents = clk_hw_get_num_parents(hw);
46 : :
47 [ # # ]: 0 : if (table) {
48 : : int i;
49 : :
50 [ # # ]: 0 : for (i = 0; i < num_parents; i++)
51 [ # # ]: 0 : if (table[i] == val)
52 : 0 : return i;
53 : : return -EINVAL;
54 : : }
55 : :
56 [ # # # # ]: 0 : if (val && (flags & CLK_MUX_INDEX_BIT))
57 : 0 : val = ffs(val) - 1;
58 : :
59 [ # # # # ]: 0 : if (val && (flags & CLK_MUX_INDEX_ONE))
60 : 0 : val--;
61 : :
62 [ # # ]: 0 : if (val >= num_parents)
63 : : return -EINVAL;
64 : :
65 : 0 : return val;
66 : : }
67 : : EXPORT_SYMBOL_GPL(clk_mux_val_to_index);
68 : :
69 : 0 : unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index)
70 : : {
71 : 0 : unsigned int val = index;
72 : :
73 [ # # ]: 0 : if (table) {
74 : 0 : val = table[index];
75 : : } else {
76 [ # # # # ]: 0 : if (flags & CLK_MUX_INDEX_BIT)
77 : 0 : val = 1 << index;
78 : :
79 [ # # # # ]: 0 : if (flags & CLK_MUX_INDEX_ONE)
80 : 0 : val++;
81 : : }
82 : :
83 : 0 : return val;
84 : : }
85 : : EXPORT_SYMBOL_GPL(clk_mux_index_to_val);
86 : :
87 : 0 : static u8 clk_mux_get_parent(struct clk_hw *hw)
88 : : {
89 : 0 : struct clk_mux *mux = to_clk_mux(hw);
90 : 0 : u32 val;
91 : :
92 [ # # ]: 0 : val = clk_mux_readl(mux) >> mux->shift;
93 : 0 : val &= mux->mask;
94 : :
95 : 0 : return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
96 : : }
97 : :
98 : 0 : static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
99 : : {
100 : 0 : struct clk_mux *mux = to_clk_mux(hw);
101 [ # # ]: 0 : u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
102 : 0 : unsigned long flags = 0;
103 : 0 : u32 reg;
104 : :
105 [ # # ]: 0 : if (mux->lock)
106 : 0 : spin_lock_irqsave(mux->lock, flags);
107 : : else
108 : 0 : __acquire(mux->lock);
109 : :
110 [ # # ]: 0 : if (mux->flags & CLK_MUX_HIWORD_MASK) {
111 : 0 : reg = mux->mask << (mux->shift + 16);
112 : : } else {
113 [ # # ]: 0 : reg = clk_mux_readl(mux);
114 : 0 : reg &= ~(mux->mask << mux->shift);
115 : : }
116 : 0 : val = val << mux->shift;
117 : 0 : reg |= val;
118 [ # # ]: 0 : clk_mux_writel(mux, reg);
119 : :
120 [ # # ]: 0 : if (mux->lock)
121 : 0 : spin_unlock_irqrestore(mux->lock, flags);
122 : : else
123 : 0 : __release(mux->lock);
124 : :
125 : 0 : return 0;
126 : : }
127 : :
128 : 0 : static int clk_mux_determine_rate(struct clk_hw *hw,
129 : : struct clk_rate_request *req)
130 : : {
131 : 0 : struct clk_mux *mux = to_clk_mux(hw);
132 : :
133 : 0 : return clk_mux_determine_rate_flags(hw, req, mux->flags);
134 : : }
135 : :
136 : : const struct clk_ops clk_mux_ops = {
137 : : .get_parent = clk_mux_get_parent,
138 : : .set_parent = clk_mux_set_parent,
139 : : .determine_rate = clk_mux_determine_rate,
140 : : };
141 : : EXPORT_SYMBOL_GPL(clk_mux_ops);
142 : :
143 : : const struct clk_ops clk_mux_ro_ops = {
144 : : .get_parent = clk_mux_get_parent,
145 : : };
146 : : EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
147 : :
148 : 0 : struct clk_hw *__clk_hw_register_mux(struct device *dev, struct device_node *np,
149 : : const char *name, u8 num_parents,
150 : : const char * const *parent_names,
151 : : const struct clk_hw **parent_hws,
152 : : const struct clk_parent_data *parent_data,
153 : : unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
154 : : u8 clk_mux_flags, u32 *table, spinlock_t *lock)
155 : : {
156 : 0 : struct clk_mux *mux;
157 : 0 : struct clk_hw *hw;
158 : 0 : struct clk_init_data init = {};
159 : 0 : u8 width = 0;
160 : 0 : int ret = -EINVAL;
161 : :
162 [ # # ]: 0 : if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
163 [ # # ]: 0 : width = fls(mask) - ffs(mask) + 1;
164 [ # # ]: 0 : if (width + shift > 16) {
165 : 0 : pr_err("mux value exceeds LOWORD field\n");
166 : 0 : return ERR_PTR(-EINVAL);
167 : : }
168 : : }
169 : :
170 : : /* allocate the mux */
171 : 0 : mux = kzalloc(sizeof(*mux), GFP_KERNEL);
172 [ # # ]: 0 : if (!mux)
173 : : return ERR_PTR(-ENOMEM);
174 : :
175 : 0 : init.name = name;
176 [ # # ]: 0 : if (clk_mux_flags & CLK_MUX_READ_ONLY)
177 : 0 : init.ops = &clk_mux_ro_ops;
178 : : else
179 : 0 : init.ops = &clk_mux_ops;
180 : 0 : init.flags = flags;
181 : 0 : init.parent_names = parent_names;
182 : 0 : init.parent_data = parent_data;
183 : 0 : init.parent_hws = parent_hws;
184 : 0 : init.num_parents = num_parents;
185 : :
186 : : /* struct clk_mux assignments */
187 : 0 : mux->reg = reg;
188 : 0 : mux->shift = shift;
189 : 0 : mux->mask = mask;
190 : 0 : mux->flags = clk_mux_flags;
191 : 0 : mux->lock = lock;
192 : 0 : mux->table = table;
193 : 0 : mux->hw.init = &init;
194 : :
195 : 0 : hw = &mux->hw;
196 [ # # ]: 0 : if (dev || !np)
197 : 0 : ret = clk_hw_register(dev, hw);
198 : 0 : else if (np)
199 : 0 : ret = of_clk_hw_register(np, hw);
200 [ # # ]: 0 : if (ret) {
201 : 0 : kfree(mux);
202 : 0 : hw = ERR_PTR(ret);
203 : : }
204 : :
205 : : return hw;
206 : : }
207 : : EXPORT_SYMBOL_GPL(__clk_hw_register_mux);
208 : :
209 : 0 : struct clk *clk_register_mux_table(struct device *dev, const char *name,
210 : : const char * const *parent_names, u8 num_parents,
211 : : unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
212 : : u8 clk_mux_flags, u32 *table, spinlock_t *lock)
213 : : {
214 : 0 : struct clk_hw *hw;
215 : :
216 : 0 : hw = clk_hw_register_mux_table(dev, name, parent_names,
217 : : num_parents, flags, reg, shift, mask,
218 : : clk_mux_flags, table, lock);
219 [ # # ]: 0 : if (IS_ERR(hw))
220 : : return ERR_CAST(hw);
221 : 0 : return hw->clk;
222 : : }
223 : : EXPORT_SYMBOL_GPL(clk_register_mux_table);
224 : :
225 : 0 : void clk_unregister_mux(struct clk *clk)
226 : : {
227 : 0 : struct clk_mux *mux;
228 : 0 : struct clk_hw *hw;
229 : :
230 : 0 : hw = __clk_get_hw(clk);
231 [ # # ]: 0 : if (!hw)
232 : : return;
233 : :
234 : 0 : mux = to_clk_mux(hw);
235 : :
236 : 0 : clk_unregister(clk);
237 : 0 : kfree(mux);
238 : : }
239 : : EXPORT_SYMBOL_GPL(clk_unregister_mux);
240 : :
241 : 0 : void clk_hw_unregister_mux(struct clk_hw *hw)
242 : : {
243 : 0 : struct clk_mux *mux;
244 : :
245 : 0 : mux = to_clk_mux(hw);
246 : :
247 : 0 : clk_hw_unregister(hw);
248 : 0 : kfree(mux);
249 : 0 : }
250 : : EXPORT_SYMBOL_GPL(clk_hw_unregister_mux);
|