1 /*
2 * Copyright (c) 2016 ARM Ltd.
3 * Copyright (c) 2019 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT nordic_nrf_temp
9
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/drivers/clock_control.h>
13 #include <zephyr/drivers/clock_control/nrf_clock_control.h>
14 #include <zephyr/logging/log.h>
15 #include <hal/nrf_temp.h>
16 #include <zephyr/irq.h>
17
18 LOG_MODULE_REGISTER(temp_nrf5, CONFIG_SENSOR_LOG_LEVEL);
19
20
21 /* The nRF5 temperature device returns measurements in 0.25C
22 * increments. Scale to mDegrees C.
23 */
24 #define TEMP_NRF5_TEMP_SCALE (1000000 / 4)
25
26 struct temp_nrf5_data {
27 struct k_sem device_sync_sem;
28 struct k_mutex mutex;
29 int32_t sample;
30 struct onoff_manager *clk_mgr;
31 };
32
hfclk_on_callback(struct onoff_manager * mgr,struct onoff_client * cli,uint32_t state,int res)33 static void hfclk_on_callback(struct onoff_manager *mgr,
34 struct onoff_client *cli,
35 uint32_t state,
36 int res)
37 {
38 nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_START);
39 }
40
temp_nrf5_sample_fetch(const struct device * dev,enum sensor_channel chan)41 static int temp_nrf5_sample_fetch(const struct device *dev,
42 enum sensor_channel chan)
43 {
44 struct temp_nrf5_data *data = dev->data;
45 struct onoff_client cli;
46 int r;
47
48 /* Error if before sensor initialized */
49 if (data->clk_mgr == NULL) {
50 return -EAGAIN;
51 }
52
53 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
54 return -ENOTSUP;
55 }
56
57 k_mutex_lock(&data->mutex, K_FOREVER);
58
59 sys_notify_init_callback(&cli.notify, hfclk_on_callback);
60 r = onoff_request(data->clk_mgr, &cli);
61 __ASSERT_NO_MSG(r >= 0);
62
63 k_sem_take(&data->device_sync_sem, K_FOREVER);
64
65 r = onoff_release(data->clk_mgr);
66 __ASSERT_NO_MSG(r >= 0);
67
68 data->sample = nrf_temp_result_get(NRF_TEMP);
69 LOG_DBG("sample: %d", data->sample);
70 nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_STOP);
71
72 k_mutex_unlock(&data->mutex);
73
74 return 0;
75 }
76
temp_nrf5_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)77 static int temp_nrf5_channel_get(const struct device *dev,
78 enum sensor_channel chan,
79 struct sensor_value *val)
80 {
81 struct temp_nrf5_data *data = dev->data;
82 int32_t uval;
83
84
85 if (chan != SENSOR_CHAN_DIE_TEMP) {
86 return -ENOTSUP;
87 }
88
89 uval = data->sample * TEMP_NRF5_TEMP_SCALE;
90 val->val1 = uval / 1000000;
91 val->val2 = uval % 1000000;
92
93 LOG_DBG("Temperature:%d,%d", val->val1, val->val2);
94
95 return 0;
96 }
97
temp_nrf5_isr(const void * arg)98 static void temp_nrf5_isr(const void *arg)
99 {
100 const struct device *dev = (const struct device *)arg;
101 struct temp_nrf5_data *data = dev->data;
102
103 nrf_temp_event_clear(NRF_TEMP, NRF_TEMP_EVENT_DATARDY);
104 k_sem_give(&data->device_sync_sem);
105 }
106
107 static DEVICE_API(sensor, temp_nrf5_driver_api) = {
108 .sample_fetch = temp_nrf5_sample_fetch,
109 .channel_get = temp_nrf5_channel_get,
110 };
111
temp_nrf5_init(const struct device * dev)112 static int temp_nrf5_init(const struct device *dev)
113 {
114 struct temp_nrf5_data *data = dev->data;
115
116 /* A null clk_mgr indicates sensor has not been initialized */
117 data->clk_mgr =
118 z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
119 __ASSERT_NO_MSG(data->clk_mgr);
120
121 k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT);
122 k_mutex_init(&data->mutex);
123
124 IRQ_CONNECT(
125 DT_INST_IRQN(0),
126 DT_INST_IRQ(0, priority),
127 temp_nrf5_isr,
128 DEVICE_DT_INST_GET(0),
129 0);
130 irq_enable(DT_INST_IRQN(0));
131
132 nrf_temp_int_enable(NRF_TEMP, NRF_TEMP_INT_DATARDY_MASK);
133
134 return 0;
135 }
136
137 #define NRF_TEMP_DEFINE(inst) \
138 static struct temp_nrf5_data temp_nrf5_data_##inst; \
139 \
140 SENSOR_DEVICE_DT_INST_DEFINE(inst, temp_nrf5_init, NULL, \
141 &temp_nrf5_data_##inst, NULL, POST_KERNEL, \
142 CONFIG_SENSOR_INIT_PRIORITY, &temp_nrf5_driver_api); \
143
144 DT_INST_FOREACH_STATUS_OKAY(NRF_TEMP_DEFINE)
145