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