1 // SPDX-License-Identifier: GPL-2.0-only
3 * System Control and Power Interface (SCPI) Protocol based clock driver
5 * Copyright (C) 2015 ARM Ltd.
8 #include <linux/clk-provider.h>
9 #include <linux/device.h>
10 #include <linux/err.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/scpi_protocol.h>
19 struct scpi_dvfs_info
*info
;
20 struct scpi_ops
*scpi_ops
;
23 #define to_scpi_clk(clk) container_of(clk, struct scpi_clk, hw)
25 static struct platform_device
*cpufreq_dev
;
27 static unsigned long scpi_clk_recalc_rate(struct clk_hw
*hw
,
28 unsigned long parent_rate
)
30 struct scpi_clk
*clk
= to_scpi_clk(hw
);
32 return clk
->scpi_ops
->clk_get_val(clk
->id
);
35 static long scpi_clk_round_rate(struct clk_hw
*hw
, unsigned long rate
,
36 unsigned long *parent_rate
)
39 * We can't figure out what rate it will be, so just return the
40 * rate back to the caller. scpi_clk_recalc_rate() will be called
41 * after the rate is set and we'll know what rate the clock is
47 static int scpi_clk_set_rate(struct clk_hw
*hw
, unsigned long rate
,
48 unsigned long parent_rate
)
50 struct scpi_clk
*clk
= to_scpi_clk(hw
);
52 return clk
->scpi_ops
->clk_set_val(clk
->id
, rate
);
55 static const struct clk_ops scpi_clk_ops
= {
56 .recalc_rate
= scpi_clk_recalc_rate
,
57 .round_rate
= scpi_clk_round_rate
,
58 .set_rate
= scpi_clk_set_rate
,
61 /* find closest match to given frequency in OPP table */
62 static long __scpi_dvfs_round_rate(struct scpi_clk
*clk
, unsigned long rate
)
65 unsigned long fmin
= 0, fmax
= ~0, ftmp
;
66 const struct scpi_opp
*opp
= clk
->info
->opps
;
68 for (idx
= 0; idx
< clk
->info
->count
; idx
++, opp
++) {
74 } else if (ftmp
>= fmin
) {
78 return fmax
!= ~0 ? fmax
: fmin
;
81 static unsigned long scpi_dvfs_recalc_rate(struct clk_hw
*hw
,
82 unsigned long parent_rate
)
84 struct scpi_clk
*clk
= to_scpi_clk(hw
);
85 int idx
= clk
->scpi_ops
->dvfs_get_idx(clk
->id
);
86 const struct scpi_opp
*opp
;
91 opp
= clk
->info
->opps
+ idx
;
95 static long scpi_dvfs_round_rate(struct clk_hw
*hw
, unsigned long rate
,
96 unsigned long *parent_rate
)
98 struct scpi_clk
*clk
= to_scpi_clk(hw
);
100 return __scpi_dvfs_round_rate(clk
, rate
);
103 static int __scpi_find_dvfs_index(struct scpi_clk
*clk
, unsigned long rate
)
105 int idx
, max_opp
= clk
->info
->count
;
106 const struct scpi_opp
*opp
= clk
->info
->opps
;
108 for (idx
= 0; idx
< max_opp
; idx
++, opp
++)
109 if (opp
->freq
== rate
)
114 static int scpi_dvfs_set_rate(struct clk_hw
*hw
, unsigned long rate
,
115 unsigned long parent_rate
)
117 struct scpi_clk
*clk
= to_scpi_clk(hw
);
118 int ret
= __scpi_find_dvfs_index(clk
, rate
);
122 return clk
->scpi_ops
->dvfs_set_idx(clk
->id
, (u8
)ret
);
125 static const struct clk_ops scpi_dvfs_ops
= {
126 .recalc_rate
= scpi_dvfs_recalc_rate
,
127 .round_rate
= scpi_dvfs_round_rate
,
128 .set_rate
= scpi_dvfs_set_rate
,
131 static const struct of_device_id scpi_clk_match
[] __maybe_unused
= {
132 { .compatible
= "arm,scpi-dvfs-clocks", .data
= &scpi_dvfs_ops
, },
133 { .compatible
= "arm,scpi-variable-clocks", .data
= &scpi_clk_ops
, },
138 scpi_clk_ops_init(struct device
*dev
, const struct of_device_id
*match
,
139 struct scpi_clk
*sclk
, const char *name
)
141 struct clk_init_data init
;
142 unsigned long min
= 0, max
= 0;
147 init
.num_parents
= 0;
148 init
.ops
= match
->data
;
149 sclk
->hw
.init
= &init
;
150 sclk
->scpi_ops
= get_scpi_ops();
152 if (init
.ops
== &scpi_dvfs_ops
) {
153 sclk
->info
= sclk
->scpi_ops
->dvfs_get_info(sclk
->id
);
154 if (IS_ERR(sclk
->info
))
155 return PTR_ERR(sclk
->info
);
156 } else if (init
.ops
== &scpi_clk_ops
) {
157 if (sclk
->scpi_ops
->clk_get_range(sclk
->id
, &min
, &max
) || !max
)
163 ret
= devm_clk_hw_register(dev
, &sclk
->hw
);
165 clk_hw_set_rate_range(&sclk
->hw
, min
, max
);
169 struct scpi_clk_data
{
170 struct scpi_clk
**clk
;
171 unsigned int clk_num
;
174 static struct clk_hw
*
175 scpi_of_clk_src_get(struct of_phandle_args
*clkspec
, void *data
)
177 struct scpi_clk
*sclk
;
178 struct scpi_clk_data
*clk_data
= data
;
179 unsigned int idx
= clkspec
->args
[0], count
;
181 for (count
= 0; count
< clk_data
->clk_num
; count
++) {
182 sclk
= clk_data
->clk
[count
];
187 return ERR_PTR(-EINVAL
);
190 static int scpi_clk_add(struct device
*dev
, struct device_node
*np
,
191 const struct of_device_id
*match
)
194 struct scpi_clk_data
*clk_data
;
196 count
= of_property_count_strings(np
, "clock-output-names");
198 dev_err(dev
, "%pOFn: invalid clock output count\n", np
);
202 clk_data
= devm_kmalloc(dev
, sizeof(*clk_data
), GFP_KERNEL
);
206 clk_data
->clk_num
= count
;
207 clk_data
->clk
= devm_kcalloc(dev
, count
, sizeof(*clk_data
->clk
),
212 for (idx
= 0; idx
< count
; idx
++) {
213 struct scpi_clk
*sclk
;
217 sclk
= devm_kzalloc(dev
, sizeof(*sclk
), GFP_KERNEL
);
221 if (of_property_read_string_index(np
, "clock-output-names",
223 dev_err(dev
, "invalid clock name @ %pOFn\n", np
);
227 if (of_property_read_u32_index(np
, "clock-indices",
229 dev_err(dev
, "invalid clock index @ %pOFn\n", np
);
235 err
= scpi_clk_ops_init(dev
, match
, sclk
, name
);
237 dev_err(dev
, "failed to register clock '%s'\n", name
);
241 dev_dbg(dev
, "Registered clock '%s'\n", name
);
242 clk_data
->clk
[idx
] = sclk
;
245 return of_clk_add_hw_provider(np
, scpi_of_clk_src_get
, clk_data
);
248 static void scpi_clocks_remove(struct platform_device
*pdev
)
250 struct device
*dev
= &pdev
->dev
;
251 struct device_node
*child
, *np
= dev
->of_node
;
254 platform_device_unregister(cpufreq_dev
);
258 for_each_available_child_of_node(np
, child
)
259 of_clk_del_provider(np
);
262 static int scpi_clocks_probe(struct platform_device
*pdev
)
265 struct device
*dev
= &pdev
->dev
;
266 struct device_node
*child
, *np
= dev
->of_node
;
267 const struct of_device_id
*match
;
272 for_each_available_child_of_node(np
, child
) {
273 match
= of_match_node(scpi_clk_match
, child
);
276 ret
= scpi_clk_add(dev
, child
, match
);
278 scpi_clocks_remove(pdev
);
283 if (match
->data
!= &scpi_dvfs_ops
)
285 /* Add the virtual cpufreq device if it's DVFS clock provider */
286 cpufreq_dev
= platform_device_register_simple("scpi-cpufreq",
288 if (IS_ERR(cpufreq_dev
))
289 pr_warn("unable to register cpufreq device");
294 static const struct of_device_id scpi_clocks_ids
[] = {
295 { .compatible
= "arm,scpi-clocks", },
298 MODULE_DEVICE_TABLE(of
, scpi_clocks_ids
);
300 static struct platform_driver scpi_clocks_driver
= {
302 .name
= "scpi_clocks",
303 .of_match_table
= scpi_clocks_ids
,
305 .probe
= scpi_clocks_probe
,
306 .remove
= scpi_clocks_remove
,
308 module_platform_driver(scpi_clocks_driver
);
310 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
311 MODULE_DESCRIPTION("ARM SCPI clock driver");
312 MODULE_LICENSE("GPL v2");