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