Branch data Line data Source code
1 : : /*
2 : : * This program is free software; you can redistribute it and/or modify
3 : : * it under the terms of the GNU General Public License version 2 as
4 : : * published by the Free Software Foundation.
5 : : *
6 : : * This program is distributed in the hope that it will be useful,
7 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 : : * GNU General Public License for more details.
10 : : *
11 : : * Copyright (C) 2012 ARM Limited
12 : : */
13 : :
14 : : #define pr_fmt(fmt) "vexpress-osc: " fmt
15 : :
16 : : #include <linux/clkdev.h>
17 : : #include <linux/clk-provider.h>
18 : : #include <linux/err.h>
19 : : #include <linux/of.h>
20 : : #include <linux/platform_device.h>
21 : : #include <linux/slab.h>
22 : : #include <linux/vexpress.h>
23 : :
24 : : struct vexpress_osc {
25 : : struct vexpress_config_func *func;
26 : : struct clk_hw hw;
27 : : unsigned long rate_min;
28 : : unsigned long rate_max;
29 : : };
30 : :
31 : : #define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw)
32 : :
33 : 0 : static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
34 : : unsigned long parent_rate)
35 : : {
36 : : struct vexpress_osc *osc = to_vexpress_osc(hw);
37 : : u32 rate;
38 : :
39 : 0 : vexpress_config_read(osc->func, 0, &rate);
40 : :
41 : 0 : return rate;
42 : : }
43 : :
44 : 0 : static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate,
45 : : unsigned long *parent_rate)
46 : : {
47 : : struct vexpress_osc *osc = to_vexpress_osc(hw);
48 : :
49 [ # # ][ # # ]: 0 : if (WARN_ON(osc->rate_min && rate < osc->rate_min))
[ # # ][ # # ]
50 : 0 : rate = osc->rate_min;
51 : :
52 [ # # ][ # # ]: 0 : if (WARN_ON(osc->rate_max && rate > osc->rate_max))
[ # # ][ # # ]
53 : 0 : rate = osc->rate_max;
54 : :
55 : 0 : return rate;
56 : : }
57 : :
58 : 0 : static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
59 : : unsigned long parent_rate)
60 : : {
61 : : struct vexpress_osc *osc = to_vexpress_osc(hw);
62 : :
63 : 0 : return vexpress_config_write(osc->func, 0, rate);
64 : : }
65 : :
66 : : static struct clk_ops vexpress_osc_ops = {
67 : : .recalc_rate = vexpress_osc_recalc_rate,
68 : : .round_rate = vexpress_osc_round_rate,
69 : : .set_rate = vexpress_osc_set_rate,
70 : : };
71 : :
72 : :
73 : 0 : struct clk * __init vexpress_osc_setup(struct device *dev)
74 : : {
75 : : struct clk_init_data init;
76 : : struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
77 : :
78 [ # # ]: 0 : if (!osc)
79 : : return NULL;
80 : :
81 : 0 : osc->func = vexpress_config_func_get_by_dev(dev);
82 [ # # ]: 0 : if (!osc->func) {
83 : 0 : kfree(osc);
84 : 0 : return NULL;
85 : : }
86 : :
87 : 0 : init.name = dev_name(dev);
88 : 0 : init.ops = &vexpress_osc_ops;
89 : 0 : init.flags = CLK_IS_ROOT;
90 : 0 : init.num_parents = 0;
91 : 0 : osc->hw.init = &init;
92 : :
93 : 0 : return clk_register(NULL, &osc->hw);
94 : : }
95 : :
96 : 0 : void __init vexpress_osc_of_setup(struct device_node *node)
97 : : {
98 : : struct clk_init_data init;
99 : : struct vexpress_osc *osc;
100 : : struct clk *clk;
101 : : u32 range[2];
102 : :
103 : : osc = kzalloc(sizeof(*osc), GFP_KERNEL);
104 [ # # ]: 0 : if (!osc)
105 : : goto error;
106 : :
107 : 0 : osc->func = vexpress_config_func_get_by_node(node);
108 [ # # ]: 0 : if (!osc->func) {
109 : 0 : pr_err("Failed to obtain config func for node '%s'!\n",
110 : : node->full_name);
111 : 0 : goto error;
112 : : }
113 : :
114 [ # # ]: 0 : if (of_property_read_u32_array(node, "freq-range", range,
115 : : ARRAY_SIZE(range)) == 0) {
116 : 0 : osc->rate_min = range[0];
117 : 0 : osc->rate_max = range[1];
118 : : }
119 : :
120 : 0 : of_property_read_string(node, "clock-output-names", &init.name);
121 [ # # ]: 0 : if (!init.name)
122 : 0 : init.name = node->full_name;
123 : :
124 : 0 : init.ops = &vexpress_osc_ops;
125 : 0 : init.flags = CLK_IS_ROOT;
126 : 0 : init.num_parents = 0;
127 : :
128 : 0 : osc->hw.init = &init;
129 : :
130 : 0 : clk = clk_register(NULL, &osc->hw);
131 [ # # ]: 0 : if (IS_ERR(clk)) {
132 : 0 : pr_err("Failed to register clock '%s'!\n", init.name);
133 : 0 : goto error;
134 : : }
135 : :
136 : 0 : of_clk_add_provider(node, of_clk_src_simple_get, clk);
137 : :
138 : : pr_debug("Registered clock '%s'\n", init.name);
139 : :
140 : 0 : return;
141 : :
142 : : error:
143 [ # # ]: 0 : if (osc->func)
144 : 0 : vexpress_config_func_put(osc->func);
145 : 0 : kfree(osc);
146 : : }
147 : : CLK_OF_DECLARE(vexpress_soc, "arm,vexpress-osc", vexpress_osc_of_setup);
|