1 /*
2  * Copyright (c) 2019 Centaur Analytics, Inc
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ti_tmp116
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/drivers/sensor/tmp116.h>
13 #include <zephyr/dt-bindings/sensor/tmp116.h>
14 #include <zephyr/sys/util.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/sys/__assert.h>
17 #include <zephyr/logging/log.h>
18 #include <zephyr/kernel.h>
19 
20 #include "tmp116.h"
21 
22 #define  EEPROM_SIZE_REG sizeof(uint16_t)
23 #define  EEPROM_TMP117_RESERVED (2 * sizeof(uint16_t))
24 #define  EEPROM_MIN_BUSY_MS 7
25 
26 LOG_MODULE_REGISTER(TMP116, CONFIG_SENSOR_LOG_LEVEL);
27 
tmp116_reg_read(const struct device * dev,uint8_t reg,uint16_t * val)28 static int tmp116_reg_read(const struct device *dev, uint8_t reg,
29 			   uint16_t *val)
30 {
31 	const struct tmp116_dev_config *cfg = dev->config;
32 
33 	if (i2c_burst_read_dt(&cfg->bus, reg, (uint8_t *)val, 2)
34 	    < 0) {
35 		return -EIO;
36 	}
37 
38 	*val = sys_be16_to_cpu(*val);
39 
40 	return 0;
41 }
42 
tmp116_reg_write(const struct device * dev,uint8_t reg,uint16_t val)43 static int tmp116_reg_write(const struct device *dev, uint8_t reg,
44 			    uint16_t val)
45 {
46 	const struct tmp116_dev_config *cfg = dev->config;
47 	uint8_t tx_buf[3] = {reg, val >> 8, val & 0xFF};
48 
49 	return i2c_write_dt(&cfg->bus, tx_buf, sizeof(tx_buf));
50 }
51 
tmp116_write_config(const struct device * dev,uint16_t mask,uint16_t conf)52 int tmp116_write_config(const struct device *dev, uint16_t mask, uint16_t conf)
53 {
54 	uint16_t config = 0;
55 	int result;
56 
57 	result = tmp116_reg_read(dev, TMP116_REG_CFGR, &config);
58 
59 	if (result < 0) {
60 		return result;
61 	}
62 
63 	config &= ~mask;
64 	config |= conf;
65 
66 	return tmp116_reg_write(dev, TMP116_REG_CFGR, config);
67 }
68 
check_eeprom_bounds(const struct device * dev,off_t offset,size_t len)69 static bool check_eeprom_bounds(const struct device *dev, off_t offset,
70 			       size_t len)
71 {
72 	struct tmp116_data *drv_data = dev->data;
73 
74 	if ((offset + len) > EEPROM_TMP116_SIZE ||
75 	    offset % EEPROM_SIZE_REG != 0 ||
76 	    len % EEPROM_SIZE_REG != 0) {
77 		return false;
78 	}
79 
80 	/* TMP117 uses EEPROM[2] as temperature offset register */
81 	if (drv_data->id == TMP117_DEVICE_ID &&
82 	    offset <= EEPROM_TMP117_RESERVED &&
83 	    (offset + len) > EEPROM_TMP117_RESERVED) {
84 		return false;
85 	}
86 
87 	return true;
88 }
89 
tmp116_eeprom_write(const struct device * dev,off_t offset,const void * data,size_t len)90 int tmp116_eeprom_write(const struct device *dev, off_t offset,
91 			const void *data, size_t len)
92 {
93 	uint8_t reg;
94 	const uint16_t *src = data;
95 	int res;
96 
97 	if (!check_eeprom_bounds(dev, offset, len)) {
98 		return -EINVAL;
99 	}
100 
101 	res = tmp116_reg_write(dev, TMP116_REG_EEPROM_UL, TMP116_EEPROM_UL_UNLOCK);
102 	if (res) {
103 		return res;
104 	}
105 
106 	for (reg = (offset / 2); reg < offset / 2 + len / 2; reg++) {
107 		uint16_t val = *src;
108 
109 		res = tmp116_reg_write(dev, reg + TMP116_REG_EEPROM1, val);
110 		if (res != 0) {
111 			break;
112 		}
113 
114 		k_sleep(K_MSEC(EEPROM_MIN_BUSY_MS));
115 
116 		do {
117 			res = tmp116_reg_read(dev, TMP116_REG_EEPROM_UL, &val);
118 			if (res != 0) {
119 				break;
120 			}
121 		} while (val & TMP116_EEPROM_UL_BUSY);
122 		src++;
123 
124 		if (res != 0) {
125 			break;
126 		}
127 	}
128 
129 	res = tmp116_reg_write(dev, TMP116_REG_EEPROM_UL, 0);
130 
131 	return res;
132 }
133 
tmp116_eeprom_read(const struct device * dev,off_t offset,void * data,size_t len)134 int tmp116_eeprom_read(const struct device *dev, off_t offset, void *data,
135 		       size_t len)
136 {
137 	uint8_t reg;
138 	uint16_t *dst = data;
139 	int res = 0;
140 
141 	if (!check_eeprom_bounds(dev, offset, len)) {
142 		return -EINVAL;
143 	}
144 
145 	for (reg = (offset / 2); reg < offset / 2 + len / 2; reg++) {
146 		res = tmp116_reg_read(dev, reg + TMP116_REG_EEPROM1, dst);
147 		if (res != 0) {
148 			break;
149 		}
150 		dst++;
151 	}
152 
153 	return res;
154 }
155 
156 
157 /**
158  * @brief Check the Device ID
159  *
160  * @param[in]   dev     Pointer to the device structure
161  * @param[in]	id	Pointer to the variable for storing the device id
162  *
163  * @retval 0 on success
164  * @retval -EIO Otherwise
165  */
tmp116_device_id_check(const struct device * dev,uint16_t * id)166 static inline int tmp116_device_id_check(const struct device *dev, uint16_t *id)
167 {
168 	if (tmp116_reg_read(dev, TMP116_REG_DEVICE_ID, id) != 0) {
169 		LOG_ERR("%s: Failed to get Device ID register!",
170 			dev->name);
171 		return -EIO;
172 	}
173 
174 	if ((*id != TMP116_DEVICE_ID) && (*id != TMP117_DEVICE_ID)) {
175 		LOG_ERR("%s: Failed to match the device IDs!",
176 			dev->name);
177 		return -EINVAL;
178 	}
179 
180 	return 0;
181 }
182 
tmp116_sample_fetch(const struct device * dev,enum sensor_channel chan)183 static int tmp116_sample_fetch(const struct device *dev,
184 			       enum sensor_channel chan)
185 {
186 	struct tmp116_data *drv_data = dev->data;
187 	uint16_t value;
188 	uint16_t cfg_reg = 0;
189 	int rc;
190 
191 	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL ||
192 			chan == SENSOR_CHAN_AMBIENT_TEMP);
193 
194 	/* clear sensor values */
195 	drv_data->sample = 0U;
196 
197 	/* Make sure that a data is available */
198 	rc = tmp116_reg_read(dev, TMP116_REG_CFGR, &cfg_reg);
199 	if (rc < 0) {
200 		LOG_ERR("%s, Failed to read from CFGR register",
201 			dev->name);
202 		return rc;
203 	}
204 
205 	if ((cfg_reg & TMP116_CFGR_DATA_READY) == 0) {
206 		LOG_DBG("%s: no data ready", dev->name);
207 		return -EBUSY;
208 	}
209 
210 	/* Get the most recent temperature measurement */
211 	rc = tmp116_reg_read(dev, TMP116_REG_TEMP, &value);
212 	if (rc < 0) {
213 		LOG_ERR("%s: Failed to read from TEMP register!",
214 			dev->name);
215 		return rc;
216 	}
217 
218 	/* store measurements to the driver */
219 	drv_data->sample = (int16_t)value;
220 
221 	return 0;
222 }
223 
tmp116_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)224 static int tmp116_channel_get(const struct device *dev,
225 			      enum sensor_channel chan,
226 			      struct sensor_value *val)
227 {
228 	struct tmp116_data *drv_data = dev->data;
229 	int32_t tmp;
230 
231 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
232 		return -ENOTSUP;
233 	}
234 
235 	/*
236 	 * See datasheet "Temperature Results and Limits" section for more
237 	 * details on processing sample data.
238 	 */
239 	tmp = ((int16_t)drv_data->sample * (int32_t)TMP116_RESOLUTION) / 10;
240 	val->val1 = tmp / 1000000; /* uCelsius */
241 	val->val2 = tmp % 1000000;
242 
243 	return 0;
244 }
245 
tmp116_conv_value(const struct sensor_value * val)246 static int16_t tmp116_conv_value(const struct sensor_value *val)
247 {
248 	uint32_t freq_micro = sensor_value_to_micro(val);
249 
250 	switch (freq_micro) {
251 	case 64000000: /* 1 / 15.5 ms has been rounded down */
252 		return TMP116_DT_ODR_15_5_MS;
253 	case 8000000:
254 		return TMP116_DT_ODR_125_MS;
255 	case 4000000:
256 		return TMP116_DT_ODR_250_MS;
257 	case 2000000:
258 		return TMP116_DT_ODR_500_MS;
259 	case 1000000:
260 		return TMP116_DT_ODR_1000_MS;
261 	case 250000:
262 		return TMP116_DT_ODR_4000_MS;
263 	case 125000:
264 		return TMP116_DT_ODR_8000_MS;
265 	case 62500:
266 		return TMP116_DT_ODR_16000_MS;
267 	default:
268 		LOG_ERR("%" PRIu32 " uHz not supported", freq_micro);
269 		return -EINVAL;
270 	}
271 }
272 
tmp116_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)273 static int tmp116_attr_set(const struct device *dev,
274 			   enum sensor_channel chan,
275 			   enum sensor_attribute attr,
276 			   const struct sensor_value *val)
277 {
278 	struct tmp116_data *drv_data = dev->data;
279 	int16_t value;
280 	uint16_t avg;
281 
282 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
283 		return -ENOTSUP;
284 	}
285 
286 	switch ((int)attr) {
287 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
288 		value = tmp116_conv_value(val);
289 		if (value < 0) {
290 			return value;
291 		}
292 
293 		return tmp116_write_config(dev, TMP116_CFGR_CONV, value);
294 
295 	case SENSOR_ATTR_OFFSET:
296 		if (drv_data->id != TMP117_DEVICE_ID) {
297 			LOG_ERR("%s: Offset is only supported by TMP117",
298 			dev->name);
299 			return -EINVAL;
300 		}
301 		/*
302 		 * The offset is encoded into the temperature register format.
303 		 */
304 		value = (((val->val1) * 10000000) + ((val->val2) * 10))
305 						/ (int32_t)TMP116_RESOLUTION;
306 
307 		return tmp116_reg_write(dev, TMP117_REG_TEMP_OFFSET, value);
308 
309 	case SENSOR_ATTR_OVERSAMPLING:
310 		/* sensor supports averaging 1, 8, 32 and 64 samples */
311 		switch (val->val1) {
312 		case 1:
313 			avg = TMP116_AVG_1_SAMPLE;
314 			break;
315 
316 		case 8:
317 			avg = TMP116_AVG_8_SAMPLES;
318 			break;
319 
320 		case 32:
321 			avg = TMP116_AVG_32_SAMPLES;
322 			break;
323 
324 		case 64:
325 			avg = TMP116_AVG_64_SAMPLES;
326 			break;
327 
328 		default:
329 			return -EINVAL;
330 		}
331 		return tmp116_write_config(dev, TMP116_CFGR_AVG, avg);
332 	case SENSOR_ATTR_TMP116_SHUTDOWN_MODE:
333 		return tmp116_write_config(dev, TMP116_CFGR_MODE, TMP116_MODE_SHUTDOWN);
334 
335 	case SENSOR_ATTR_TMP116_CONTINUOUS_CONVERSION_MODE:
336 		return tmp116_write_config(dev, TMP116_CFGR_MODE, TMP116_MODE_CONTINUOUS);
337 
338 	case SENSOR_ATTR_TMP116_ONE_SHOT_MODE:
339 		return tmp116_write_config(dev, TMP116_CFGR_MODE, TMP116_MODE_ONE_SHOT);
340 
341 	default:
342 		return -ENOTSUP;
343 	}
344 }
345 
tmp116_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)346 static int tmp116_attr_get(const struct device *dev, enum sensor_channel chan,
347 			   enum sensor_attribute attr, struct sensor_value *val)
348 {
349 	uint16_t data;
350 	int rc;
351 
352 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
353 		return -ENOTSUP;
354 	}
355 
356 	switch (attr) {
357 	case SENSOR_ATTR_CONFIGURATION:
358 		rc = tmp116_reg_read(dev, TMP116_REG_CFGR, &data);
359 		if (rc < 0) {
360 			return rc;
361 		}
362 		break;
363 	default:
364 		return -ENOTSUP;
365 	}
366 
367 	val->val1 = data;
368 	val->val2 = 0;
369 
370 	return 0;
371 }
372 
373 static DEVICE_API(sensor, tmp116_driver_api) = {
374 	.attr_set = tmp116_attr_set,
375 	.attr_get = tmp116_attr_get,
376 	.sample_fetch = tmp116_sample_fetch,
377 	.channel_get = tmp116_channel_get
378 };
379 
tmp116_init(const struct device * dev)380 static int tmp116_init(const struct device *dev)
381 {
382 	struct tmp116_data *drv_data = dev->data;
383 	const struct tmp116_dev_config *cfg = dev->config;
384 	int rc;
385 	uint16_t id;
386 
387 	if (!device_is_ready(cfg->bus.bus)) {
388 		LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name);
389 		return -EINVAL;
390 	}
391 
392 	/* Check the Device ID */
393 	rc = tmp116_device_id_check(dev, &id);
394 	if (rc < 0) {
395 		return rc;
396 	}
397 	LOG_DBG("Got device ID: %x", id);
398 	drv_data->id = id;
399 
400 	rc = tmp116_write_config(dev, TMP116_CFGR_CONV, cfg->odr);
401 
402 	return rc;
403 }
404 
405 #define DEFINE_TMP116(_num) \
406 	static struct tmp116_data tmp116_data_##_num; \
407 	static const struct tmp116_dev_config tmp116_config_##_num = { \
408 		.bus = I2C_DT_SPEC_INST_GET(_num), \
409 		.odr = DT_INST_PROP(_num, odr), \
410 	}; \
411 	SENSOR_DEVICE_DT_INST_DEFINE(_num, tmp116_init, NULL, \
412 		&tmp116_data_##_num, &tmp116_config_##_num, POST_KERNEL, \
413 		CONFIG_SENSOR_INIT_PRIORITY, &tmp116_driver_api);
414 
415 DT_INST_FOREACH_STATUS_OKAY(DEFINE_TMP116)
416