1 /*
2  * Copyright 2024-2025 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/firmware/scmi/clk.h>
8 #include <zephyr/drivers/clock_control.h>
9 #include <zephyr/logging/log.h>
10 
11 LOG_MODULE_REGISTER(arm_scmi_clock);
12 
13 #define DT_DRV_COMPAT arm_scmi_clock
14 
15 struct scmi_clock_data {
16 	uint32_t clk_num;
17 };
18 
scmi_clock_on_off(const struct device * dev,clock_control_subsys_t clk,bool on)19 static int scmi_clock_on_off(const struct device *dev,
20 			     clock_control_subsys_t clk, bool on)
21 {
22 	struct scmi_clock_data *data;
23 	struct scmi_protocol *proto;
24 	uint32_t clk_id;
25 	struct scmi_clock_config cfg;
26 
27 	proto = dev->data;
28 	data = proto->data;
29 	clk_id = POINTER_TO_UINT(clk);
30 
31 	if (clk_id >= data->clk_num) {
32 		return -EINVAL;
33 	}
34 
35 	memset(&cfg, 0, sizeof(cfg));
36 
37 	cfg.attributes = SCMI_CLK_CONFIG_ENABLE_DISABLE(on);
38 	cfg.clk_id = clk_id;
39 
40 	return scmi_clock_config_set(proto, &cfg);
41 }
42 
scmi_clock_on(const struct device * dev,clock_control_subsys_t clk)43 static int scmi_clock_on(const struct device *dev, clock_control_subsys_t clk)
44 {
45 	return scmi_clock_on_off(dev, clk, true);
46 }
47 
scmi_clock_off(const struct device * dev,clock_control_subsys_t clk)48 static int scmi_clock_off(const struct device *dev, clock_control_subsys_t clk)
49 {
50 	return scmi_clock_on_off(dev, clk, false);
51 }
52 
scmi_clock_get_rate(const struct device * dev,clock_control_subsys_t clk,uint32_t * rate)53 static int scmi_clock_get_rate(const struct device *dev,
54 			       clock_control_subsys_t clk, uint32_t *rate)
55 {
56 	struct scmi_clock_data *data;
57 	struct scmi_protocol *proto;
58 	uint32_t clk_id;
59 
60 	proto = dev->data;
61 	data = proto->data;
62 	clk_id = POINTER_TO_UINT(clk);
63 
64 	if (clk_id >= data->clk_num) {
65 		return -EINVAL;
66 	}
67 
68 	return scmi_clock_rate_get(proto, clk_id, rate);
69 }
70 
scmi_clock_set_rate(const struct device * dev,clock_control_subsys_t clk,clock_control_subsys_rate_t rate)71 static int scmi_clock_set_rate(const struct device *dev,
72 			       clock_control_subsys_t clk,
73 			       clock_control_subsys_rate_t rate)
74 {
75 	struct scmi_clock_data *data;
76 	struct scmi_protocol *proto;
77 	struct scmi_clock_rate_config cfg = {0};
78 
79 	proto = dev->data;
80 	data = proto->data;
81 	cfg.flags = SCMI_CLK_RATE_SET_FLAGS_ROUNDS_AUTO;
82 	cfg.clk_id = POINTER_TO_UINT(clk);
83 	cfg.rate[0] = (uintptr_t)rate;
84 
85 	if (cfg.clk_id >= data->clk_num) {
86 		return -EINVAL;
87 	}
88 
89 	return scmi_clock_rate_set(proto, &cfg);
90 }
91 
92 static DEVICE_API(clock_control, scmi_clock_api) = {
93 	.on = scmi_clock_on,
94 	.off = scmi_clock_off,
95 	.get_rate = scmi_clock_get_rate,
96 	.set_rate = scmi_clock_set_rate,
97 };
98 
scmi_clock_init(const struct device * dev)99 static int scmi_clock_init(const struct device *dev)
100 {
101 	struct scmi_protocol *proto;
102 	struct scmi_clock_data *data;
103 	int ret;
104 	uint32_t attributes;
105 
106 	proto = dev->data;
107 	data = proto->data;
108 
109 	ret = scmi_clock_protocol_attributes(proto, &attributes);
110 	if (ret < 0) {
111 		LOG_ERR("failed to fetch clock attributes: %d", ret);
112 		return ret;
113 	}
114 
115 	data->clk_num = SCMI_CLK_ATTRIBUTES_CLK_NUM(attributes);
116 
117 	return 0;
118 }
119 
120 static struct scmi_clock_data data;
121 
122 DT_INST_SCMI_PROTOCOL_DEFINE(0, &scmi_clock_init, NULL, &data, NULL,
123 			     PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
124 			     &scmi_clock_api);
125