1 /*
2 * Copyright (c) 2021 Jimmy Johnson <catch22@fastmail.net>
3 * Copyright (c) 2022 T-Mobile USA, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT ti_tmp108
9
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/i2c.h>
12 #include <zephyr/drivers/sensor.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/kernel.h>
17
18 #include "tmp108.h"
19
20 LOG_MODULE_REGISTER(TMP108, CONFIG_SENSOR_LOG_LEVEL);
21
tmp108_reg_read(const struct device * dev,uint8_t reg,uint16_t * val)22 int tmp108_reg_read(const struct device *dev, uint8_t reg, uint16_t *val)
23 {
24 const struct tmp108_config *cfg = dev->config;
25 int result;
26
27 result = i2c_burst_read_dt(&cfg->i2c_spec, reg, (uint8_t *) val, 2);
28
29 if (result < 0) {
30 return result;
31 }
32
33 *val = sys_be16_to_cpu(*val);
34
35 return 0;
36 }
37
tmp108_reg_write(const struct device * dev,uint8_t reg,uint16_t val)38 int tmp108_reg_write(const struct device *dev, uint8_t reg, uint16_t val)
39 {
40 const struct tmp108_config *cfg = dev->config;
41 uint8_t tx_buf[3];
42 int result;
43
44 tx_buf[0] = reg;
45 sys_put_be16(val, &tx_buf[1]);
46
47 result = i2c_write_dt(&cfg->i2c_spec, tx_buf, sizeof(tx_buf));
48
49 if (result < 0) {
50 return result;
51 }
52
53 return 0;
54 }
55
tmp108_write_config(const struct device * dev,uint16_t mask,uint16_t conf)56 int tmp108_write_config(const struct device *dev, uint16_t mask, uint16_t conf)
57 {
58 uint16_t config = 0;
59 int result;
60
61 result = tmp108_reg_read(dev, TI_TMP108_REG_CONF, &config);
62
63 if (result < 0) {
64 return result;
65 }
66
67 config &= mask;
68 config |= conf;
69
70 result = tmp108_reg_write(dev, TI_TMP108_REG_CONF, config);
71
72 if (result < 0) {
73 return result;
74 }
75
76 return 0;
77 }
78
ti_tmp108_read_temp(const struct device * dev)79 int ti_tmp108_read_temp(const struct device *dev)
80 {
81 struct tmp108_data *drv_data = dev->data;
82 int result;
83
84 /* clear previous temperature readings */
85
86 drv_data->sample = 0U;
87
88 /* Get the most recent temperature measurement */
89
90 result = tmp108_reg_read(dev, TI_TMP108_REG_TEMP, &drv_data->sample);
91
92 if (result < 0) {
93 return result;
94 }
95
96 return 0;
97 }
98
tmp108_sample_fetch(const struct device * dev,enum sensor_channel chan)99 static int tmp108_sample_fetch(const struct device *dev,
100 enum sensor_channel chan)
101 {
102 struct tmp108_data *drv_data = dev->data;
103 uint16_t config, converting_mask;
104 int result;
105
106 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
107 return -ENOTSUP;
108 }
109
110 if (!drv_data->one_shot_mode) {
111 /* Read the latest temperature result */
112 return ti_tmp108_read_temp(dev);
113 }
114
115 /* Trigger the conversion */
116 result = tmp108_write_config(dev,
117 TI_TMP108_MODE_MASK(dev),
118 TI_TMP108_MODE_ONE_SHOT(dev));
119 if (result < 0) {
120 return result;
121 }
122
123 /* Typical conversion time:
124 * TMP108: 27ms
125 * AS6212: 36ms
126 * Maximum conversion time:
127 * TMP108: 35ms
128 * AS6212: 51ms
129 */
130 const uint32_t conv_time_min = 25;
131 const uint32_t conv_time_max = 100;
132 const uint32_t poll_period = 5;
133
134 k_sleep(K_MSEC(conv_time_min));
135 converting_mask = TI_TMP108_CONF_M1(dev) | TI_TMP108_CONF_M0(dev);
136
137 for (int i = conv_time_min; i < conv_time_max; i += poll_period) {
138 /* Read the config register */
139 result = tmp108_reg_read(dev, TI_TMP108_REG_CONF, &config);
140 if (result < 0) {
141 return result;
142 }
143 if ((config & converting_mask) == 0) {
144 /* Conversion has finished */
145 LOG_DBG("Conversion complete after %d ms", i);
146 return ti_tmp108_read_temp(dev);
147 }
148 /* Wait before reading again */
149 k_sleep(K_MSEC(poll_period));
150 }
151
152 /* Conversion timed out */
153 return -EAGAIN;
154 }
155
tmp108_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)156 static int tmp108_channel_get(const struct device *dev,
157 enum sensor_channel chan,
158 struct sensor_value *val)
159 {
160 struct tmp108_data *drv_data = dev->data;
161 int32_t uval;
162
163 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
164 return -ENOTSUP;
165 }
166
167 uval = ((int32_t)drv_data->sample * TMP108_TEMP_MULTIPLIER(dev)) / TMP108_TEMP_DIVISOR(dev);
168 return sensor_value_from_micro(val, uval);
169 }
170
tmp108_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)171 static int tmp108_attr_get(const struct device *dev,
172 enum sensor_channel chan,
173 enum sensor_attribute attr,
174 struct sensor_value *val)
175 {
176 int result;
177 uint16_t tmp_val;
178
179 if (chan != SENSOR_CHAN_AMBIENT_TEMP && chan != SENSOR_CHAN_ALL) {
180 return -ENOTSUP;
181 }
182
183 switch ((int) attr) {
184 case SENSOR_ATTR_CONFIGURATION:
185 result = tmp108_reg_read(dev,
186 TI_TMP108_REG_CONF,
187 &tmp_val);
188 val->val1 = tmp_val;
189 val->val2 = 0;
190 break;
191 default:
192 return -ENOTSUP;
193 }
194
195 return result;
196 }
197
tmp108_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)198 static int tmp108_attr_set(const struct device *dev,
199 enum sensor_channel chan,
200 enum sensor_attribute attr,
201 const struct sensor_value *val)
202 {
203 struct tmp108_data *drv_data = dev->data;
204 __maybe_unused uint16_t reg_value;
205 __maybe_unused int32_t uval;
206 uint16_t mode;
207 int result = 0;
208
209 if (chan != SENSOR_CHAN_AMBIENT_TEMP && chan != SENSOR_CHAN_ALL) {
210 return -ENOTSUP;
211 }
212
213 switch ((int) attr) {
214 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
215 case SENSOR_ATTR_HYSTERESIS:
216 if (TI_TMP108_HYSTER_0_C(dev) == TI_TMP108_CONF_NA) {
217 LOG_WRN("AS621x Series lacks Hysterisis setttings");
218 return -ENOTSUP;
219 }
220 if (val->val1 < 1) {
221 mode = TI_TMP108_HYSTER_0_C(dev);
222 } else if (val->val1 < 2) {
223 mode = TI_TMP108_HYSTER_1_C(dev);
224 } else if (val->val1 < 4) {
225 mode = TI_TMP108_HYSTER_2_C(dev);
226 } else {
227 mode = TI_TMP108_HYSTER_4_C(dev);
228 }
229
230 result = tmp108_write_config(dev,
231 TI_TMP108_HYSTER_MASK(dev),
232 mode);
233 break;
234
235 case SENSOR_ATTR_ALERT:
236 /* Spec Sheet Errata: TM is set on reset not cleared */
237 if (val->val1 == 1) {
238 mode = TI_TMP108_CONF_TM_INT(dev);
239 } else {
240 mode = TI_TMP108_CONF_TM_CMP(dev);
241 }
242
243 result = tmp108_write_config(dev,
244 TI_TMP108_CONF_TM_MASK(dev),
245 mode);
246 break;
247
248 case SENSOR_ATTR_LOWER_THRESH:
249 uval = sensor_value_to_micro(val);
250 reg_value = (uval * TMP108_TEMP_DIVISOR(dev)) / TMP108_TEMP_MULTIPLIER(dev);
251 result = tmp108_reg_write(dev,
252 TI_TMP108_REG_LOW_LIMIT,
253 reg_value);
254 break;
255
256 case SENSOR_ATTR_UPPER_THRESH:
257 uval = sensor_value_to_micro(val);
258 reg_value = (uval * TMP108_TEMP_DIVISOR(dev)) / TMP108_TEMP_MULTIPLIER(dev);
259 result = tmp108_reg_write(dev,
260 TI_TMP108_REG_HIGH_LIMIT,
261 reg_value);
262 break;
263
264 case SENSOR_ATTR_TMP108_ALERT_POLARITY:
265 if (val->val1 == 1) {
266 mode = TI_TMP108_CONF_POL_HIGH(dev);
267 } else {
268 mode = TI_TMP108_CONF_POL_LOW(dev);
269 }
270 result = tmp108_write_config(dev,
271 TI_TMP108_CONF_POL_MASK(dev),
272 mode);
273 break;
274 #endif /* CONFIG_TMP108_ALERT_INTERRUPTS */
275
276 case SENSOR_ATTR_SAMPLING_FREQUENCY:
277 if (val->val1 < 1) {
278 mode = TI_TMP108_FREQ_4_SECS(dev);
279 } else if (val->val1 < 4) {
280 mode = TI_TMP108_FREQ_1_HZ(dev);
281 } else if (val->val1 < 16) {
282 mode = TI_TMP108_FREQ_4_HZ(dev);
283 } else {
284 mode = TI_TMP108_FREQ_16_HZ(dev);
285 }
286 result = tmp108_write_config(dev,
287 TI_TMP108_FREQ_MASK(dev),
288 mode);
289 break;
290
291 case SENSOR_ATTR_TMP108_SHUTDOWN_MODE:
292 result = tmp108_write_config(dev,
293 TI_TMP108_MODE_MASK(dev),
294 TI_TMP108_MODE_SHUTDOWN(dev));
295 drv_data->one_shot_mode = false;
296 break;
297
298 case SENSOR_ATTR_TMP108_CONTINUOUS_CONVERSION_MODE:
299 result = tmp108_write_config(dev,
300 TI_TMP108_MODE_MASK(dev),
301 TI_TMP108_MODE_CONTINUOUS(dev));
302 drv_data->one_shot_mode = false;
303 break;
304
305 case SENSOR_ATTR_TMP108_ONE_SHOT_MODE:
306 result = tmp108_write_config(dev,
307 TI_TMP108_MODE_MASK(dev),
308 TI_TMP108_MODE_ONE_SHOT(dev));
309 drv_data->one_shot_mode = true;
310 break;
311
312 default:
313 return -ENOTSUP;
314 }
315
316 if (result < 0) {
317 return result;
318 }
319
320 return 0;
321 }
322
323 static DEVICE_API(sensor, tmp108_driver_api) = {
324 .attr_set = tmp108_attr_set,
325 .attr_get = tmp108_attr_get,
326 .sample_fetch = tmp108_sample_fetch,
327 .channel_get = tmp108_channel_get,
328 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
329 .trigger_set = tmp_108_trigger_set,
330 #endif
331 };
332
333 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
setup_interrupts(const struct device * dev)334 static int setup_interrupts(const struct device *dev)
335 {
336 struct tmp108_data *drv_data = dev->data;
337 const struct tmp108_config *config = dev->config;
338 const struct gpio_dt_spec *alert_gpio = &config->alert_gpio;
339 int result;
340
341 if (!device_is_ready(alert_gpio->port)) {
342 LOG_ERR("tmp108: gpio controller %s not ready",
343 alert_gpio->port->name);
344 return -ENODEV;
345 }
346
347 result = gpio_pin_configure_dt(alert_gpio, GPIO_INPUT);
348
349 if (result < 0) {
350 return result;
351 }
352
353 gpio_init_callback(&drv_data->temp_alert_gpio_cb,
354 tmp108_trigger_handle_alert,
355 BIT(alert_gpio->pin));
356
357 result = gpio_add_callback(alert_gpio->port,
358 &drv_data->temp_alert_gpio_cb);
359
360 if (result < 0) {
361 return result;
362 }
363
364 result = gpio_pin_interrupt_configure_dt(alert_gpio,
365 GPIO_INT_EDGE_BOTH);
366
367 if (result < 0) {
368 return result;
369 }
370
371 return 0;
372 }
373 #endif
374
tmp108_init(const struct device * dev)375 static int tmp108_init(const struct device *dev)
376 {
377 const struct tmp108_config *cfg = dev->config;
378 int result = 0;
379
380 if (!device_is_ready(cfg->i2c_spec.bus)) {
381 LOG_ERR("I2C dev %s not ready", cfg->i2c_spec.bus->name);
382 return -ENODEV;
383 }
384
385 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
386 struct tmp108_data *drv_data = dev->data;
387
388 /* save this driver instance for passing to other functions */
389 drv_data->tmp108_dev = dev;
390
391 result = setup_interrupts(dev);
392
393 if (result < 0) {
394 return result;
395 }
396 #endif
397 /* clear and set configuration registers back to default values */
398 result = tmp108_write_config(dev,
399 0x0000,
400 TMP108_CONF_RST(dev));
401 return result;
402 }
403
404 #define TMP108_DEFINE(inst, t) \
405 static struct tmp108_data tmp108_prv_data_##inst##t; \
406 static const struct tmp108_config tmp108_config_##inst##t = { \
407 .i2c_spec = I2C_DT_SPEC_INST_GET(inst), \
408 IF_ENABLED(CONFIG_TMP108_ALERT_INTERRUPTS, \
409 (.alert_gpio = GPIO_DT_SPEC_INST_GET(inst, alert_gpios),)) \
410 .reg_def = t##_CONF}; \
411 SENSOR_DEVICE_DT_INST_DEFINE(inst, &tmp108_init, NULL, &tmp108_prv_data_##inst##t, \
412 &tmp108_config_##inst##t, POST_KERNEL, \
413 CONFIG_SENSOR_INIT_PRIORITY, &tmp108_driver_api);
414
415 #define TMP108_INIT(n) TMP108_DEFINE(n, TI_TMP108)
416 #undef DT_DRV_COMPAT
417 #define DT_DRV_COMPAT ti_tmp108
418 DT_INST_FOREACH_STATUS_OKAY(TMP108_INIT)
419
420 #define AS6212_INIT(n) TMP108_DEFINE(n, AMS_AS6212)
421 #undef DT_DRV_COMPAT
422 #define DT_DRV_COMPAT ams_as6212
423 DT_INST_FOREACH_STATUS_OKAY(AS6212_INIT)
424