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