1 /*
2  * Copyright (c) 2024 Bittium Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ti_tmp435
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/drivers/sensor.h>
16 #include <zephyr/logging/log.h>
17 #include "tmp435.h"
18 
19 LOG_MODULE_REGISTER(TMP435, CONFIG_SENSOR_LOG_LEVEL);
20 
tmp435_reg_read(const struct tmp435_config * cfg,uint8_t reg,uint8_t * buf,uint32_t size)21 static inline int tmp435_reg_read(const struct tmp435_config *cfg, uint8_t reg, uint8_t *buf,
22 				  uint32_t size)
23 {
24 	return i2c_burst_read_dt(&cfg->i2c, reg, buf, size);
25 }
26 
tmp435_reg_write(const struct tmp435_config * cfg,uint8_t reg,uint8_t * buf,uint32_t size)27 static inline int tmp435_reg_write(const struct tmp435_config *cfg, uint8_t reg, uint8_t *buf,
28 				   uint32_t size)
29 {
30 	return i2c_burst_write_dt(&cfg->i2c, reg, buf, size);
31 }
32 
tmp435_get_status(const struct tmp435_config * cfg,uint8_t * status)33 static inline int tmp435_get_status(const struct tmp435_config *cfg, uint8_t *status)
34 {
35 	return tmp435_reg_read(cfg, TMP435_STATUS_REG, status, 1);
36 }
37 
tmp435_one_shot(const struct device * dev)38 static int tmp435_one_shot(const struct device *dev)
39 {
40 	uint8_t data = 0;
41 	uint8_t status = 0;
42 	int ret = 0;
43 	const struct tmp435_config *cfg = dev->config;
44 
45 	data = 1; /* write anything to start */
46 	ret = tmp435_reg_write(cfg, TMP435_ONE_SHOT_START_REG, &data, 1);
47 	for (uint16_t i = 0; i < TMP435_CONV_LOOP_LIMIT; i++) {
48 		ret = tmp435_get_status(cfg, &status);
49 		if (ret < 0) {
50 			LOG_DBG("Failed to read TMP435_STATUS_REG, ret:%d", ret);
51 		} else {
52 			if (status & TMP435_STATUS_REG_BUSY) {
53 				/* conversion not ready */
54 				k_msleep(10);
55 			} else {
56 				LOG_DBG("conv over, loops:%d status:%x", i, status);
57 				break;
58 			}
59 		}
60 	}
61 	return ret;
62 }
63 
tmp435_sample_fetch(const struct device * dev,enum sensor_channel chan)64 static int tmp435_sample_fetch(const struct device *dev, enum sensor_channel chan)
65 {
66 	int ret = 0;
67 	uint8_t value = 0;
68 	int32_t temp = 0;
69 	const struct tmp435_config *cfg = dev->config;
70 	struct tmp435_data *data = dev->data;
71 
72 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP &&
73 	    chan != SENSOR_CHAN_AMBIENT_TEMP) {
74 		return -ENOTSUP;
75 	}
76 	tmp435_one_shot(dev); /* start conversion */
77 	if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_DIE_TEMP)) {
78 		ret = tmp435_reg_read(cfg, TMP435_LOCAL_TEMP_H_REG, &value, sizeof(value));
79 		if (ret < 0) {
80 			LOG_ERR("Failed to read TMP435_LOCAL_TEMP_H_REG, ret:%d", ret);
81 			return ret;
82 		}
83 		temp = value;
84 		ret = tmp435_reg_read(cfg, TMP435_LOCAL_TEMP_L_REG, &value, sizeof(value));
85 		if (ret < 0) {
86 			LOG_ERR("Failed to read TMP435_LOCAL_TEMP_L_REG, ret:%d", ret);
87 			return ret;
88 		}
89 		if (value > TMP435_FRACTION_INC) {
90 			temp++;
91 		}
92 		data->temp_die = temp + tmp435_temp_offset;
93 	}
94 
95 	if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_AMBIENT_TEMP)) {
96 		if (!(cfg->external_channel)) {
97 			return 0; /* not enabled, just return */
98 		}
99 		ret = tmp435_reg_read(cfg, TMP435_REMOTE_TEMP_H_REG, &value, sizeof(value));
100 		if (ret < 0) {
101 			LOG_ERR("Failed to read TMP435_REMOTE_TEMP_H_REG ret:%d", ret);
102 			return ret;
103 		}
104 		temp = value;
105 		ret = tmp435_reg_read(cfg, TMP435_REMOTE_TEMP_L_REG, &value, sizeof(value));
106 		if (ret < 0) {
107 			LOG_ERR("Failed to read TMP435_REMOTE_TEMP_L_REG, ret:%d", ret);
108 			return ret;
109 		}
110 		if (value > TMP435_FRACTION_INC) {
111 			temp++;
112 		}
113 		data->temp_ambient = temp + tmp435_temp_offset;
114 	}
115 	return 0;
116 }
117 
tmp435_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)118 static int tmp435_channel_get(const struct device *dev, enum sensor_channel chan,
119 			      struct sensor_value *val)
120 {
121 	int ret = 0;
122 	struct tmp435_data *data = dev->data;
123 	const struct tmp435_config *cfg = dev->config;
124 
125 	switch (chan) {
126 
127 	case SENSOR_CHAN_DIE_TEMP:
128 		val->val1 = data->temp_die;
129 		val->val2 = 0;
130 		break;
131 	case SENSOR_CHAN_AMBIENT_TEMP:
132 		if (cfg->external_channel) {
133 			val->val1 = data->temp_ambient;
134 			val->val2 = 0;
135 		} else {
136 			ret = -ENOTSUP;
137 		}
138 		break;
139 	default:
140 		ret = -ENOTSUP;
141 		break;
142 	}
143 	return ret;
144 }
145 
146 static DEVICE_API(sensor, tmp435_driver_api) = {
147 	.sample_fetch = tmp435_sample_fetch,
148 	.channel_get = tmp435_channel_get,
149 };
150 
tmp435_init(const struct device * dev)151 static int tmp435_init(const struct device *dev)
152 {
153 	uint8_t data = 0;
154 	int ret = 0;
155 	const struct tmp435_config *cfg = dev->config;
156 
157 	if (!(i2c_is_ready_dt(&cfg->i2c))) {
158 		LOG_ERR("I2C dev not ready");
159 		return -ENODEV;
160 	}
161 
162 	data = 1; /* write anything to reset */
163 	ret = tmp435_reg_write(cfg, TMP435_SOFTWARE_RESET_REG, &data, 1);
164 	if (ret < 0) {
165 		LOG_ERR("Failed to write TMP435_SOFTWARE_RESET_REG ret:%d", ret);
166 		return ret;
167 	}
168 
169 	data = TMP435_CONF_REG_1_DATA;
170 	ret = tmp435_reg_write(cfg, TMP435_CONF_REG_1, &data, 1);
171 	if (ret < 0) {
172 		LOG_ERR("Failed to write TMP435_CONF_REG_1 ret:%d", ret);
173 		return ret;
174 	}
175 
176 	data = TMP435_CONF_REG_2_DATA;
177 	if (cfg->external_channel) {
178 		data = data + TMP435_CONF_REG_2_REN;
179 	}
180 	if (cfg->resistance_correction) {
181 		data = data + TMP435_CONF_REG_2_RC;
182 	}
183 	ret = tmp435_reg_write(cfg, TMP435_CONF_REG_2, &data, 1);
184 	if (ret < 0) {
185 		LOG_ERR("Failed to write TMP435_CONF_REG_2 ret:%d", ret);
186 		return ret;
187 	}
188 
189 	data = cfg->beta_compensation;
190 	ret = tmp435_reg_write(cfg, TMP435_BETA_RANGE_REG, &data, 1);
191 	if (ret < 0) {
192 		LOG_ERR("Failed to write TMP435_BETA_RANGE_REG ret:%d", ret);
193 		return ret;
194 	}
195 	return 0;
196 }
197 
198 /*
199  * Device creation macros
200  */
201 
202 #define TMP435_INST(inst)                                                                          \
203 	static struct tmp435_data tmp435_data_##inst;                                              \
204 	static const struct tmp435_config tmp435_config_##inst = {                                 \
205 		.i2c = I2C_DT_SPEC_INST_GET(inst),                                                 \
206 		.external_channel = DT_INST_PROP(inst, external_channel),                          \
207 		.resistance_correction = DT_INST_PROP(inst, resistance_correction),                \
208 		.beta_compensation = DT_INST_PROP(inst, beta_compensation),                        \
209 	};                                                                                         \
210 	SENSOR_DEVICE_DT_INST_DEFINE(inst, tmp435_init, NULL, &tmp435_data_##inst,                 \
211 				     &tmp435_config_##inst, POST_KERNEL,                           \
212 				     CONFIG_SENSOR_INIT_PRIORITY, &tmp435_driver_api);
213 
214 DT_INST_FOREACH_STATUS_OKAY(TMP435_INST)
215