diff options
author | Pawel Moll <pawel.moll@arm.com> | 2012-09-18 10:17:47 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2012-10-29 14:07:51 -0400 |
commit | ed27ff1db869cc81a92bed6defb7d107f5a156ff (patch) | |
tree | 635223b21f41fbda49ce9fc917ce5334574f59f9 /drivers/clk/versatile | |
parent | f9f8c0438da2c6d6a4cd8af73097add3850d6084 (diff) |
clk: Versatile Express clock generators ("osc") driver
This driver provides a common clock framework hardware driver
for Versatile Express clock generators (a.k.a "osc") controlled
via the config bus.
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/versatile')
-rw-r--r-- | drivers/clk/versatile/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-vexpress-osc.c | 146 |
2 files changed, 147 insertions, 0 deletions
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index c0a0f6478798..1e49a7afcf44 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile | |||
@@ -2,3 +2,4 @@ | |||
2 | obj-$(CONFIG_ICST) += clk-icst.o | 2 | obj-$(CONFIG_ICST) += clk-icst.o |
3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o | 3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o |
4 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o | 4 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o |
5 | obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o | ||
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c new file mode 100644 index 000000000000..dcb6ae0a0425 --- /dev/null +++ b/drivers/clk/versatile/clk-vexpress-osc.c | |||
@@ -0,0 +1,146 @@ | |||
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 | 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 | vexpress_config_read(osc->func, 0, &rate); | ||
40 | |||
41 | return rate; | ||
42 | } | ||
43 | |||
44 | 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 | if (WARN_ON(osc->rate_min && rate < osc->rate_min)) | ||
50 | rate = osc->rate_min; | ||
51 | |||
52 | if (WARN_ON(osc->rate_max && rate > osc->rate_max)) | ||
53 | rate = osc->rate_max; | ||
54 | |||
55 | return rate; | ||
56 | } | ||
57 | |||
58 | 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 | 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 | 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 | if (!osc) | ||
79 | return NULL; | ||
80 | |||
81 | osc->func = vexpress_config_func_get_by_dev(dev); | ||
82 | if (!osc->func) { | ||
83 | kfree(osc); | ||
84 | return NULL; | ||
85 | } | ||
86 | |||
87 | init.name = dev_name(dev); | ||
88 | init.ops = &vexpress_osc_ops; | ||
89 | init.flags = CLK_IS_ROOT; | ||
90 | init.num_parents = 0; | ||
91 | osc->hw.init = &init; | ||
92 | |||
93 | return clk_register(NULL, &osc->hw); | ||
94 | } | ||
95 | |||
96 | 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 | if (!osc) | ||
105 | goto error; | ||
106 | |||
107 | osc->func = vexpress_config_func_get_by_node(node); | ||
108 | if (!osc->func) { | ||
109 | pr_err("Failed to obtain config func for node '%s'!\n", | ||
110 | node->name); | ||
111 | goto error; | ||
112 | } | ||
113 | |||
114 | if (of_property_read_u32_array(node, "freq-range", range, | ||
115 | ARRAY_SIZE(range)) == 0) { | ||
116 | osc->rate_min = range[0]; | ||
117 | osc->rate_max = range[1]; | ||
118 | } | ||
119 | |||
120 | of_property_read_string(node, "clock-output-names", &init.name); | ||
121 | if (!init.name) | ||
122 | init.name = node->name; | ||
123 | |||
124 | init.ops = &vexpress_osc_ops; | ||
125 | init.flags = CLK_IS_ROOT; | ||
126 | init.num_parents = 0; | ||
127 | |||
128 | osc->hw.init = &init; | ||
129 | |||
130 | clk = clk_register(NULL, &osc->hw); | ||
131 | if (IS_ERR(clk)) { | ||
132 | pr_err("Failed to register clock '%s'!\n", init.name); | ||
133 | goto error; | ||
134 | } | ||
135 | |||
136 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
137 | |||
138 | pr_debug("Registered clock '%s'\n", init.name); | ||
139 | |||
140 | return; | ||
141 | |||
142 | error: | ||
143 | if (osc->func) | ||
144 | vexpress_config_func_put(osc->func); | ||
145 | kfree(osc); | ||
146 | } | ||