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