1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Power Interface (SCMI) Protocol based clock driver
5 * Copyright (C) 2018 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/scmi_protocol.h>
14 #include <asm/div64.h>
19 const struct scmi_clock_info
*info
;
20 const struct scmi_handle
*handle
;
23 #define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
25 static unsigned long scmi_clk_recalc_rate(struct clk_hw
*hw
,
26 unsigned long parent_rate
)
30 struct scmi_clk
*clk
= to_scmi_clk(hw
);
32 ret
= clk
->handle
->clk_ops
->rate_get(clk
->handle
, clk
->id
, &rate
);
38 static long scmi_clk_round_rate(struct clk_hw
*hw
, unsigned long rate
,
39 unsigned long *parent_rate
)
42 struct scmi_clk
*clk
= to_scmi_clk(hw
);
45 * We can't figure out what rate it will be, so just return the
46 * rate back to the caller. scmi_clk_recalc_rate() will be called
47 * after the rate is set and we'll know what rate the clock is
50 if (clk
->info
->rate_discrete
)
53 fmin
= clk
->info
->range
.min_rate
;
54 fmax
= clk
->info
->range
.max_rate
;
57 else if (rate
>= fmax
)
61 ftmp
+= clk
->info
->range
.step_size
- 1; /* to round up */
62 do_div(ftmp
, clk
->info
->range
.step_size
);
64 return ftmp
* clk
->info
->range
.step_size
+ fmin
;
67 static int scmi_clk_set_rate(struct clk_hw
*hw
, unsigned long rate
,
68 unsigned long parent_rate
)
70 struct scmi_clk
*clk
= to_scmi_clk(hw
);
72 return clk
->handle
->clk_ops
->rate_set(clk
->handle
, clk
->id
, rate
);
75 static int scmi_clk_enable(struct clk_hw
*hw
)
77 struct scmi_clk
*clk
= to_scmi_clk(hw
);
79 return clk
->handle
->clk_ops
->enable(clk
->handle
, clk
->id
);
82 static void scmi_clk_disable(struct clk_hw
*hw
)
84 struct scmi_clk
*clk
= to_scmi_clk(hw
);
86 clk
->handle
->clk_ops
->disable(clk
->handle
, clk
->id
);
89 static const struct clk_ops scmi_clk_ops
= {
90 .recalc_rate
= scmi_clk_recalc_rate
,
91 .round_rate
= scmi_clk_round_rate
,
92 .set_rate
= scmi_clk_set_rate
,
94 * We can't provide enable/disable callback as we can't perform the same
95 * in atomic context. Since the clock framework provides standard API
96 * clk_prepare_enable that helps cases using clk_enable in non-atomic
97 * context, it should be fine providing prepare/unprepare.
99 .prepare
= scmi_clk_enable
,
100 .unprepare
= scmi_clk_disable
,
103 static int scmi_clk_ops_init(struct device
*dev
, struct scmi_clk
*sclk
)
106 unsigned long min_rate
, max_rate
;
108 struct clk_init_data init
= {
109 .flags
= CLK_GET_RATE_NOCACHE
,
111 .ops
= &scmi_clk_ops
,
112 .name
= sclk
->info
->name
,
115 sclk
->hw
.init
= &init
;
116 ret
= devm_clk_hw_register(dev
, &sclk
->hw
);
120 if (sclk
->info
->rate_discrete
) {
121 int num_rates
= sclk
->info
->list
.num_rates
;
126 min_rate
= sclk
->info
->list
.rates
[0];
127 max_rate
= sclk
->info
->list
.rates
[num_rates
- 1];
129 min_rate
= sclk
->info
->range
.min_rate
;
130 max_rate
= sclk
->info
->range
.max_rate
;
133 clk_hw_set_rate_range(&sclk
->hw
, min_rate
, max_rate
);
137 static int scmi_clocks_probe(struct scmi_device
*sdev
)
141 struct clk_hw_onecell_data
*clk_data
;
142 struct device
*dev
= &sdev
->dev
;
143 struct device_node
*np
= dev
->of_node
;
144 const struct scmi_handle
*handle
= sdev
->handle
;
146 if (!handle
|| !handle
->clk_ops
)
149 count
= handle
->clk_ops
->count_get(handle
);
151 dev_err(dev
, "%pOFn: invalid clock output count\n", np
);
155 clk_data
= devm_kzalloc(dev
, struct_size(clk_data
, hws
, count
),
160 clk_data
->num
= count
;
163 for (idx
= 0; idx
< count
; idx
++) {
164 struct scmi_clk
*sclk
;
166 sclk
= devm_kzalloc(dev
, sizeof(*sclk
), GFP_KERNEL
);
170 sclk
->info
= handle
->clk_ops
->info_get(handle
, idx
);
172 dev_dbg(dev
, "invalid clock info for idx %d\n", idx
);
177 sclk
->handle
= handle
;
179 err
= scmi_clk_ops_init(dev
, sclk
);
181 dev_err(dev
, "failed to register clock %d\n", idx
);
182 devm_kfree(dev
, sclk
);
185 dev_dbg(dev
, "Registered clock:%s\n", sclk
->info
->name
);
186 hws
[idx
] = &sclk
->hw
;
190 return devm_of_clk_add_hw_provider(dev
, of_clk_hw_onecell_get
,
194 static const struct scmi_device_id scmi_id_table
[] = {
195 { SCMI_PROTOCOL_CLOCK
, "clocks" },
198 MODULE_DEVICE_TABLE(scmi
, scmi_id_table
);
200 static struct scmi_driver scmi_clocks_driver
= {
201 .name
= "scmi-clocks",
202 .probe
= scmi_clocks_probe
,
203 .id_table
= scmi_id_table
,
205 module_scmi_driver(scmi_clocks_driver
);
207 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
208 MODULE_DESCRIPTION("ARM SCMI clock driver");
209 MODULE_LICENSE("GPL v2");