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 int result;
104
105 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
106 return -ENOTSUP;
107 }
108
109 /* If one shot mode is set, query chip for reading
110 * should be finished 30 ms later
111 */
112 if (drv_data->one_shot_mode == true) {
113
114 result = tmp108_write_config(dev,
115 TI_TMP108_MODE_MASK(dev),
116 TI_TMP108_MODE_ONE_SHOT(dev));
117
118 if (result < 0) {
119 return result;
120 }
121
122 /* Schedule read to start in 30 ms if mode change was successful
123 * the typical wakeup time given in the data sheet is 27
124 */
125 result = k_work_schedule(&drv_data->scheduled_work,
126 K_MSEC(TMP108_WAKEUP_TIME_IN_MS(dev)));
127
128 if (result < 0) {
129 return result;
130 }
131
132 return 0;
133 }
134
135 result = ti_tmp108_read_temp(dev);
136
137 if (result < 0) {
138 return result;
139 }
140
141 return 0;
142 }
143
tmp108_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)144 static int tmp108_channel_get(const struct device *dev,
145 enum sensor_channel chan,
146 struct sensor_value *val)
147 {
148 struct tmp108_data *drv_data = dev->data;
149 int32_t uval;
150
151 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
152 return -ENOTSUP;
153 }
154
155 uval = ((int32_t)drv_data->sample * TMP108_TEMP_MULTIPLIER(dev)) / TMP108_TEMP_DIVISOR(dev);
156 val->val1 = uval / 1000000;
157 val->val2 = uval % 1000000;
158
159 return 0;
160 }
161
tmp108_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)162 static int tmp108_attr_get(const struct device *dev,
163 enum sensor_channel chan,
164 enum sensor_attribute attr,
165 struct sensor_value *val)
166 {
167 int result;
168 uint16_t tmp_val;
169
170 if (chan != SENSOR_CHAN_AMBIENT_TEMP && chan != SENSOR_CHAN_ALL) {
171 return -ENOTSUP;
172 }
173
174 switch ((int) attr) {
175 case SENSOR_ATTR_CONFIGURATION:
176 result = tmp108_reg_read(dev,
177 TI_TMP108_REG_CONF,
178 &tmp_val);
179 val->val1 = tmp_val;
180 val->val2 = 0;
181 break;
182 default:
183 return -ENOTSUP;
184 }
185
186 return result;
187 }
188
tmp108_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)189 static int tmp108_attr_set(const struct device *dev,
190 enum sensor_channel chan,
191 enum sensor_attribute attr,
192 const struct sensor_value *val)
193 {
194 struct tmp108_data *drv_data = dev->data;
195 uint16_t mode = 0;
196 uint16_t reg_value = 0;
197 int result = 0;
198 int32_t uval;
199
200 if (chan != SENSOR_CHAN_AMBIENT_TEMP && chan != SENSOR_CHAN_ALL) {
201 return -ENOTSUP;
202 }
203
204 switch ((int) attr) {
205 case SENSOR_ATTR_HYSTERESIS:
206 if (TI_TMP108_HYSTER_0_C(dev) == TI_TMP108_CONF_NA) {
207 LOG_WRN("AS621x Series lacks Hysterisis setttings");
208 return -ENOTSUP;
209 }
210 if (val->val1 < 1) {
211 mode = TI_TMP108_HYSTER_0_C(dev);
212 } else if (val->val1 < 2) {
213 mode = TI_TMP108_HYSTER_1_C(dev);
214 } else if (val->val1 < 4) {
215 mode = TI_TMP108_HYSTER_2_C(dev);
216 } else {
217 mode = TI_TMP108_HYSTER_4_C(dev);
218 }
219
220 result = tmp108_write_config(dev,
221 TI_TMP108_HYSTER_MASK(dev),
222 mode);
223 break;
224
225 case SENSOR_ATTR_ALERT:
226 /* Spec Sheet Errata: TM is set on reset not cleared */
227 if (val->val1 == 1) {
228 mode = TI_TMP108_CONF_TM_INT(dev);
229 } else {
230 mode = TI_TMP108_CONF_TM_CMP(dev);
231 }
232
233 result = tmp108_write_config(dev,
234 TI_TMP108_CONF_TM_MASK(dev),
235 mode);
236 break;
237
238 case SENSOR_ATTR_LOWER_THRESH:
239 uval = val->val1 * 1000000 + val->val2;
240 reg_value = (uval * TMP108_TEMP_DIVISOR(dev)) / TMP108_TEMP_MULTIPLIER(dev);
241 result = tmp108_reg_write(dev,
242 TI_TMP108_REG_LOW_LIMIT,
243 reg_value);
244 break;
245
246 case SENSOR_ATTR_UPPER_THRESH:
247 uval = val->val1 * 1000000 + val->val2;
248 reg_value = (uval * TMP108_TEMP_DIVISOR(dev)) / TMP108_TEMP_MULTIPLIER(dev);
249 result = tmp108_reg_write(dev,
250 TI_TMP108_REG_HIGH_LIMIT,
251 reg_value);
252 break;
253
254 case SENSOR_ATTR_SAMPLING_FREQUENCY:
255 if (val->val1 < 1) {
256 mode = TI_TMP108_FREQ_4_SECS(dev);
257 } else if (val->val1 < 4) {
258 mode = TI_TMP108_FREQ_1_HZ(dev);
259 } else if (val->val1 < 16) {
260 mode = TI_TMP108_FREQ_4_HZ(dev);
261 } else {
262 mode = TI_TMP108_FREQ_16_HZ(dev);
263 }
264 result = tmp108_write_config(dev,
265 TI_TMP108_FREQ_MASK(dev),
266 mode);
267 break;
268
269 case SENSOR_ATTR_TMP108_SHUTDOWN_MODE:
270 result = tmp108_write_config(dev,
271 TI_TMP108_MODE_MASK(dev),
272 TI_TMP108_MODE_SHUTDOWN(dev));
273 drv_data->one_shot_mode = false;
274 break;
275
276 case SENSOR_ATTR_TMP108_CONTINUOUS_CONVERSION_MODE:
277 result = tmp108_write_config(dev,
278 TI_TMP108_MODE_MASK(dev),
279 TI_TMP108_MODE_CONTINUOUS(dev));
280 drv_data->one_shot_mode = false;
281 break;
282
283 case SENSOR_ATTR_TMP108_ONE_SHOT_MODE:
284 result = tmp108_write_config(dev,
285 TI_TMP108_MODE_MASK(dev),
286 TI_TMP108_MODE_ONE_SHOT(dev));
287 drv_data->one_shot_mode = true;
288 break;
289
290 case SENSOR_ATTR_TMP108_ALERT_POLARITY:
291 if (val->val1 == 1) {
292 mode = TI_TMP108_CONF_POL_HIGH(dev);
293 } else {
294 mode = TI_TMP108_CONF_POL_LOW(dev);
295 }
296 result = tmp108_write_config(dev,
297 TI_TMP108_CONF_POL_MASK(dev),
298 mode);
299 break;
300
301 default:
302 return -ENOTSUP;
303 }
304
305 if (result < 0) {
306 return result;
307 }
308
309 return 0;
310 }
311
312 static DEVICE_API(sensor, tmp108_driver_api) = {
313 .attr_set = tmp108_attr_set,
314 .attr_get = tmp108_attr_get,
315 .sample_fetch = tmp108_sample_fetch,
316 .channel_get = tmp108_channel_get,
317 .trigger_set = tmp_108_trigger_set,
318 };
319
320 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
setup_interrupts(const struct device * dev)321 static int setup_interrupts(const struct device *dev)
322 {
323 struct tmp108_data *drv_data = dev->data;
324 const struct tmp108_config *config = dev->config;
325 const struct gpio_dt_spec *alert_gpio = &config->alert_gpio;
326 int result;
327
328 if (!device_is_ready(alert_gpio->port)) {
329 LOG_ERR("tmp108: gpio controller %s not ready",
330 alert_gpio->port->name);
331 return -ENODEV;
332 }
333
334 result = gpio_pin_configure_dt(alert_gpio, GPIO_INPUT);
335
336 if (result < 0) {
337 return result;
338 }
339
340 gpio_init_callback(&drv_data->temp_alert_gpio_cb,
341 tmp108_trigger_handle_alert,
342 BIT(alert_gpio->pin));
343
344 result = gpio_add_callback(alert_gpio->port,
345 &drv_data->temp_alert_gpio_cb);
346
347 if (result < 0) {
348 return result;
349 }
350
351 result = gpio_pin_interrupt_configure_dt(alert_gpio,
352 GPIO_INT_EDGE_BOTH);
353
354 if (result < 0) {
355 return result;
356 }
357
358 return 0;
359 }
360 #endif
361
tmp108_init(const struct device * dev)362 static int tmp108_init(const struct device *dev)
363 {
364 const struct tmp108_config *cfg = dev->config;
365 struct tmp108_data *drv_data = dev->data;
366 int result = 0;
367
368 if (!device_is_ready(cfg->i2c_spec.bus)) {
369 LOG_ERR("I2C dev %s not ready", cfg->i2c_spec.bus->name);
370 return -ENODEV;
371 }
372
373 drv_data->scheduled_work.work.handler = tmp108_trigger_handle_one_shot;
374
375 /* save this driver instance for passing to other functions */
376 drv_data->tmp108_dev = dev;
377
378 #ifdef CONFIG_TMP108_ALERT_INTERRUPTS
379 result = setup_interrupts(dev);
380
381 if (result < 0) {
382 return result;
383 }
384 #endif
385 /* clear and set configuration registers back to default values */
386 result = tmp108_write_config(dev,
387 0x0000,
388 TMP108_CONF_RST(dev));
389 return result;
390 }
391
392 #define TMP108_DEFINE(inst, t) \
393 static struct tmp108_data tmp108_prv_data_##inst##t; \
394 static const struct tmp108_config tmp108_config_##inst##t = { \
395 .i2c_spec = I2C_DT_SPEC_INST_GET(inst), \
396 .alert_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, \
397 alert_gpios, { 0 }),\
398 .reg_def = t##_CONF \
399 }; \
400 SENSOR_DEVICE_DT_INST_DEFINE(inst, \
401 &tmp108_init, \
402 NULL, \
403 &tmp108_prv_data_##inst##t, \
404 &tmp108_config_##inst##t, \
405 POST_KERNEL, \
406 CONFIG_SENSOR_INIT_PRIORITY, \
407 &tmp108_driver_api);
408
409 #define TMP108_INIT(n) TMP108_DEFINE(n, TI_TMP108)
410 #undef DT_DRV_COMPAT
411 #define DT_DRV_COMPAT ti_tmp108
412 DT_INST_FOREACH_STATUS_OKAY(TMP108_INIT)
413
414 #define AS6212_INIT(n) TMP108_DEFINE(n, AMS_AS6212)
415 #undef DT_DRV_COMPAT
416 #define DT_DRV_COMPAT ams_as6212
417 DT_INST_FOREACH_STATUS_OKAY(AS6212_INIT)
418