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