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