1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nordic_nrf_temp_nrfs
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/__assert.h>
13
14 #include <nrfs_temp.h>
15
16 LOG_MODULE_REGISTER(temp_nrfs, CONFIG_SENSOR_LOG_LEVEL);
17
18 struct temp_nrfs_data {
19 struct k_sem measure_sem;
20 struct k_mutex mutex;
21 int32_t raw_temp;
22
23 #ifdef CONFIG_TEMP_NRFS_TRIGGER
24 struct sensor_trigger trigger;
25 sensor_trigger_handler_t handler;
26 const struct device *dev;
27 struct sensor_value sampling_freq;
28 struct sensor_value up_threshold;
29 struct sensor_value low_threshold;
30 #endif
31 #if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
32 K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_TEMP_NRFS_THREAD_STACK_SIZE);
33 struct k_thread thread;
34 struct k_sem event_sem;
35 #elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD)
36 struct k_work work;
37 #endif
38 };
39
40 #ifdef CONFIG_TEMP_NRFS_TRIGGER
41
42 #define DEFAULT_SAMPLING_FREQ { 1, 0 }
43 #define DEFAULT_UP_THRESHOLD { 25, 0 }
44 #define DEFAULT_LOW_THRESHOLD { 0, 0 }
45
temp_nrfs_handle_event(const struct device * dev)46 static void temp_nrfs_handle_event(const struct device *dev)
47 {
48 struct temp_nrfs_data *data = dev->data;
49 struct sensor_trigger trigger;
50 sensor_trigger_handler_t handler;
51
52 k_mutex_lock(&data->mutex, K_FOREVER);
53 trigger = data->trigger;
54 handler = data->handler;
55 k_mutex_unlock(&data->mutex);
56
57 if (handler) {
58 handler(dev, &trigger);
59 }
60 }
61
62 #if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
temp_nrfs_thread(void * p1,void * p2,void * p3)63 static void temp_nrfs_thread(void *p1, void *p2, void *p3)
64 {
65 ARG_UNUSED(p2);
66 ARG_UNUSED(p3);
67
68 struct temp_nrfs_data *data = p1;
69
70 while (1) {
71 k_sem_take(&data->event_sem, K_FOREVER);
72 temp_nrfs_handle_event(data->dev);
73 }
74 }
75 #elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD)
temp_nrfs_work_handler(struct k_work * work)76 static void temp_nrfs_work_handler(struct k_work *work)
77 {
78 struct temp_nrfs_data *data =
79 CONTAINER_OF(work, struct temp_nrfs_data, work);
80
81 temp_nrfs_handle_event(data->dev);
82 }
83 #endif
84
to_measure_rate_ms(const struct sensor_value * freq_val)85 static uint16_t to_measure_rate_ms(const struct sensor_value *freq_val)
86 {
87 uint32_t measure_rate_ms = (MSEC_PER_SEC * 1000) /
88 (uint32_t)sensor_value_to_milli(freq_val);
89
90 return (uint16_t)MIN(measure_rate_ms, UINT16_MAX);
91 }
92
to_raw_temp(const struct sensor_value * temp_val)93 static int32_t to_raw_temp(const struct sensor_value *temp_val)
94 {
95 int32_t temp_mul_100 = (int32_t)(sensor_value_to_milli(temp_val) / 10);
96
97 return nrfs_temp_to_raw(temp_mul_100);
98 }
99
api_sensor_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)100 static int api_sensor_trigger_set(const struct device *dev,
101 const struct sensor_trigger *trig,
102 sensor_trigger_handler_t handler)
103 {
104 struct temp_nrfs_data *data = dev->data;
105 nrfs_err_t err;
106
107 if (trig->chan != SENSOR_CHAN_ALL &&
108 trig->chan != SENSOR_CHAN_DIE_TEMP) {
109 return -ENOTSUP;
110 }
111
112 switch (trig->type) {
113 case SENSOR_TRIG_THRESHOLD:
114 k_mutex_lock(&data->mutex, K_FOREVER);
115 data->trigger = *trig;
116 data->handler = handler;
117 k_mutex_unlock(&data->mutex);
118
119 if (handler) {
120 err = nrfs_temp_subscribe(
121 to_measure_rate_ms(&data->sampling_freq),
122 to_raw_temp(&data->low_threshold),
123 to_raw_temp(&data->up_threshold),
124 data);
125 } else {
126 err = nrfs_temp_unsubscribe();
127 }
128
129 switch (err) {
130 case NRFS_SUCCESS:
131 break;
132 case NRFS_ERR_INVALID_STATE:
133 return -EAGAIN;
134 default:
135 return -EIO;
136 }
137 break;
138
139 default:
140 return -ENOTSUP;
141 }
142
143 return 0;
144 }
145
api_sensor_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)146 static int api_sensor_attr_set(const struct device *dev,
147 enum sensor_channel chan,
148 enum sensor_attribute attr,
149 const struct sensor_value *val)
150 {
151 struct temp_nrfs_data *data = dev->data;
152
153 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
154 return -ENOTSUP;
155 }
156
157 switch (attr) {
158 case SENSOR_ATTR_SAMPLING_FREQUENCY:
159 if (sensor_value_to_milli(val) <= 0) {
160 return -EINVAL;
161 }
162 data->sampling_freq = *val;
163 break;
164 case SENSOR_ATTR_UPPER_THRESH:
165 data->up_threshold = *val;
166 break;
167 case SENSOR_ATTR_LOWER_THRESH:
168 data->low_threshold = *val;
169 break;
170 default:
171 return -ENOTSUP;
172 }
173 return 0;
174 }
175
176 #endif /* CONFIG_TEMP_NRFS_TRIGGER */
177
sensor_handler(nrfs_temp_evt_t const * p_evt,void * context)178 static void sensor_handler(nrfs_temp_evt_t const *p_evt, void *context)
179 {
180 ARG_UNUSED(context);
181
182 struct temp_nrfs_data *data = context;
183
184 switch (p_evt->type) {
185 case NRFS_TEMP_EVT_MEASURE_DONE:
186 data->raw_temp = p_evt->raw_temp;
187 k_sem_give(&data->measure_sem);
188 break;
189
190 #ifdef CONFIG_TEMP_NRFS_TRIGGER
191 case NRFS_TEMP_EVT_CHANGE:
192 data->raw_temp = p_evt->raw_temp;
193 #if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
194 k_sem_give(&data->event_sem);
195 #elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD)
196 k_work_submit(&data->work);
197 #endif
198 break;
199 #endif /* CONFIG_TEMP_NRFS_TRIGGER */
200
201 default:
202 LOG_DBG("Temperature handler - unsupported event: 0x%x",
203 p_evt->type);
204 break;
205 }
206 }
207
api_sample_fetch(const struct device * dev,enum sensor_channel chan)208 static int api_sample_fetch(const struct device *dev,
209 enum sensor_channel chan)
210 {
211 struct temp_nrfs_data *data = dev->data;
212 int nrfs_rc;
213 int rc = 0;
214
215 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
216 return -ENOTSUP;
217 }
218
219 k_mutex_lock(&data->mutex, K_FOREVER);
220 nrfs_rc = nrfs_temp_measure_request(data);
221 switch (nrfs_rc) {
222 case NRFS_SUCCESS:
223 k_sem_take(&data->measure_sem, K_FOREVER);
224 LOG_DBG("Temperature sample: %d", data->raw_temp);
225 break;
226 case NRFS_ERR_INVALID_STATE:
227 LOG_DBG("Backend is not ready, try again.");
228 rc = -EAGAIN;
229 break;
230 default:
231 LOG_DBG("Measure request failed: %d", nrfs_rc);
232 rc = -EIO;
233 break;
234 }
235 k_mutex_unlock(&data->mutex);
236
237 return rc;
238 }
239
api_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)240 static int api_channel_get(const struct device *dev,
241 enum sensor_channel chan,
242 struct sensor_value *val)
243 {
244 struct temp_nrfs_data *data = dev->data;
245
246 if (chan != SENSOR_CHAN_DIE_TEMP) {
247 return -ENOTSUP;
248 }
249
250 int32_t uval = nrfs_temp_from_raw(data->raw_temp);
251
252 val->val1 = uval / 100;
253 val->val2 = (abs(uval) % 100) * 10000;
254
255 LOG_DBG("Temperature: %d.%02u[C]", uval / 100, abs(uval) % 100);
256
257 return 0;
258 }
259
temp_nrfs_init(const struct device * dev)260 static int temp_nrfs_init(const struct device *dev)
261 {
262 int rc;
263
264 rc = nrfs_temp_init(sensor_handler);
265 if (rc < 0) {
266 return rc;
267 }
268
269 #if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
270 struct temp_nrfs_data *data = dev->data;
271
272 k_thread_create(&data->thread, data->thread_stack,
273 CONFIG_TEMP_NRFS_THREAD_STACK_SIZE,
274 temp_nrfs_thread,
275 data, NULL, NULL,
276 K_PRIO_COOP(CONFIG_TEMP_NRFS_THREAD_PRIORITY),
277 0, K_NO_WAIT);
278 k_thread_name_set(&data->thread, dev->name);
279 #endif
280
281 return 0;
282 }
283
284 static DEVICE_API(sensor, temp_nrfs_drv_api) = {
285 #ifdef CONFIG_TEMP_NRFS_TRIGGER
286 .attr_set = api_sensor_attr_set,
287 .trigger_set = api_sensor_trigger_set,
288 #endif
289 .sample_fetch = api_sample_fetch,
290 .channel_get = api_channel_get
291 };
292
293 static struct temp_nrfs_data temp_nrfs_drv_data = {
294 .mutex = Z_MUTEX_INITIALIZER(temp_nrfs_drv_data.mutex),
295 .measure_sem = Z_SEM_INITIALIZER(temp_nrfs_drv_data.measure_sem, 0, 1),
296 #ifdef CONFIG_TEMP_NRFS_TRIGGER
297 .dev = DEVICE_DT_INST_GET(0),
298 .sampling_freq = DEFAULT_SAMPLING_FREQ,
299 .up_threshold = DEFAULT_UP_THRESHOLD,
300 .low_threshold = DEFAULT_LOW_THRESHOLD,
301 #endif
302 #if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
303 .event_sem = Z_SEM_INITIALIZER(temp_nrfs_drv_data.event_sem, 0, 1),
304 #elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD)
305 .work = Z_WORK_INITIALIZER(temp_nrfs_work_handler),
306 #endif
307 };
308
309 DEVICE_DT_INST_DEFINE(0, temp_nrfs_init, NULL,
310 &temp_nrfs_drv_data, NULL,
311 POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
312 &temp_nrfs_drv_api);
313