2 * System Control and Power Interface (SCPI) Protocol based clock driver
4 * Copyright (C) 2015 ARM Ltd.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <linux/clk-provider.h>
20 #include <linux/device.h>
21 #include <linux/err.h>
23 #include <linux/module.h>
24 #include <linux/of_platform.h>
25 #include <linux/platform_device.h>
26 #include <linux/scpi_protocol.h>
31 struct scpi_dvfs_info
*info
;
32 struct scpi_ops
*scpi_ops
;
35 #define to_scpi_clk(clk) container_of(clk, struct scpi_clk, hw)
37 static struct platform_device
*cpufreq_dev
;
39 static unsigned long scpi_clk_recalc_rate(struct clk_hw
*hw
,
40 unsigned long parent_rate
)
42 struct scpi_clk
*clk
= to_scpi_clk(hw
);
44 return clk
->scpi_ops
->clk_get_val(clk
->id
);
47 static long scpi_clk_round_rate(struct clk_hw
*hw
, unsigned long rate
,
48 unsigned long *parent_rate
)
51 * We can't figure out what rate it will be, so just return the
52 * rate back to the caller. scpi_clk_recalc_rate() will be called
53 * after the rate is set and we'll know what rate the clock is
59 static int scpi_clk_set_rate(struct clk_hw
*hw
, unsigned long rate
,
60 unsigned long parent_rate
)
62 struct scpi_clk
*clk
= to_scpi_clk(hw
);
64 return clk
->scpi_ops
->clk_set_val(clk
->id
, rate
);
67 static const struct clk_ops scpi_clk_ops
= {
68 .recalc_rate
= scpi_clk_recalc_rate
,
69 .round_rate
= scpi_clk_round_rate
,
70 .set_rate
= scpi_clk_set_rate
,
73 /* find closest match to given frequency in OPP table */
74 static long __scpi_dvfs_round_rate(struct scpi_clk
*clk
, unsigned long rate
)
77 unsigned long fmin
= 0, fmax
= ~0, ftmp
;
78 const struct scpi_opp
*opp
= clk
->info
->opps
;
80 for (idx
= 0; idx
< clk
->info
->count
; idx
++, opp
++) {
86 } else if (ftmp
>= fmin
) {
90 return fmax
!= ~0 ? fmax
: fmin
;
93 static unsigned long scpi_dvfs_recalc_rate(struct clk_hw
*hw
,
94 unsigned long parent_rate
)
96 struct scpi_clk
*clk
= to_scpi_clk(hw
);
97 int idx
= clk
->scpi_ops
->dvfs_get_idx(clk
->id
);
98 const struct scpi_opp
*opp
;
103 opp
= clk
->info
->opps
+ idx
;
107 static long scpi_dvfs_round_rate(struct clk_hw
*hw
, unsigned long rate
,
108 unsigned long *parent_rate
)
110 struct scpi_clk
*clk
= to_scpi_clk(hw
);
112 return __scpi_dvfs_round_rate(clk
, rate
);
115 static int __scpi_find_dvfs_index(struct scpi_clk
*clk
, unsigned long rate
)
117 int idx
, max_opp
= clk
->info
->count
;
118 const struct scpi_opp
*opp
= clk
->info
->opps
;
120 for (idx
= 0; idx
< max_opp
; idx
++, opp
++)
121 if (opp
->freq
== rate
)
126 static int scpi_dvfs_set_rate(struct clk_hw
*hw
, unsigned long rate
,
127 unsigned long parent_rate
)
129 struct scpi_clk
*clk
= to_scpi_clk(hw
);
130 int ret
= __scpi_find_dvfs_index(clk
, rate
);
134 return clk
->scpi_ops
->dvfs_set_idx(clk
->id
, (u8
)ret
);
137 static const struct clk_ops scpi_dvfs_ops
= {
138 .recalc_rate
= scpi_dvfs_recalc_rate
,
139 .round_rate
= scpi_dvfs_round_rate
,
140 .set_rate
= scpi_dvfs_set_rate
,
143 static const struct of_device_id scpi_clk_match
[] = {
144 { .compatible
= "arm,scpi-dvfs-clocks", .data
= &scpi_dvfs_ops
, },
145 { .compatible
= "arm,scpi-variable-clocks", .data
= &scpi_clk_ops
, },
150 scpi_clk_ops_init(struct device
*dev
, const struct of_device_id
*match
,
151 struct scpi_clk
*sclk
, const char *name
)
153 struct clk_init_data init
;
154 unsigned long min
= 0, max
= 0;
159 init
.num_parents
= 0;
160 init
.ops
= match
->data
;
161 sclk
->hw
.init
= &init
;
162 sclk
->scpi_ops
= get_scpi_ops();
164 if (init
.ops
== &scpi_dvfs_ops
) {
165 sclk
->info
= sclk
->scpi_ops
->dvfs_get_info(sclk
->id
);
166 if (IS_ERR(sclk
->info
))
167 return PTR_ERR(sclk
->info
);
168 } else if (init
.ops
== &scpi_clk_ops
) {
169 if (sclk
->scpi_ops
->clk_get_range(sclk
->id
, &min
, &max
) || !max
)
175 ret
= devm_clk_hw_register(dev
, &sclk
->hw
);
177 clk_hw_set_rate_range(&sclk
->hw
, min
, max
);
181 struct scpi_clk_data
{
182 struct scpi_clk
**clk
;
183 unsigned int clk_num
;
186 static struct clk_hw
*
187 scpi_of_clk_src_get(struct of_phandle_args
*clkspec
, void *data
)
189 struct scpi_clk
*sclk
;
190 struct scpi_clk_data
*clk_data
= data
;
191 unsigned int idx
= clkspec
->args
[0], count
;
193 for (count
= 0; count
< clk_data
->clk_num
; count
++) {
194 sclk
= clk_data
->clk
[count
];
199 return ERR_PTR(-EINVAL
);
202 static int scpi_clk_add(struct device
*dev
, struct device_node
*np
,
203 const struct of_device_id
*match
)
206 struct scpi_clk_data
*clk_data
;
208 count
= of_property_count_strings(np
, "clock-output-names");
210 dev_err(dev
, "%s: invalid clock output count\n", np
->name
);
214 clk_data
= devm_kmalloc(dev
, sizeof(*clk_data
), GFP_KERNEL
);
218 clk_data
->clk_num
= count
;
219 clk_data
->clk
= devm_kcalloc(dev
, count
, sizeof(*clk_data
->clk
),
224 for (idx
= 0; idx
< count
; idx
++) {
225 struct scpi_clk
*sclk
;
229 sclk
= devm_kzalloc(dev
, sizeof(*sclk
), GFP_KERNEL
);
233 if (of_property_read_string_index(np
, "clock-output-names",
235 dev_err(dev
, "invalid clock name @ %s\n", np
->name
);
239 if (of_property_read_u32_index(np
, "clock-indices",
241 dev_err(dev
, "invalid clock index @ %s\n", np
->name
);
247 err
= scpi_clk_ops_init(dev
, match
, sclk
, name
);
249 dev_err(dev
, "failed to register clock '%s'\n", name
);
251 dev_dbg(dev
, "Registered clock '%s'\n", name
);
252 clk_data
->clk
[idx
] = sclk
;
255 return of_clk_add_hw_provider(np
, scpi_of_clk_src_get
, clk_data
);
258 static int scpi_clocks_remove(struct platform_device
*pdev
)
260 struct device
*dev
= &pdev
->dev
;
261 struct device_node
*child
, *np
= dev
->of_node
;
264 platform_device_unregister(cpufreq_dev
);
268 for_each_available_child_of_node(np
, child
)
269 of_clk_del_provider(np
);
273 static int scpi_clocks_probe(struct platform_device
*pdev
)
276 struct device
*dev
= &pdev
->dev
;
277 struct device_node
*child
, *np
= dev
->of_node
;
278 const struct of_device_id
*match
;
283 for_each_available_child_of_node(np
, child
) {
284 match
= of_match_node(scpi_clk_match
, child
);
287 ret
= scpi_clk_add(dev
, child
, match
);
289 scpi_clocks_remove(pdev
);
294 if (match
->data
!= &scpi_dvfs_ops
)
296 /* Add the virtual cpufreq device if it's DVFS clock provider */
297 cpufreq_dev
= platform_device_register_simple("scpi-cpufreq",
299 if (IS_ERR(cpufreq_dev
))
300 pr_warn("unable to register cpufreq device");
305 static const struct of_device_id scpi_clocks_ids
[] = {
306 { .compatible
= "arm,scpi-clocks", },
309 MODULE_DEVICE_TABLE(of
, scpi_clocks_ids
);
311 static struct platform_driver scpi_clocks_driver
= {
313 .name
= "scpi_clocks",
314 .of_match_table
= scpi_clocks_ids
,
316 .probe
= scpi_clocks_probe
,
317 .remove
= scpi_clocks_remove
,
319 module_platform_driver(scpi_clocks_driver
);
321 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
322 MODULE_DESCRIPTION("ARM SCPI clock driver");
323 MODULE_LICENSE("GPL v2");