1 /*
2 * Copyright (c) 2024 Aurelien Jarno
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT st_stm32_digi_temp
8
9 #include <zephyr/device.h>
10 #include <zephyr/pm/device.h>
11 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
12 #include <zephyr/drivers/sensor.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15
16 LOG_MODULE_REGISTER(stm32_digi_temp, CONFIG_SENSOR_LOG_LEVEL);
17
18 /* Constants */
19 #define ONE_MHZ 1000000 /* Hz */
20 #define TS1_T0_VAL0 30 /* °C */
21 #define TS1_T0_VAL1 130 /* °C */
22 #define SAMPLING_TIME 15 /* best precision */
23
24 struct stm32_digi_temp_data {
25 struct k_sem sem_isr;
26 struct k_mutex mutex;
27
28 /* Peripheral clock frequency */
29 uint32_t pclk_freq;
30 /* Engineering value of the frequency measured at T0 in Hz */
31 uint32_t t0_freq;
32 /* Engineering value of the T0 temperature in °C */
33 uint16_t t0;
34 /* Engineering value of the ramp coefficient in Hz / °C */
35 uint16_t ramp_coeff;
36
37 /* Raw sensor value */
38 uint16_t raw;
39 };
40
41 struct stm32_digi_temp_config {
42 /* DTS instance. */
43 DTS_TypeDef *base;
44 /* Clock configuration. */
45 struct stm32_pclken pclken;
46 /* Interrupt configuration. */
47 void (*irq_config)(const struct device *dev);
48 };
49
stm32_digi_temp_isr(const struct device * dev)50 static void stm32_digi_temp_isr(const struct device *dev)
51 {
52 struct stm32_digi_temp_data *data = dev->data;
53 const struct stm32_digi_temp_config *cfg = dev->config;
54 DTS_TypeDef *dts = cfg->base;
55
56 /* Clear interrupt */
57 SET_BIT(dts->ICIFR, DTS_ICIFR_TS1_CITEF);
58
59 /* Give semaphore */
60 k_sem_give(&data->sem_isr);
61 }
62
stm32_digi_temp_sample_fetch(const struct device * dev,enum sensor_channel chan)63 static int stm32_digi_temp_sample_fetch(const struct device *dev, enum sensor_channel chan)
64 {
65 const struct stm32_digi_temp_config *cfg = dev->config;
66 struct stm32_digi_temp_data *data = dev->data;
67 DTS_TypeDef *dts = cfg->base;
68
69 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
70 return -ENOTSUP;
71 }
72
73 k_mutex_lock(&data->mutex, K_FOREVER);
74
75 /* Wait for the sensor to be ready (~40µS delay after enabling it) */
76 while (READ_BIT(dts->SR, DTS_SR_TS1_RDY) == 0) {
77 k_yield();
78 }
79
80 /* Trigger a measurement */
81 SET_BIT(dts->CFGR1, DTS_CFGR1_TS1_START);
82 CLEAR_BIT(dts->CFGR1, DTS_CFGR1_TS1_START);
83
84 /* Wait for interrupt */
85 k_sem_take(&data->sem_isr, K_FOREVER);
86
87 /* Read value */
88 data->raw = READ_REG(dts->DR);
89
90 k_mutex_unlock(&data->mutex);
91
92 return 0;
93 }
94
stm32_digi_temp_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)95 static int stm32_digi_temp_channel_get(const struct device *dev, enum sensor_channel chan,
96 struct sensor_value *val)
97 {
98 struct stm32_digi_temp_data *data = dev->data;
99 float meas_freq, temp;
100
101 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
102 return -ENOTSUP;
103 }
104
105 meas_freq = ((float)data->pclk_freq * SAMPLING_TIME) / data->raw;
106 temp = data->t0 + (meas_freq - data->t0_freq) / data->ramp_coeff;
107
108 return sensor_value_from_float(val, temp);
109 }
110
stm32_digi_temp_configure(const struct device * dev)111 static void stm32_digi_temp_configure(const struct device *dev)
112 {
113 const struct stm32_digi_temp_config *cfg = dev->config;
114 struct stm32_digi_temp_data *data = dev->data;
115 DTS_TypeDef *dts = cfg->base;
116 int clk_div;
117
118 /* Use the prescaler to obtain an internal frequency lower than 1 MHz.
119 * Allowed values are between 0 and 127.
120 */
121 clk_div = MIN(DIV_ROUND_UP(data->pclk_freq, ONE_MHZ), 127);
122 MODIFY_REG(dts->CFGR1, DTS_CFGR1_HSREF_CLK_DIV_Msk,
123 clk_div << DTS_CFGR1_HSREF_CLK_DIV_Pos);
124
125 /* Select PCLK as reference clock */
126 MODIFY_REG(dts->CFGR1, DTS_CFGR1_REFCLK_SEL_Msk,
127 0 << DTS_CFGR1_REFCLK_SEL_Pos);
128
129 /* Select trigger */
130 MODIFY_REG(dts->CFGR1, DTS_CFGR1_TS1_INTRIG_SEL_Msk,
131 0 << DTS_CFGR1_TS1_INTRIG_SEL_Pos);
132
133 /* Set sampling time */
134 MODIFY_REG(dts->CFGR1, DTS_CFGR1_TS1_SMP_TIME_Msk,
135 SAMPLING_TIME << DTS_CFGR1_TS1_SMP_TIME_Pos);
136 }
137
stm32_digi_temp_enable(const struct device * dev)138 static void stm32_digi_temp_enable(const struct device *dev)
139 {
140 const struct stm32_digi_temp_config *cfg = dev->config;
141 DTS_TypeDef *dts = cfg->base;
142
143 /* Enable the sensor */
144 SET_BIT(dts->CFGR1, DTS_CFGR1_TS1_EN);
145
146 /* Enable interrupt */
147 SET_BIT(dts->ITENR, DTS_ITENR_TS1_ITEEN);
148 }
149
150 #ifdef CONFIG_PM_DEVICE
stm32_digi_temp_disable(const struct device * dev)151 static void stm32_digi_temp_disable(const struct device *dev)
152 {
153 const struct stm32_digi_temp_config *cfg = dev->config;
154 DTS_TypeDef *dts = cfg->base;
155
156 /* Disable interrupt */
157 CLEAR_BIT(dts->ITENR, DTS_ITENR_TS1_ITEEN);
158
159 /* Disable the sensor */
160 CLEAR_BIT(dts->CFGR1, DTS_CFGR1_TS1_EN);
161 }
162 #endif
163
stm32_digi_temp_init(const struct device * dev)164 static int stm32_digi_temp_init(const struct device *dev)
165 {
166 const struct stm32_digi_temp_config *cfg = dev->config;
167 struct stm32_digi_temp_data *data = dev->data;
168 DTS_TypeDef *dts = cfg->base;
169
170 /* enable clock for subsystem */
171 const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
172
173 if (!device_is_ready(clk)) {
174 LOG_ERR("Clock control device not ready");
175 return -ENODEV;
176 }
177
178 if (clock_control_on(clk, (clock_control_subsys_t) &cfg->pclken) != 0) {
179 LOG_ERR("Could not enable DTS clock");
180 return -EIO;
181 }
182
183 /* Save the peripheral clock frequency in the data structure to avoid
184 * querying it for each call to the channel_get method.
185 */
186 if (clock_control_get_rate(clk, (clock_control_subsys_t) &cfg->pclken,
187 &data->pclk_freq) < 0) {
188 LOG_ERR("Failed call clock_control_get_rate(pclken)");
189 return -EIO;
190 }
191
192 /* Save the calibration data in the data structure to avoid reading
193 * them for each call to the channel_get method, as this requires
194 * enabling the peripheral clock.
195 */
196 data->ramp_coeff = dts->RAMPVALR & DTS_RAMPVALR_TS1_RAMP_COEFF;
197 data->t0_freq = (dts->T0VALR1 & DTS_T0VALR1_TS1_FMT0) * 100; /* 0.1 kHz -> Hz */
198
199 /* T0 temperature from the datasheet */
200 switch (dts->T0VALR1 >> DTS_T0VALR1_TS1_T0_Pos) {
201 case 0:
202 data->t0 = TS1_T0_VAL0;
203 break;
204 case 1:
205 data->t0 = TS1_T0_VAL1;
206 break;
207 default:
208 LOG_ERR("Unknown T0 temperature value");
209 return -EIO;
210 }
211
212 /* Init mutex and semaphore */
213 k_mutex_init(&data->mutex);
214 k_sem_init(&data->sem_isr, 0, 1);
215
216 /* Configure and enable the sensor */
217 cfg->irq_config(dev);
218 stm32_digi_temp_configure(dev);
219 stm32_digi_temp_enable(dev);
220
221 return 0;
222 }
223
224 #ifdef CONFIG_PM_DEVICE
stm32_digi_temp_pm_action(const struct device * dev,enum pm_device_action action)225 static int stm32_digi_temp_pm_action(const struct device *dev, enum pm_device_action action)
226 {
227 const struct stm32_digi_temp_config *cfg = dev->config;
228 const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
229 int err;
230
231 switch (action) {
232 case PM_DEVICE_ACTION_RESUME:
233 /* enable clock */
234 err = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken);
235 if (err != 0) {
236 LOG_ERR("Could not enable DTS clock");
237 return err;
238 }
239 /* Enable sensor */
240 stm32_digi_temp_enable(dev);
241 break;
242 case PM_DEVICE_ACTION_SUSPEND:
243 /* Disable sensor */
244 stm32_digi_temp_disable(dev);
245 /* Stop device clock */
246 err = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken);
247 if (err != 0) {
248 LOG_ERR("Could not disable DTS clock");
249 return err;
250 }
251 break;
252 default:
253 return -ENOTSUP;
254 }
255
256 return 0;
257 }
258 #endif /* CONFIG_PM_DEVICE */
259
260 static DEVICE_API(sensor, stm32_digi_temp_driver_api) = {
261 .sample_fetch = stm32_digi_temp_sample_fetch,
262 .channel_get = stm32_digi_temp_channel_get,
263 };
264
265 #define STM32_DIGI_TEMP_INIT(index) \
266 static void stm32_digi_temp_irq_config_func_##index(const struct device *dev) \
267 { \
268 IRQ_CONNECT(DT_INST_IRQN(index), \
269 DT_INST_IRQ(index, priority), \
270 stm32_digi_temp_isr, DEVICE_DT_INST_GET(index), 0); \
271 irq_enable(DT_INST_IRQN(index)); \
272 } \
273 \
274 static struct stm32_digi_temp_data stm32_digi_temp_dev_data_##index; \
275 \
276 static const struct stm32_digi_temp_config stm32_digi_temp_dev_config_##index = { \
277 .base = (DTS_TypeDef *)DT_INST_REG_ADDR(index), \
278 .pclken = { \
279 .enr = DT_INST_CLOCKS_CELL(index, bits), \
280 .bus = DT_INST_CLOCKS_CELL(index, bus) \
281 }, \
282 .irq_config = stm32_digi_temp_irq_config_func_##index, \
283 }; \
284 \
285 PM_DEVICE_DT_INST_DEFINE(index, stm32_digi_temp_pm_action); \
286 \
287 SENSOR_DEVICE_DT_INST_DEFINE(index, stm32_digi_temp_init, \
288 PM_DEVICE_DT_INST_GET(index), \
289 &stm32_digi_temp_dev_data_##index, \
290 &stm32_digi_temp_dev_config_##index, \
291 POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
292 &stm32_digi_temp_driver_api); \
293
294 DT_INST_FOREACH_STATUS_OKAY(STM32_DIGI_TEMP_INIT)
295