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