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 const struct tmp108_config *config = dev->config;
205 __maybe_unused uint16_t reg_value;
206 __maybe_unused int32_t uval;
207 uint16_t mode;
208 int result = 0;
209
210 if (chan != SENSOR_CHAN_AMBIENT_TEMP && chan != SENSOR_CHAN_ALL) {
211 return -ENOTSUP;
212 }
213
214 switch ((int) attr) {
215 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
216 case SENSOR_ATTR_HYSTERESIS:
217 if (TI_TMP108_HYSTER_0_C(dev) == TI_TMP108_CONF_NA) {
218 LOG_WRN("AS621x Series lacks Hysterisis setttings");
219 return -ENOTSUP;
220 }
221 if (val->val1 < 1) {
222 mode = TI_TMP108_HYSTER_0_C(dev);
223 } else if (val->val1 < 2) {
224 mode = TI_TMP108_HYSTER_1_C(dev);
225 } else if (val->val1 < 4) {
226 mode = TI_TMP108_HYSTER_2_C(dev);
227 } else {
228 mode = TI_TMP108_HYSTER_4_C(dev);
229 }
230
231 result = tmp108_write_config(dev,
232 TI_TMP108_HYSTER_MASK(dev),
233 mode);
234 break;
235
236 case SENSOR_ATTR_ALERT:
237 /* Spec Sheet Errata: TM is set on reset not cleared */
238 if (val->val1 == 1) {
239 mode = TI_TMP108_CONF_TM_INT(dev);
240 } else {
241 mode = TI_TMP108_CONF_TM_CMP(dev);
242 }
243
244 result = tmp108_write_config(dev,
245 TI_TMP108_CONF_TM_MASK(dev),
246 mode);
247 break;
248
249 case SENSOR_ATTR_LOWER_THRESH:
250 uval = sensor_value_to_micro(val);
251 reg_value = (uval * TMP108_TEMP_DIVISOR(dev)) / TMP108_TEMP_MULTIPLIER(dev);
252 result = tmp108_reg_write(dev,
253 TI_TMP108_REG_LOW_LIMIT,
254 reg_value);
255 break;
256
257 case SENSOR_ATTR_UPPER_THRESH:
258 uval = sensor_value_to_micro(val);
259 reg_value = (uval * TMP108_TEMP_DIVISOR(dev)) / TMP108_TEMP_MULTIPLIER(dev);
260 result = tmp108_reg_write(dev,
261 TI_TMP108_REG_HIGH_LIMIT,
262 reg_value);
263 break;
264
265 case SENSOR_ATTR_TMP108_ALERT_POLARITY:
266 if (val->val1 == 1) {
267 mode = TI_TMP108_CONF_POL_HIGH(dev);
268 } else {
269 mode = TI_TMP108_CONF_POL_LOW(dev);
270 }
271 result = tmp108_write_config(dev,
272 TI_TMP108_CONF_POL_MASK(dev),
273 mode);
274 break;
275 #endif /* CONFIG_TMP108_ALERT_INTERRUPTS */
276
277 case SENSOR_ATTR_SAMPLING_FREQUENCY: {
278 struct tmp_108_reg_def ams_as6212_reg_def = AMS_AS6212_CONF;
279
280 if (memcmp(&config->reg_def, &ams_as6212_reg_def, sizeof(struct tmp_108_reg_def)) ==
281 0) {
282 if (val->val1 < 1) {
283 mode = TI_TMP108_FREQ_4_SECS(dev);
284 } else if (val->val1 < 4) {
285 mode = TI_TMP108_FREQ_1_HZ(dev);
286 } else if (val->val1 < 8) {
287 mode = TI_TMP108_FREQ_4_HZ(dev);
288 } else {
289 mode = AMS_AS6212_FREQ_8_HZ(dev);
290 }
291 } else {
292 if (val->val1 < 1) {
293 mode = TI_TMP108_FREQ_4_SECS(dev);
294 } else if (val->val1 < 4) {
295 mode = TI_TMP108_FREQ_1_HZ(dev);
296 } else if (val->val1 < 16) {
297 mode = TI_TMP108_FREQ_4_HZ(dev);
298 } else {
299 mode = TI_TMP108_FREQ_16_HZ(dev);
300 }
301 }
302 result = tmp108_write_config(dev,
303 TI_TMP108_FREQ_MASK(dev),
304 mode);
305 break;
306 }
307
308 case SENSOR_ATTR_TMP108_SHUTDOWN_MODE:
309 result = tmp108_write_config(dev,
310 TI_TMP108_MODE_MASK(dev),
311 TI_TMP108_MODE_SHUTDOWN(dev));
312 drv_data->one_shot_mode = false;
313 break;
314
315 case SENSOR_ATTR_TMP108_CONTINUOUS_CONVERSION_MODE:
316 result = tmp108_write_config(dev,
317 TI_TMP108_MODE_MASK(dev),
318 TI_TMP108_MODE_CONTINUOUS(dev));
319 drv_data->one_shot_mode = false;
320 break;
321
322 case SENSOR_ATTR_TMP108_ONE_SHOT_MODE:
323 result = tmp108_write_config(dev,
324 TI_TMP108_MODE_MASK(dev),
325 TI_TMP108_MODE_ONE_SHOT(dev));
326 drv_data->one_shot_mode = true;
327 break;
328
329 default:
330 return -ENOTSUP;
331 }
332
333 if (result < 0) {
334 return result;
335 }
336
337 return 0;
338 }
339
340 static DEVICE_API(sensor, tmp108_driver_api) = {
341 .attr_set = tmp108_attr_set,
342 .attr_get = tmp108_attr_get,
343 .sample_fetch = tmp108_sample_fetch,
344 .channel_get = tmp108_channel_get,
345 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
346 .trigger_set = tmp_108_trigger_set,
347 #endif
348 };
349
350 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
setup_interrupts(const struct device * dev)351 static int setup_interrupts(const struct device *dev)
352 {
353 struct tmp108_data *drv_data = dev->data;
354 const struct tmp108_config *config = dev->config;
355 const struct gpio_dt_spec *alert_gpio = &config->alert_gpio;
356 int result;
357
358 if (!device_is_ready(alert_gpio->port)) {
359 LOG_ERR("tmp108: gpio controller %s not ready",
360 alert_gpio->port->name);
361 return -ENODEV;
362 }
363
364 result = gpio_pin_configure_dt(alert_gpio, GPIO_INPUT);
365
366 if (result < 0) {
367 return result;
368 }
369
370 gpio_init_callback(&drv_data->temp_alert_gpio_cb,
371 tmp108_trigger_handle_alert,
372 BIT(alert_gpio->pin));
373
374 result = gpio_add_callback(alert_gpio->port,
375 &drv_data->temp_alert_gpio_cb);
376
377 if (result < 0) {
378 return result;
379 }
380
381 result = gpio_pin_interrupt_configure_dt(alert_gpio,
382 GPIO_INT_EDGE_BOTH);
383
384 if (result < 0) {
385 return result;
386 }
387
388 return 0;
389 }
390 #endif
391
tmp108_init(const struct device * dev)392 static int tmp108_init(const struct device *dev)
393 {
394 const struct tmp108_config *cfg = dev->config;
395 int result = 0;
396
397 if (!device_is_ready(cfg->i2c_spec.bus)) {
398 LOG_ERR("I2C dev %s not ready", cfg->i2c_spec.bus->name);
399 return -ENODEV;
400 }
401
402 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
403 struct tmp108_data *drv_data = dev->data;
404
405 /* save this driver instance for passing to other functions */
406 drv_data->tmp108_dev = dev;
407
408 result = setup_interrupts(dev);
409
410 if (result < 0) {
411 return result;
412 }
413 #endif
414 /* clear and set configuration registers back to default values */
415 result = tmp108_write_config(dev,
416 0x0000,
417 TMP108_CONF_RST(dev));
418 return result;
419 }
420
421 #define TMP108_DEFINE(inst, t) \
422 static struct tmp108_data tmp108_prv_data_##inst##t; \
423 static const struct tmp108_config tmp108_config_##inst##t = { \
424 .i2c_spec = I2C_DT_SPEC_INST_GET(inst), \
425 IF_ENABLED(CONFIG_TMP108_ALERT_INTERRUPTS, \
426 (.alert_gpio = GPIO_DT_SPEC_INST_GET(inst, alert_gpios),)) \
427 .reg_def = t##_CONF}; \
428 SENSOR_DEVICE_DT_INST_DEFINE(inst, &tmp108_init, NULL, &tmp108_prv_data_##inst##t, \
429 &tmp108_config_##inst##t, POST_KERNEL, \
430 CONFIG_SENSOR_INIT_PRIORITY, &tmp108_driver_api);
431
432 #define TMP108_INIT(n) TMP108_DEFINE(n, TI_TMP108)
433 #undef DT_DRV_COMPAT
434 #define DT_DRV_COMPAT ti_tmp108
435 DT_INST_FOREACH_STATUS_OKAY(TMP108_INIT)
436
437 #define AS6212_INIT(n) TMP108_DEFINE(n, AMS_AS6212)
438 #undef DT_DRV_COMPAT
439 #define DT_DRV_COMPAT ams_as6212
440 DT_INST_FOREACH_STATUS_OKAY(AS6212_INIT)
441