1 /*
2 * Copyright (c) 2019, Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/ztest.h>
7 #include <zephyr/drivers/clock_control.h>
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_REGISTER(test);
10
11 #if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_clock)
12 #include "nrf_device_subsys.h"
13 #elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_clock)
14 #include "esp32_device_subsys.h"
15 #elif DT_HAS_COMPAT_STATUS_OKAY(silabs_series_clock)
16 #include "silabs_device_subsys.h"
17 #elif DT_HAS_COMPAT_STATUS_OKAY(microchip_sam_d5x_e5x_clock)
18 #include "mchp_device_subsys.h"
19 #else
20 #error "Unsupported board"
21 #endif
22
23 typedef void (*test_func_t)(const struct device *dev,
24 clock_control_subsys_t subsys,
25 uint32_t startup_us);
26
27 typedef bool (*test_capability_check_t)(const struct device *dev,
28 clock_control_subsys_t subsys);
29
setup_instance(const struct device * dev,clock_control_subsys_t subsys)30 static void setup_instance(const struct device *dev, clock_control_subsys_t subsys)
31 {
32 int err;
33 k_busy_wait(1000);
34 do {
35 err = clock_control_off(dev, subsys);
36 #if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_clock)
37 if (err == -EPERM) {
38 struct onoff_manager *mgr =
39 z_nrf_clock_control_get_onoff(subsys);
40
41 err = onoff_release(mgr);
42 if (err >= 0) {
43 break;
44 }
45 }
46 #endif
47 } while (clock_control_get_status(dev, subsys) !=
48 CLOCK_CONTROL_STATUS_OFF);
49
50 LOG_INF("setup done");
51 }
52
tear_down_instance(const struct device * dev,clock_control_subsys_t subsys)53 static void tear_down_instance(const struct device *dev,
54 clock_control_subsys_t subsys)
55 {
56 #if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_clock)
57 /* Turn on LF clock using onoff service if it is disabled. */
58 const struct device *const clk = DEVICE_DT_GET_ONE(nordic_nrf_clock);
59 struct onoff_client cli;
60 struct onoff_manager *mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF);
61 int err;
62
63 zassert_true(device_is_ready(clk), "Clock dev is not ready");
64
65 if (clock_control_get_status(clk, CLOCK_CONTROL_NRF_SUBSYS_LF) !=
66 CLOCK_CONTROL_STATUS_OFF) {
67 return;
68 }
69
70 sys_notify_init_spinwait(&cli.notify);
71 err = onoff_request(mgr, &cli);
72 zassert_true(err >= 0, "");
73
74 while (sys_notify_fetch_result(&cli.notify, &err) < 0) {
75 /*empty*/
76 }
77 zassert_true(err >= 0, "");
78 #endif
79 }
80
test_with_single_instance(const struct device * dev,clock_control_subsys_t subsys,uint32_t startup_time,test_func_t func,test_capability_check_t capability_check)81 static void test_with_single_instance(const struct device *dev,
82 clock_control_subsys_t subsys,
83 uint32_t startup_time,
84 test_func_t func,
85 test_capability_check_t capability_check)
86 {
87 setup_instance(dev, subsys);
88
89 if ((capability_check == NULL) || capability_check(dev, subsys)) {
90 func(dev, subsys, startup_time);
91 } else {
92 PRINT("test skipped for subsys:%d\n", (int)subsys);
93 }
94
95 tear_down_instance(dev, subsys);
96 /* Allow logs to be printed. */
97 k_sleep(K_MSEC(100));
98 }
test_all_instances(test_func_t func,test_capability_check_t capability_check)99 static void test_all_instances(test_func_t func,
100 test_capability_check_t capability_check)
101 {
102 for (size_t i = 0; i < ARRAY_SIZE(devices); i++) {
103 for (size_t j = 0; j < devices[i].subsys_cnt; j++) {
104 zassert_true(device_is_ready(devices[i].dev),
105 "Device %s is not ready", devices[i].dev->name);
106 test_with_single_instance(devices[i].dev,
107 devices[i].subsys_data[j].subsys,
108 devices[i].subsys_data[j].startup_us,
109 func, capability_check);
110 }
111 }
112 }
113
114 /*
115 * Basic test for checking correctness of getting clock status.
116 */
test_on_off_status_instance(const struct device * dev,clock_control_subsys_t subsys,uint32_t startup_us)117 static void test_on_off_status_instance(const struct device *dev,
118 clock_control_subsys_t subsys,
119 uint32_t startup_us)
120 {
121 enum clock_control_status status;
122 int err;
123
124 status = clock_control_get_status(dev, subsys);
125 zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
126 "%s: Unexpected status (%d)", dev->name, status);
127
128 err = clock_control_on(dev, subsys);
129 zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err);
130
131 status = clock_control_get_status(dev, subsys);
132 zassert_equal(status, CLOCK_CONTROL_STATUS_ON,
133 "%s: Unexpected status (%d)", dev->name, status);
134
135 err = clock_control_off(dev, subsys);
136 zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err);
137
138 status = clock_control_get_status(dev, subsys);
139 zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
140 "%s: Unexpected status (%d)", dev->name, status);
141 }
142
ZTEST(clock_control,test_on_off_status)143 ZTEST(clock_control, test_on_off_status)
144 {
145 test_all_instances(test_on_off_status_instance, NULL);
146 }
147
async_capable_callback(const struct device * dev,clock_control_subsys_t subsys,void * user_data)148 static void async_capable_callback(const struct device *dev,
149 clock_control_subsys_t subsys,
150 void *user_data)
151 {
152 /* empty */
153 }
154
155 /* Function checks if clock supports asynchronous starting. */
async_capable(const struct device * dev,clock_control_subsys_t subsys)156 static bool async_capable(const struct device *dev, clock_control_subsys_t subsys)
157 {
158 int err;
159
160 err = clock_control_async_on(dev, subsys, async_capable_callback, NULL);
161 if (err == -ENOSYS) {
162 ztest_test_skip();
163 } else if (err < 0) {
164 printk("failed %d", err);
165 return false;
166 }
167
168 while (clock_control_get_status(dev, subsys) !=
169 CLOCK_CONTROL_STATUS_ON) {
170 /* pend util clock is started */
171 }
172
173 err = clock_control_off(dev, subsys);
174 if (err < 0) {
175 printk("clock_control_off failed %d", err);
176 return false;
177 }
178
179 return true;
180 }
181
182 /*
183 * Test checks that callbacks are called after clock is started.
184 */
clock_on_callback(const struct device * dev,clock_control_subsys_t subsys,void * user_data)185 static void clock_on_callback(const struct device *dev,
186 clock_control_subsys_t subsys,
187 void *user_data)
188 {
189 bool *executed = (bool *)user_data;
190
191 *executed = true;
192 }
193
test_async_on_instance(const struct device * dev,clock_control_subsys_t subsys,uint32_t startup_us)194 static void test_async_on_instance(const struct device *dev,
195 clock_control_subsys_t subsys,
196 uint32_t startup_us)
197 {
198 enum clock_control_status status;
199 int err;
200 bool executed = false;
201
202 status = clock_control_get_status(dev, subsys);
203 zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
204 "%s: Unexpected status (%d)", dev->name, status);
205
206 err = clock_control_async_on(dev, subsys, clock_on_callback, &executed);
207 zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err);
208
209 /* wait for clock started. */
210 k_busy_wait(startup_us);
211
212 zassert_true(executed, "%s: Expected flag to be true", dev->name);
213 zassert_equal(CLOCK_CONTROL_STATUS_ON,
214 clock_control_get_status(dev, subsys),
215 "Unexpected clock status");
216 }
217
ZTEST(clock_control,test_async_on)218 ZTEST(clock_control, test_async_on)
219 {
220 test_all_instances(test_async_on_instance, async_capable);
221 }
222
223 /*
224 * Test checks that when asynchronous clock enabling is scheduled but clock
225 * is disabled before being started then callback is never called and error
226 * is reported.
227 */
test_async_on_stopped_on_instance(const struct device * dev,clock_control_subsys_t subsys,uint32_t startup_us)228 static void test_async_on_stopped_on_instance(const struct device *dev,
229 clock_control_subsys_t subsys,
230 uint32_t startup_us)
231 {
232 enum clock_control_status status;
233 int err;
234 unsigned int key;
235 bool executed = false;
236
237 status = clock_control_get_status(dev, subsys);
238 zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
239 "%s: Unexpected status (%d)", dev->name, status);
240
241 /* lock to prevent clock interrupt for fast starting clocks.*/
242 key = irq_lock();
243 err = clock_control_async_on(dev, subsys, clock_on_callback, &executed);
244 zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err);
245
246 /* Attempt to stop clock while it is being started. */
247 err = clock_control_off(dev, subsys);
248 zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err);
249
250 irq_unlock(key);
251
252 k_busy_wait(10000);
253
254 zassert_false(executed, "%s: Expected flag to be false", dev->name);
255 }
256
ZTEST(clock_control,test_async_on_stopped)257 ZTEST(clock_control, test_async_on_stopped)
258 {
259 test_all_instances(test_async_on_stopped_on_instance, async_capable);
260 }
261
262 /*
263 * Test checks that the second start returns error.
264 */
test_double_start_on_instance(const struct device * dev,clock_control_subsys_t subsys,uint32_t startup_us)265 static void test_double_start_on_instance(const struct device *dev,
266 clock_control_subsys_t subsys,
267 uint32_t startup_us)
268 {
269 enum clock_control_status status;
270 int err;
271
272 status = clock_control_get_status(dev, subsys);
273 zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
274 "%s: Unexpected status (%d)", dev->name, status);
275
276 err = clock_control_on(dev, subsys);
277 zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err);
278
279 err = clock_control_on(dev, subsys);
280 zassert_true(err < 0, "%s: Unexpected return value:%d", dev->name, err);
281 }
282
ZTEST(clock_control,test_double_start)283 ZTEST(clock_control, test_double_start)
284 {
285 test_all_instances(test_double_start_on_instance, NULL);
286 }
287
288 /*
289 * Test checks that the second stop returns 0.
290 * Test precondition: clock is stopped.
291 */
test_double_stop_on_instance(const struct device * dev,clock_control_subsys_t subsys,uint32_t startup_us)292 static void test_double_stop_on_instance(const struct device *dev,
293 clock_control_subsys_t subsys,
294 uint32_t startup_us)
295 {
296 enum clock_control_status status;
297 int err;
298
299 status = clock_control_get_status(dev, subsys);
300 zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
301 "%s: Unexpected status (%d)", dev->name, status);
302
303 err = clock_control_off(dev, subsys);
304 zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err);
305 }
306
ZTEST(clock_control,test_double_stop)307 ZTEST(clock_control, test_double_stop)
308 {
309 test_all_instances(test_double_stop_on_instance, NULL);
310 }
311
312 ZTEST_SUITE(clock_control, NULL, NULL, NULL, NULL, NULL);
313