Commit | Line | Data |
---|---|---|
a8aceccb TK |
1 | /* |
2 | * TI 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 | ||
1b29e601 | 18 | #include <linux/clk.h> |
a8aceccb TK |
19 | #include <linux/clk-provider.h> |
20 | #include <linux/clkdev.h> | |
21 | #include <linux/clk/ti.h> | |
62e59c4e | 22 | #include <linux/io.h> |
a8aceccb | 23 | #include <linux/of.h> |
819b4861 TK |
24 | #include <linux/of_address.h> |
25 | #include <linux/list.h> | |
989feafb | 26 | #include <linux/regmap.h> |
57c8a661 | 27 | #include <linux/memblock.h> |
21f0bf2d | 28 | #include <linux/device.h> |
a8aceccb | 29 | |
c82f8957 TK |
30 | #include "clock.h" |
31 | ||
a8aceccb TK |
32 | #undef pr_fmt |
33 | #define pr_fmt(fmt) "%s: " fmt, __func__ | |
34 | ||
77b773ae | 35 | static LIST_HEAD(clk_hw_omap_clocks); |
819b4861 | 36 | struct ti_clk_ll_ops *ti_clk_ll_ops; |
c08ee14c | 37 | static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; |
819b4861 | 38 | |
47b00dcf | 39 | struct ti_clk_features ti_clk_features; |
e9e63088 | 40 | |
989feafb TK |
41 | struct clk_iomap { |
42 | struct regmap *regmap; | |
43 | void __iomem *mem; | |
44 | }; | |
45 | ||
46 | static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS]; | |
47 | ||
6c0afb50 | 48 | static void clk_memmap_writel(u32 val, const struct clk_omap_reg *reg) |
989feafb | 49 | { |
6c0afb50 | 50 | struct clk_iomap *io = clk_memmaps[reg->index]; |
989feafb | 51 | |
6c0afb50 TK |
52 | if (reg->ptr) |
53 | writel_relaxed(val, reg->ptr); | |
54 | else if (io->regmap) | |
55 | regmap_write(io->regmap, reg->offset, val); | |
989feafb | 56 | else |
6c0afb50 | 57 | writel_relaxed(val, io->mem + reg->offset); |
989feafb TK |
58 | } |
59 | ||
4902c202 TK |
60 | static void _clk_rmw(u32 val, u32 mask, void __iomem *ptr) |
61 | { | |
62 | u32 v; | |
63 | ||
64 | v = readl_relaxed(ptr); | |
65 | v &= ~mask; | |
66 | v |= val; | |
67 | writel_relaxed(v, ptr); | |
68 | } | |
69 | ||
70 | static void clk_memmap_rmw(u32 val, u32 mask, const struct clk_omap_reg *reg) | |
71 | { | |
72 | struct clk_iomap *io = clk_memmaps[reg->index]; | |
73 | ||
74 | if (reg->ptr) { | |
75 | _clk_rmw(val, mask, reg->ptr); | |
76 | } else if (io->regmap) { | |
77 | regmap_update_bits(io->regmap, reg->offset, mask, val); | |
78 | } else { | |
79 | _clk_rmw(val, mask, io->mem + reg->offset); | |
80 | } | |
81 | } | |
82 | ||
6c0afb50 | 83 | static u32 clk_memmap_readl(const struct clk_omap_reg *reg) |
989feafb TK |
84 | { |
85 | u32 val; | |
6c0afb50 | 86 | struct clk_iomap *io = clk_memmaps[reg->index]; |
989feafb | 87 | |
6c0afb50 TK |
88 | if (reg->ptr) |
89 | val = readl_relaxed(reg->ptr); | |
90 | else if (io->regmap) | |
91 | regmap_read(io->regmap, reg->offset, &val); | |
989feafb | 92 | else |
6c0afb50 | 93 | val = readl_relaxed(io->mem + reg->offset); |
989feafb TK |
94 | |
95 | return val; | |
96 | } | |
97 | ||
e9e63088 TK |
98 | /** |
99 | * ti_clk_setup_ll_ops - setup low level clock operations | |
100 | * @ops: low level clock ops descriptor | |
101 | * | |
102 | * Sets up low level clock operations for TI clock driver. This is used | |
103 | * to provide various callbacks for the clock driver towards platform | |
104 | * specific code. Returns 0 on success, -EBUSY if ll_ops have been | |
105 | * registered already. | |
106 | */ | |
107 | int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) | |
108 | { | |
109 | if (ti_clk_ll_ops) { | |
110 | pr_err("Attempt to register ll_ops multiple times.\n"); | |
111 | return -EBUSY; | |
112 | } | |
113 | ||
114 | ti_clk_ll_ops = ops; | |
989feafb TK |
115 | ops->clk_readl = clk_memmap_readl; |
116 | ops->clk_writel = clk_memmap_writel; | |
4902c202 | 117 | ops->clk_rmw = clk_memmap_rmw; |
e9e63088 TK |
118 | |
119 | return 0; | |
120 | } | |
f3b19aa5 | 121 | |
a8aceccb TK |
122 | /** |
123 | * ti_dt_clocks_register - register DT alias clocks during boot | |
124 | * @oclks: list of clocks to register | |
125 | * | |
126 | * Register alias or non-standard DT clock entries during boot. By | |
127 | * default, DT clocks are found based on their node name. If any | |
128 | * additional con-id / dev-id -> clock mapping is required, use this | |
129 | * function to list these. | |
130 | */ | |
131 | void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) | |
132 | { | |
133 | struct ti_dt_clk *c; | |
00a461cc | 134 | struct device_node *node, *parent; |
a8aceccb TK |
135 | struct clk *clk; |
136 | struct of_phandle_args clkspec; | |
5b385a45 TK |
137 | char buf[64]; |
138 | char *ptr; | |
139 | char *tags[2]; | |
140 | int i; | |
141 | int num_args; | |
142 | int ret; | |
143 | static bool clkctrl_nodes_missing; | |
144 | static bool has_clkctrl_data; | |
47b00dcf TK |
145 | static bool compat_mode; |
146 | ||
147 | compat_mode = ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT; | |
a8aceccb TK |
148 | |
149 | for (c = oclks; c->node_name != NULL; c++) { | |
5b385a45 TK |
150 | strcpy(buf, c->node_name); |
151 | ptr = buf; | |
152 | for (i = 0; i < 2; i++) | |
153 | tags[i] = NULL; | |
154 | num_args = 0; | |
155 | while (*ptr) { | |
156 | if (*ptr == ':') { | |
157 | if (num_args >= 2) { | |
158 | pr_warn("Bad number of tags on %s\n", | |
159 | c->node_name); | |
160 | return; | |
161 | } | |
162 | tags[num_args++] = ptr + 1; | |
163 | *ptr = 0; | |
164 | } | |
165 | ptr++; | |
166 | } | |
167 | ||
168 | if (num_args && clkctrl_nodes_missing) | |
169 | continue; | |
170 | ||
171 | node = of_find_node_by_name(NULL, buf); | |
47b00dcf | 172 | if (num_args && compat_mode) { |
00a461cc JH |
173 | parent = node; |
174 | node = of_get_child_by_name(parent, "clk"); | |
175 | of_node_put(parent); | |
176 | } | |
177 | ||
a8aceccb | 178 | clkspec.np = node; |
5b385a45 TK |
179 | clkspec.args_count = num_args; |
180 | for (i = 0; i < num_args; i++) { | |
181 | ret = kstrtoint(tags[i], i ? 10 : 16, clkspec.args + i); | |
182 | if (ret) { | |
183 | pr_warn("Bad tag in %s at %d: %s\n", | |
184 | c->node_name, i, tags[i]); | |
00a461cc | 185 | of_node_put(node); |
5b385a45 TK |
186 | return; |
187 | } | |
188 | } | |
a8aceccb | 189 | clk = of_clk_get_from_provider(&clkspec); |
00a461cc | 190 | of_node_put(node); |
a8aceccb TK |
191 | if (!IS_ERR(clk)) { |
192 | c->lk.clk = clk; | |
193 | clkdev_add(&c->lk); | |
194 | } else { | |
5b385a45 | 195 | if (num_args && !has_clkctrl_data) { |
2274d800 YL |
196 | struct device_node *np; |
197 | ||
198 | np = of_find_compatible_node(NULL, NULL, | |
199 | "ti,clkctrl"); | |
200 | if (np) { | |
5b385a45 | 201 | has_clkctrl_data = true; |
2274d800 | 202 | of_node_put(np); |
5b385a45 TK |
203 | } else { |
204 | clkctrl_nodes_missing = true; | |
205 | ||
206 | pr_warn("missing clkctrl nodes, please update your dts.\n"); | |
207 | continue; | |
208 | } | |
209 | } | |
210 | ||
211 | pr_warn("failed to lookup clock node %s, ret=%ld\n", | |
212 | c->node_name, PTR_ERR(clk)); | |
a8aceccb TK |
213 | } |
214 | } | |
215 | } | |
819b4861 TK |
216 | |
217 | struct clk_init_item { | |
218 | struct device_node *node; | |
ffb009b2 | 219 | void *user; |
819b4861 TK |
220 | ti_of_clk_init_cb_t func; |
221 | struct list_head link; | |
222 | }; | |
223 | ||
224 | static LIST_HEAD(retry_list); | |
225 | ||
226 | /** | |
227 | * ti_clk_retry_init - retries a failed clock init at later phase | |
228 | * @node: device not for the clock | |
ffb009b2 | 229 | * @user: user data pointer |
819b4861 TK |
230 | * @func: init function to be called for the clock |
231 | * | |
232 | * Adds a failed clock init to the retry list. The retry list is parsed | |
233 | * once all the other clocks have been initialized. | |
234 | */ | |
ffb009b2 TK |
235 | int __init ti_clk_retry_init(struct device_node *node, void *user, |
236 | ti_of_clk_init_cb_t func) | |
819b4861 TK |
237 | { |
238 | struct clk_init_item *retry; | |
239 | ||
e665f029 | 240 | pr_debug("%pOFn: adding to retry list...\n", node); |
819b4861 TK |
241 | retry = kzalloc(sizeof(*retry), GFP_KERNEL); |
242 | if (!retry) | |
243 | return -ENOMEM; | |
244 | ||
245 | retry->node = node; | |
246 | retry->func = func; | |
ffb009b2 | 247 | retry->user = user; |
819b4861 TK |
248 | list_add(&retry->link, &retry_list); |
249 | ||
250 | return 0; | |
251 | } | |
252 | ||
253 | /** | |
254 | * ti_clk_get_reg_addr - get register address for a clock register | |
255 | * @node: device node for the clock | |
256 | * @index: register index from the clock node | |
6c0afb50 | 257 | * @reg: pointer to target register struct |
819b4861 | 258 | * |
6c0afb50 TK |
259 | * Builds clock register address from device tree information, and returns |
260 | * the data via the provided output pointer @reg. Returns 0 on success, | |
261 | * negative error value on failure. | |
819b4861 | 262 | */ |
6c0afb50 TK |
263 | int ti_clk_get_reg_addr(struct device_node *node, int index, |
264 | struct clk_omap_reg *reg) | |
819b4861 | 265 | { |
819b4861 | 266 | u32 val; |
c08ee14c | 267 | int i; |
819b4861 | 268 | |
c08ee14c TK |
269 | for (i = 0; i < CLK_MAX_MEMMAPS; i++) { |
270 | if (clocks_node_ptr[i] == node->parent) | |
271 | break; | |
272 | } | |
273 | ||
274 | if (i == CLK_MAX_MEMMAPS) { | |
e665f029 | 275 | pr_err("clk-provider not found for %pOFn!\n", node); |
6c0afb50 | 276 | return -ENOENT; |
c08ee14c TK |
277 | } |
278 | ||
279 | reg->index = i; | |
819b4861 TK |
280 | |
281 | if (of_property_read_u32_index(node, "reg", index, &val)) { | |
e665f029 | 282 | pr_err("%pOFn must have reg[%d]!\n", node, index); |
6c0afb50 | 283 | return -EINVAL; |
819b4861 TK |
284 | } |
285 | ||
286 | reg->offset = val; | |
6c0afb50 | 287 | reg->ptr = NULL; |
819b4861 | 288 | |
6c0afb50 | 289 | return 0; |
819b4861 TK |
290 | } |
291 | ||
e31922ed TK |
292 | void ti_clk_latch(struct clk_omap_reg *reg, s8 shift) |
293 | { | |
294 | u32 latch; | |
295 | ||
296 | if (shift < 0) | |
297 | return; | |
298 | ||
299 | latch = 1 << shift; | |
300 | ||
301 | ti_clk_ll_ops->clk_rmw(latch, latch, reg); | |
302 | ti_clk_ll_ops->clk_rmw(0, latch, reg); | |
303 | ti_clk_ll_ops->clk_readl(reg); /* OCP barrier */ | |
304 | } | |
305 | ||
819b4861 | 306 | /** |
989feafb | 307 | * omap2_clk_provider_init - init master clock provider |
819b4861 TK |
308 | * @parent: master node |
309 | * @index: internal index for clk_reg_ops | |
989feafb TK |
310 | * @syscon: syscon regmap pointer for accessing clock registers |
311 | * @mem: iomem pointer for the clock provider memory area, only used if | |
312 | * syscon is not provided | |
819b4861 | 313 | * |
c08ee14c TK |
314 | * Initializes a master clock IP block. This basically sets up the |
315 | * mapping from clocks node to the memory map index. All the clocks | |
316 | * are then initialized through the common of_clk_init call, and the | |
317 | * clocks will access their memory maps based on the node layout. | |
989feafb | 318 | * Returns 0 in success. |
819b4861 | 319 | */ |
989feafb TK |
320 | int __init omap2_clk_provider_init(struct device_node *parent, int index, |
321 | struct regmap *syscon, void __iomem *mem) | |
819b4861 | 322 | { |
819b4861 | 323 | struct device_node *clocks; |
989feafb | 324 | struct clk_iomap *io; |
819b4861 TK |
325 | |
326 | /* get clocks for this parent */ | |
327 | clocks = of_get_child_by_name(parent, "clocks"); | |
328 | if (!clocks) { | |
e665f029 | 329 | pr_err("%pOFn missing 'clocks' child node.\n", parent); |
989feafb | 330 | return -EINVAL; |
819b4861 TK |
331 | } |
332 | ||
c08ee14c TK |
333 | /* add clocks node info */ |
334 | clocks_node_ptr[index] = clocks; | |
989feafb TK |
335 | |
336 | io = kzalloc(sizeof(*io), GFP_KERNEL); | |
f645f72d SB |
337 | if (!io) |
338 | return -ENOMEM; | |
989feafb TK |
339 | |
340 | io->regmap = syscon; | |
341 | io->mem = mem; | |
342 | ||
343 | clk_memmaps[index] = io; | |
344 | ||
345 | return 0; | |
346 | } | |
347 | ||
348 | /** | |
349 | * omap2_clk_legacy_provider_init - initialize a legacy clock provider | |
350 | * @index: index for the clock provider | |
351 | * @mem: iomem pointer for the clock provider memory area | |
352 | * | |
353 | * Initializes a legacy clock provider memory mapping. | |
354 | */ | |
355 | void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) | |
356 | { | |
357 | struct clk_iomap *io; | |
358 | ||
7e1c4e27 | 359 | io = memblock_alloc(sizeof(*io), SMP_CACHE_BYTES); |
8a7f97b9 MR |
360 | if (!io) |
361 | panic("%s: Failed to allocate %zu bytes\n", __func__, | |
362 | sizeof(*io)); | |
989feafb TK |
363 | |
364 | io->mem = mem; | |
365 | ||
366 | clk_memmaps[index] = io; | |
c08ee14c | 367 | } |
819b4861 | 368 | |
c08ee14c TK |
369 | /** |
370 | * ti_dt_clk_init_retry_clks - init clocks from the retry list | |
371 | * | |
372 | * Initializes any clocks that have failed to initialize before, | |
373 | * reasons being missing parent node(s) during earlier init. This | |
374 | * typically happens only for DPLLs which need to have both of their | |
375 | * parent clocks ready during init. | |
376 | */ | |
377 | void ti_dt_clk_init_retry_clks(void) | |
378 | { | |
379 | struct clk_init_item *retry; | |
380 | struct clk_init_item *tmp; | |
381 | int retries = 5; | |
382 | ||
383 | while (!list_empty(&retry_list) && retries) { | |
384 | list_for_each_entry_safe(retry, tmp, &retry_list, link) { | |
e665f029 | 385 | pr_debug("retry-init: %pOFn\n", retry->node); |
ffb009b2 | 386 | retry->func(retry->user, retry->node); |
c08ee14c TK |
387 | list_del(&retry->link); |
388 | kfree(retry); | |
389 | } | |
390 | retries--; | |
819b4861 TK |
391 | } |
392 | } | |
c82f8957 | 393 | |
fc04f27d AB |
394 | static const struct of_device_id simple_clk_match_table[] __initconst = { |
395 | { .compatible = "fixed-clock" }, | |
396 | { .compatible = "fixed-factor-clock" }, | |
397 | { } | |
398 | }; | |
399 | ||
c17435c5 TK |
400 | /** |
401 | * ti_clk_add_aliases - setup clock aliases | |
402 | * | |
403 | * Sets up any missing clock aliases. No return value. | |
404 | */ | |
405 | void __init ti_clk_add_aliases(void) | |
406 | { | |
407 | struct device_node *np; | |
408 | struct clk *clk; | |
409 | ||
410 | for_each_matching_node(np, simple_clk_match_table) { | |
411 | struct of_phandle_args clkspec; | |
412 | ||
413 | clkspec.np = np; | |
414 | clk = of_clk_get_from_provider(&clkspec); | |
415 | ||
416 | ti_clk_add_alias(NULL, clk, np->name); | |
417 | } | |
418 | } | |
419 | ||
f3b19aa5 TK |
420 | /** |
421 | * ti_clk_setup_features - setup clock features flags | |
422 | * @features: features definition to use | |
423 | * | |
424 | * Initializes the clock driver features flags based on platform | |
425 | * provided data. No return value. | |
426 | */ | |
427 | void __init ti_clk_setup_features(struct ti_clk_features *features) | |
428 | { | |
429 | memcpy(&ti_clk_features, features, sizeof(*features)); | |
430 | } | |
431 | ||
432 | /** | |
433 | * ti_clk_get_features - get clock driver features flags | |
434 | * | |
435 | * Get TI clock driver features description. Returns a pointer | |
436 | * to the current feature setup. | |
437 | */ | |
438 | const struct ti_clk_features *ti_clk_get_features(void) | |
439 | { | |
440 | return &ti_clk_features; | |
441 | } | |
a5aa8a60 TK |
442 | |
443 | /** | |
444 | * omap2_clk_enable_init_clocks - prepare & enable a list of clocks | |
445 | * @clk_names: ptr to an array of strings of clock names to enable | |
446 | * @num_clocks: number of clock names in @clk_names | |
447 | * | |
448 | * Prepare and enable a list of clocks, named by @clk_names. No | |
449 | * return value. XXX Deprecated; only needed until these clocks are | |
450 | * properly claimed and enabled by the drivers or core code that uses | |
451 | * them. XXX What code disables & calls clk_put on these clocks? | |
452 | */ | |
453 | void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks) | |
454 | { | |
455 | struct clk *init_clk; | |
456 | int i; | |
457 | ||
458 | for (i = 0; i < num_clocks; i++) { | |
459 | init_clk = clk_get(NULL, clk_names[i]); | |
460 | if (WARN(IS_ERR(init_clk), "could not find init clock %s\n", | |
461 | clk_names[i])) | |
462 | continue; | |
463 | clk_prepare_enable(init_clk); | |
464 | } | |
465 | } | |
21f0bf2d TK |
466 | |
467 | /** | |
468 | * ti_clk_add_alias - add a clock alias for a TI clock | |
469 | * @dev: device alias for this clock | |
470 | * @clk: clock handle to create alias for | |
471 | * @con: connection ID for this clock | |
472 | * | |
473 | * Creates a clock alias for a TI clock. Allocates the clock lookup entry | |
474 | * and assigns the data to it. Returns 0 if successful, negative error | |
475 | * value otherwise. | |
476 | */ | |
477 | int ti_clk_add_alias(struct device *dev, struct clk *clk, const char *con) | |
478 | { | |
479 | struct clk_lookup *cl; | |
480 | ||
481 | if (!clk) | |
482 | return 0; | |
483 | ||
484 | if (IS_ERR(clk)) | |
485 | return PTR_ERR(clk); | |
486 | ||
487 | cl = kzalloc(sizeof(*cl), GFP_KERNEL); | |
488 | if (!cl) | |
489 | return -ENOMEM; | |
490 | ||
491 | if (dev) | |
492 | cl->dev_id = dev_name(dev); | |
493 | cl->con_id = con; | |
494 | cl->clk = clk; | |
495 | ||
496 | clkdev_add(cl); | |
497 | ||
498 | return 0; | |
499 | } | |
500 | ||
501 | /** | |
502 | * ti_clk_register - register a TI clock to the common clock framework | |
503 | * @dev: device for this clock | |
504 | * @hw: hardware clock handle | |
505 | * @con: connection ID for this clock | |
506 | * | |
507 | * Registers a TI clock to the common clock framework, and adds a clock | |
508 | * alias for it. Returns a handle to the registered clock if successful, | |
509 | * ERR_PTR value in failure. | |
510 | */ | |
511 | struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, | |
512 | const char *con) | |
513 | { | |
514 | struct clk *clk; | |
515 | int ret; | |
516 | ||
517 | clk = clk_register(dev, hw); | |
518 | if (IS_ERR(clk)) | |
519 | return clk; | |
520 | ||
521 | ret = ti_clk_add_alias(dev, clk, con); | |
522 | if (ret) { | |
523 | clk_unregister(clk); | |
524 | return ERR_PTR(ret); | |
525 | } | |
526 | ||
527 | return clk; | |
528 | } | |
77b773ae TK |
529 | |
530 | /** | |
ead47825 TK |
531 | * ti_clk_register_omap_hw - register a clk_hw_omap to the clock framework |
532 | * @dev: device for this clock | |
533 | * @hw: hardware clock handle | |
534 | * @con: connection ID for this clock | |
77b773ae | 535 | * |
ead47825 TK |
536 | * Registers a clk_hw_omap clock to the clock framewor, adds a clock alias |
537 | * for it, and adds the list to the available clk_hw_omap type clocks. | |
538 | * Returns a handle to the registered clock if successful, ERR_PTR value | |
539 | * in failure. | |
77b773ae | 540 | */ |
ead47825 TK |
541 | struct clk *ti_clk_register_omap_hw(struct device *dev, struct clk_hw *hw, |
542 | const char *con) | |
77b773ae | 543 | { |
ead47825 TK |
544 | struct clk *clk; |
545 | struct clk_hw_omap *oclk; | |
546 | ||
547 | clk = ti_clk_register(dev, hw, con); | |
548 | if (IS_ERR(clk)) | |
549 | return clk; | |
550 | ||
551 | oclk = to_clk_hw_omap(hw); | |
77b773ae | 552 | |
ead47825 TK |
553 | list_add(&oclk->node, &clk_hw_omap_clocks); |
554 | ||
555 | return clk; | |
77b773ae TK |
556 | } |
557 | ||
558 | /** | |
559 | * omap2_clk_for_each - call function for each registered clk_hw_omap | |
560 | * @fn: pointer to a callback function | |
561 | * | |
562 | * Call @fn for each registered clk_hw_omap, passing @hw to each | |
563 | * function. @fn must return 0 for success or any other value for | |
564 | * failure. If @fn returns non-zero, the iteration across clocks | |
565 | * will stop and the non-zero return value will be passed to the | |
566 | * caller of omap2_clk_for_each(). | |
567 | */ | |
568 | int omap2_clk_for_each(int (*fn)(struct clk_hw_omap *hw)) | |
569 | { | |
570 | int ret; | |
571 | struct clk_hw_omap *hw; | |
572 | ||
573 | list_for_each_entry(hw, &clk_hw_omap_clocks, node) { | |
574 | ret = (*fn)(hw); | |
575 | if (ret) | |
576 | break; | |
577 | } | |
578 | ||
579 | return ret; | |
580 | } | |
7fd79ee7 TK |
581 | |
582 | /** | |
583 | * omap2_clk_is_hw_omap - check if the provided clk_hw is OMAP clock | |
584 | * @hw: clk_hw to check if it is an omap clock or not | |
585 | * | |
586 | * Checks if the provided clk_hw is OMAP clock or not. Returns true if | |
587 | * it is, false otherwise. | |
588 | */ | |
589 | bool omap2_clk_is_hw_omap(struct clk_hw *hw) | |
590 | { | |
591 | struct clk_hw_omap *oclk; | |
592 | ||
593 | list_for_each_entry(oclk, &clk_hw_omap_clocks, node) { | |
594 | if (&oclk->hw == hw) | |
595 | return true; | |
596 | } | |
597 | ||
598 | return false; | |
599 | } |