Commit | Line | Data |
---|---|---|
1d80c142 MR |
1 | /* |
2 | * Copyright 2016 Maxime Ripard | |
3 | * | |
4 | * Maxime Ripard <maxime.ripard@free-electrons.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/clk-provider.h> | |
18 | #include <linux/iopoll.h> | |
19 | #include <linux/slab.h> | |
20 | ||
21 | #include "ccu_common.h" | |
22 | #include "ccu_reset.h" | |
23 | ||
24 | static DEFINE_SPINLOCK(ccu_lock); | |
25 | ||
26 | void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) | |
27 | { | |
28 | u32 reg; | |
29 | ||
30 | if (!lock) | |
31 | return; | |
32 | ||
33 | WARN_ON(readl_relaxed_poll_timeout(common->base + common->reg, reg, | |
ed0ab110 | 34 | reg & lock, 100, 70000)); |
1d80c142 MR |
35 | } |
36 | ||
37 | int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, | |
38 | const struct sunxi_ccu_desc *desc) | |
39 | { | |
40 | struct ccu_reset *reset; | |
41 | int i, ret; | |
42 | ||
43 | for (i = 0; i < desc->num_ccu_clks; i++) { | |
44 | struct ccu_common *cclk = desc->ccu_clks[i]; | |
45 | ||
46 | if (!cclk) | |
47 | continue; | |
48 | ||
49 | cclk->base = reg; | |
50 | cclk->lock = &ccu_lock; | |
51 | } | |
52 | ||
53 | for (i = 0; i < desc->hw_clks->num ; i++) { | |
54 | struct clk_hw *hw = desc->hw_clks->hws[i]; | |
55 | ||
56 | if (!hw) | |
57 | continue; | |
58 | ||
59 | ret = clk_hw_register(NULL, hw); | |
60 | if (ret) { | |
61 | pr_err("Couldn't register clock %s\n", | |
62 | clk_hw_get_name(hw)); | |
63 | goto err_clk_unreg; | |
64 | } | |
65 | } | |
66 | ||
67 | ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, | |
68 | desc->hw_clks); | |
69 | if (ret) | |
70 | goto err_clk_unreg; | |
71 | ||
72 | reset = kzalloc(sizeof(*reset), GFP_KERNEL); | |
73 | reset->rcdev.of_node = node; | |
74 | reset->rcdev.ops = &ccu_reset_ops; | |
75 | reset->rcdev.owner = THIS_MODULE; | |
76 | reset->rcdev.nr_resets = desc->num_resets; | |
77 | reset->base = reg; | |
78 | reset->lock = &ccu_lock; | |
79 | reset->reset_map = desc->resets; | |
80 | ||
81 | ret = reset_controller_register(&reset->rcdev); | |
82 | if (ret) | |
83 | goto err_of_clk_unreg; | |
84 | ||
85 | return 0; | |
86 | ||
87 | err_of_clk_unreg: | |
88 | err_clk_unreg: | |
89 | return ret; | |
90 | } |