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