1 /*
2  * Copyright (c) 2019-2020, Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/ztest.h>
7 #include <zephyr/drivers/entropy.h>
8 #include <zephyr/drivers/clock_control.h>
9 #include <zephyr/drivers/clock_control/nrf_clock_control.h>
10 #include <hal/nrf_clock.h>
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(test);
14 
15 #define TEST_TIME_MS 10000
16 
17 #define HF_STARTUP_TIME_US 400
18 
19 static bool test_end;
20 
21 static const struct device *const entropy = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy));
22 static const struct device *const clock_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock);
23 static struct onoff_manager *hf_mgr;
24 static struct onoff_client cli;
25 static uint32_t iteration;
26 
setup(void)27 static void *setup(void)
28 {
29 	zassert_true(device_is_ready(entropy));
30 	zassert_true(device_is_ready(clock_dev));
31 
32 	hf_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
33 	zassert_true(hf_mgr);
34 
35 	return NULL;
36 }
37 
bt_timeout_handler(struct k_timer * timer)38 static void bt_timeout_handler(struct k_timer *timer)
39 {
40 	static bool on;
41 
42 	if (on) {
43 		on = false;
44 		z_nrf_clock_bt_ctlr_hf_release();
45 	} else {
46 		on = true;
47 		z_nrf_clock_bt_ctlr_hf_request();
48 	}
49 
50 	if (!(test_end && !on)) {
51 		k_timeout_t timeout;
52 		static bool long_timeout;
53 
54 		if (!on) {
55 			timeout = K_USEC(200);
56 		} else {
57 			timeout = long_timeout ? K_USEC(300) : K_USEC(100);
58 			long_timeout = !long_timeout;
59 		}
60 		k_timer_start(timer, timeout, K_NO_WAIT);
61 	}
62 }
63 
64 K_TIMER_DEFINE(timer1, bt_timeout_handler, NULL);
65 
check_hf_status(const struct device * dev,bool exp_on,bool sw_check)66 static void check_hf_status(const struct device *dev, bool exp_on,
67 			    bool sw_check)
68 {
69 	nrf_clock_hfclk_t type;
70 
71 	nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_HFCLK, &type);
72 	zassert_equal(type, exp_on ? NRF_CLOCK_HFCLK_HIGH_ACCURACY :
73 				NRF_CLOCK_HFCLK_LOW_ACCURACY,
74 			"%d: Clock expected to be %s",
75 			iteration, exp_on ? "on" : "off");
76 
77 	if (sw_check) {
78 		enum clock_control_status status =
79 		     clock_control_get_status(dev, CLOCK_CONTROL_NRF_SUBSYS_HF);
80 
81 		zassert_equal(status, exp_on ? CLOCK_CONTROL_STATUS_ON :
82 						CLOCK_CONTROL_STATUS_OFF,
83 				"%d: Unexpected status: %d", iteration, status);
84 	}
85 
86 }
87 
88 /* Test controls HF clock from two contexts: thread and timer interrupt.
89  * In thread context clock is requested and released through standard onoff
90  * API and in the timeout handler it is requested and released using API
91  * dedicated to be used by Bluetooth Controller.
92  *
93  * Test runs in the loop to eventually lead to cases when clock controlling is
94  * preempted by timeout handler. At certain points clock status is validated.
95  */
ZTEST(nrf_onoff_and_bt,test_onoff_interrupted)96 ZTEST(nrf_onoff_and_bt, test_onoff_interrupted)
97 {
98 	uint64_t start_time = k_uptime_get();
99 	uint64_t elapsed;
100 	uint64_t checkpoint = 1000;
101 	int err;
102 	uint8_t rand;
103 	int backoff;
104 
105 	iteration = 0;
106 	test_end = false;
107 
108 	k_timer_start(&timer1, K_MSEC(1), K_NO_WAIT);
109 
110 	do {
111 		iteration++;
112 
113 		err = entropy_get_entropy(entropy, &rand, 1);
114 		zassert_equal(err, 0);
115 		backoff = 3 * rand;
116 
117 		sys_notify_init_spinwait(&cli.notify);
118 		err = onoff_request(hf_mgr, &cli);
119 		zassert_true(err >= 0);
120 
121 		k_busy_wait(backoff);
122 
123 		if (backoff > HF_STARTUP_TIME_US) {
124 			check_hf_status(clock_dev, true, true);
125 		}
126 
127 		err = onoff_cancel_or_release(hf_mgr, &cli);
128 		zassert_true(err >= 0);
129 
130 		elapsed = k_uptime_get() - start_time;
131 		if (elapsed > checkpoint) {
132 			printk("test continues\n");
133 			checkpoint += 1000;
134 		}
135 	} while (elapsed <= TEST_TIME_MS);
136 
137 	test_end = true;
138 	k_msleep(100);
139 	check_hf_status(clock_dev, false, true);
140 }
141 
onoff_timeout_handler(struct k_timer * timer)142 static void onoff_timeout_handler(struct k_timer *timer)
143 {
144 	static bool on;
145 	static uint32_t cnt;
146 	int err;
147 
148 	cnt++;
149 	if (on) {
150 		on = false;
151 		err = onoff_cancel_or_release(hf_mgr, &cli);
152 		zassert_true(err >= 0);
153 	} else {
154 		on = true;
155 		sys_notify_init_spinwait(&cli.notify);
156 		err = onoff_request(hf_mgr, &cli);
157 		zassert_true(err >= 0, "%d: Unexpected err: %d", cnt, err);
158 	}
159 
160 	if (!(test_end && !on)) {
161 		k_timeout_t timeout;
162 		static bool long_timeout;
163 
164 		if (!on) {
165 			timeout = K_USEC(200);
166 		} else {
167 			timeout = long_timeout ? K_USEC(300) : K_USEC(100);
168 			long_timeout = !long_timeout;
169 		}
170 		k_timer_start(timer, timeout, K_NO_WAIT);
171 	}
172 }
173 
174 K_TIMER_DEFINE(timer2, onoff_timeout_handler, NULL);
175 
176 /* Test controls HF clock from two contexts: thread and timer interrupt.
177  * In thread context clock is requested and released through API
178  * dedicated to be used by Bluetooth Controller and in the timeout handler it is
179  * requested and released using standard onoffAPI .
180  *
181  * Test runs in the loop to eventually lead to cases when clock controlling is
182  * preempted by timeout handler. At certain points clock status is validated.
183  */
ZTEST(nrf_onoff_and_bt,test_bt_interrupted)184 ZTEST(nrf_onoff_and_bt, test_bt_interrupted)
185 {
186 	uint64_t start_time = k_uptime_get();
187 	uint64_t elapsed;
188 	uint64_t checkpoint = 1000;
189 	int err;
190 	uint8_t rand;
191 	int backoff;
192 
193 	iteration = 0;
194 	test_end = false;
195 
196 	k_timer_start(&timer2, K_MSEC(1), K_NO_WAIT);
197 
198 	do {
199 		iteration++;
200 
201 		err = entropy_get_entropy(entropy, &rand, 1);
202 		zassert_equal(err, 0);
203 		backoff = 3 * rand;
204 
205 		z_nrf_clock_bt_ctlr_hf_request();
206 
207 		k_busy_wait(backoff);
208 
209 		if (backoff > HF_STARTUP_TIME_US) {
210 			check_hf_status(clock_dev, true, false);
211 		}
212 
213 		z_nrf_clock_bt_ctlr_hf_release();
214 
215 		elapsed = k_uptime_get() - start_time;
216 		if (elapsed > checkpoint) {
217 			printk("test continues\n");
218 			checkpoint += 1000;
219 		}
220 	} while (elapsed <= TEST_TIME_MS);
221 
222 	test_end = true;
223 	k_msleep(100);
224 	check_hf_status(clock_dev, false, true);
225 }
226 ZTEST_SUITE(nrf_onoff_and_bt, NULL, setup, NULL, NULL, NULL);
227