1 /*
2 * Copyright (c) 2016 Firmwave
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_tmp112
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/sys/util.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/drivers/sensor.h>
15 #include <zephyr/sys/__assert.h>
16 #include <zephyr/logging/log.h>
17 #include "tmp112.h"
18
19 LOG_MODULE_REGISTER(TMP112, CONFIG_SENSOR_LOG_LEVEL);
20
tmp112_reg_read(const struct tmp112_config * cfg,uint8_t reg,uint16_t * val)21 static int tmp112_reg_read(const struct tmp112_config *cfg, uint8_t reg, uint16_t *val)
22 {
23 if (i2c_burst_read_dt(&cfg->bus, reg, (uint8_t *)val, sizeof(*val)) < 0) {
24 return -EIO;
25 }
26
27 *val = sys_be16_to_cpu(*val);
28
29 return 0;
30 }
31
tmp112_reg_write(const struct tmp112_config * cfg,uint8_t reg,uint16_t val)32 static int tmp112_reg_write(const struct tmp112_config *cfg, uint8_t reg, uint16_t val)
33 {
34 uint8_t buf[3];
35
36 buf[0] = reg;
37 sys_put_be16(val, &buf[1]);
38
39 return i2c_write_dt(&cfg->bus, buf, sizeof(buf));
40 }
41
set_config_flags(struct tmp112_data * data,uint16_t mask,uint16_t value)42 static uint16_t set_config_flags(struct tmp112_data *data, uint16_t mask, uint16_t value)
43 {
44 return (data->config_reg & ~mask) | (value & mask);
45 }
46
tmp112_update_config(const struct device * dev,uint16_t mask,uint16_t val)47 static int tmp112_update_config(const struct device *dev, uint16_t mask, uint16_t val)
48 {
49 int rc;
50 struct tmp112_data *data = dev->data;
51 const uint16_t new_val = set_config_flags(data, mask, val);
52
53 rc = tmp112_reg_write(dev->config, TMP112_REG_CONFIG, new_val);
54 if (rc == 0) {
55 data->config_reg = new_val;
56 }
57
58 return rc;
59 }
60
tmp112_set_threshold(const struct device * dev,uint8_t reg,int64_t micro_c)61 static int tmp112_set_threshold(const struct device *dev, uint8_t reg, int64_t micro_c)
62 {
63 struct tmp112_data *drv_data = dev->data;
64 int64_t v;
65 uint16_t reg_value;
66
67 v = DIV_ROUND_CLOSEST(micro_c, TMP112_TEMP_SCALE);
68
69 if (drv_data->config_reg & TMP112_CONFIG_EM) {
70 if (!IN_RANGE(v, TMP112_TEMP_MIN_EM, TMP112_TEMP_MAX_EM)) {
71 return -EINVAL;
72 }
73 reg_value = (uint16_t)v << TMP112_DATA_EXTENDED_SHIFT;
74 } else {
75 if (!IN_RANGE(v, TMP112_TEMP_MIN, TMP112_TEMP_MAX)) {
76 return -EINVAL;
77 }
78 reg_value = (uint16_t)v << TMP112_DATA_NORMAL_SHIFT;
79 }
80
81 return tmp112_reg_write(dev->config, reg, reg_value);
82 }
83
tmp112_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)84 static int tmp112_attr_set(const struct device *dev, enum sensor_channel chan,
85 enum sensor_attribute attr, const struct sensor_value *val)
86 {
87 uint16_t value;
88 uint16_t cr;
89
90 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
91 return -ENOTSUP;
92 }
93
94 switch (attr) {
95 #if CONFIG_TMP112_FULL_SCALE_RUNTIME
96 case SENSOR_ATTR_FULL_SCALE:
97 /* the sensor supports two ranges -55 to 128 and -55 to 150 */
98 /* the value contains the upper limit */
99 if (val->val1 == 128) {
100 value = 0x0000;
101 } else if (val->val1 == 150) {
102 value = TMP112_CONFIG_EM;
103 } else {
104 return -ENOTSUP;
105 }
106
107 if (tmp112_update_config(dev, TMP112_CONFIG_EM, value) < 0) {
108 LOG_DBG("Failed to set attribute!");
109 return -EIO;
110 }
111 break;
112 #endif
113
114 #if CONFIG_TMP112_SAMPLING_FREQUENCY_RUNTIME
115 case SENSOR_ATTR_SAMPLING_FREQUENCY:
116 /* conversion rate in mHz */
117 cr = val->val1 * 1000 + val->val2 / 1000;
118
119 /* the sensor supports 0.25Hz, 1Hz, 4Hz and 8Hz */
120 /* conversion rate */
121 switch (cr) {
122 case 250:
123 value = TMP112_CONV_RATE(TMP112_CONV_RATE_025);
124 break;
125
126 case 1000:
127 value = TMP112_CONV_RATE(TMP112_CONV_RATE_1000);
128 break;
129
130 case 4000:
131 value = TMP112_CONV_RATE(TMP112_CONV_RATE_4);
132 break;
133
134 case 8000:
135 value = TMP112_CONV_RATE(TMP112_CONV_RATE_8);
136 break;
137
138 default:
139 return -ENOTSUP;
140 }
141
142 if (tmp112_update_config(dev, TMP112_CONV_RATE_MASK, value) < 0) {
143 LOG_DBG("Failed to set attribute!");
144 return -EIO;
145 }
146
147 break;
148 #endif
149
150 case SENSOR_ATTR_LOWER_THRESH:
151 return tmp112_set_threshold(dev, TMP112_REG_TLOW, sensor_value_to_micro(val));
152
153 case SENSOR_ATTR_UPPER_THRESH:
154 return tmp112_set_threshold(dev, TMP112_REG_THIGH, sensor_value_to_micro(val));
155
156 default:
157 return -ENOTSUP;
158 }
159
160 return 0;
161 }
162
tmp112_sample_fetch(const struct device * dev,enum sensor_channel chan)163 static int tmp112_sample_fetch(const struct device *dev, enum sensor_channel chan)
164 {
165 struct tmp112_data *drv_data = dev->data;
166 const struct tmp112_config *cfg = dev->config;
167 uint16_t val;
168
169 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP);
170
171 if (tmp112_reg_read(cfg, TMP112_REG_TEMPERATURE, &val) < 0) {
172 return -EIO;
173 }
174
175 if (val & TMP112_DATA_EXTENDED) {
176 drv_data->sample = arithmetic_shift_right((int16_t)val, TMP112_DATA_EXTENDED_SHIFT);
177 } else {
178 drv_data->sample = arithmetic_shift_right((int16_t)val, TMP112_DATA_NORMAL_SHIFT);
179 }
180
181 return 0;
182 }
183
tmp112_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)184 static int tmp112_channel_get(const struct device *dev, enum sensor_channel chan,
185 struct sensor_value *val)
186 {
187 struct tmp112_data *drv_data = dev->data;
188
189 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
190 return -ENOTSUP;
191 }
192
193 return sensor_value_from_micro(val, (int32_t)drv_data->sample * TMP112_TEMP_SCALE);
194 }
195
196 static DEVICE_API(sensor, tmp112_driver_api) = {
197 .attr_set = tmp112_attr_set,
198 .sample_fetch = tmp112_sample_fetch,
199 .channel_get = tmp112_channel_get,
200 };
201
tmp112_init(const struct device * dev)202 int tmp112_init(const struct device *dev)
203 {
204 const struct tmp112_config *cfg = dev->config;
205 struct tmp112_data *data = dev->data;
206 int ret;
207
208 if (!device_is_ready(cfg->bus.bus)) {
209 LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name);
210 return -EINVAL;
211 }
212
213 data->config_reg = TMP112_CONV_RATE(cfg->cr) | TMP112_CONV_RES_MASK |
214 (cfg->extended_mode ? TMP112_CONFIG_EM : 0);
215
216 ret = tmp112_update_config(dev, 0, 0);
217 if (ret) {
218 LOG_ERR("Failed to set configuration (%d)", ret);
219 return ret;
220 }
221
222 ret = tmp112_set_threshold(dev, TMP112_REG_TLOW, cfg->t_low_micro_c);
223 if (ret) {
224 LOG_ERR("Failed to set tLow threshold (%d)", ret);
225 return ret;
226 }
227
228 ret = tmp112_set_threshold(dev, TMP112_REG_THIGH, cfg->t_high_micro_c);
229 if (ret) {
230 LOG_ERR("Failed to set tHigh threshold (%d)", ret);
231 return ret;
232 }
233
234 return 0;
235 }
236
237 #define TMP112_INST(inst) \
238 static struct tmp112_data tmp112_data_##inst; \
239 static const struct tmp112_config tmp112_config_##inst = { \
240 .bus = I2C_DT_SPEC_INST_GET(inst), \
241 .cr = DT_INST_ENUM_IDX(inst, conversion_rate), \
242 .t_low_micro_c = DT_INST_PROP(inst, t_low_micro_c), \
243 .t_high_micro_c = DT_INST_PROP(inst, t_high_micro_c), \
244 .extended_mode = DT_INST_PROP(inst, extended_mode), \
245 }; \
246 \
247 SENSOR_DEVICE_DT_INST_DEFINE(inst, tmp112_init, NULL, &tmp112_data_##inst, \
248 &tmp112_config_##inst, POST_KERNEL, \
249 CONFIG_SENSOR_INIT_PRIORITY, &tmp112_driver_api);
250
251 DT_INST_FOREACH_STATUS_OKAY(TMP112_INST)
252