1 /*
2 * Copyright (c) 2024 Fredrik Gihl
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_tmp114
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/kernel.h>
16
17 LOG_MODULE_REGISTER(TMP114, CONFIG_SENSOR_LOG_LEVEL);
18
19 #define TMP114_REG_TEMP 0x0
20 #define TMP114_REG_ALERT 0x2
21 #define TMP114_REG_CFGR 0x3
22 #define TMP114_REG_DEVICE_ID 0xb
23
24 #define TMP114_RESOLUTION 78125 /* in tens of uCelsius*/
25 #define TMP114_RESOLUTION_DIV 10000000
26
27 #define TMP114_DEVICE_ID 0x1114
28
29 #define TMP114_ALERT_DATA_READY BIT(0)
30 #define TMP114_AVG_MASK BIT(7)
31
32 struct tmp114_data {
33 uint16_t sample;
34 uint16_t id;
35 };
36
37 struct tmp114_dev_config {
38 struct i2c_dt_spec bus;
39 };
40
tmp114_reg_read(const struct device * dev,uint8_t reg,uint16_t * val)41 static int tmp114_reg_read(const struct device *dev, uint8_t reg,
42 uint16_t *val)
43 {
44 const struct tmp114_dev_config *cfg = dev->config;
45
46 if (i2c_burst_read_dt(&cfg->bus, reg, (uint8_t *)val, 2)
47 < 0) {
48 return -EIO;
49 }
50
51 *val = sys_be16_to_cpu(*val);
52
53 return 0;
54 }
55
tmp114_reg_write(const struct device * dev,uint8_t reg,uint16_t val)56 static int tmp114_reg_write(const struct device *dev, uint8_t reg,
57 uint16_t val)
58 {
59 const struct tmp114_dev_config *cfg = dev->config;
60 uint8_t tx_buf[3] = {reg, val >> 8, val & 0xFF};
61
62 return i2c_write_dt(&cfg->bus, tx_buf, sizeof(tx_buf));
63 }
64
tmp114_device_id_check(const struct device * dev,uint16_t * id)65 static inline int tmp114_device_id_check(const struct device *dev, uint16_t *id)
66 {
67 if (tmp114_reg_read(dev, TMP114_REG_DEVICE_ID, id) != 0) {
68 LOG_ERR("%s: Failed to get Device ID register!", dev->name);
69 return -EIO;
70 }
71
72 if (*id != TMP114_DEVICE_ID) {
73 LOG_ERR("%s: Failed to match the device ID!", dev->name);
74 return -EINVAL;
75 }
76
77 return 0;
78 }
79
tmp114_sample_fetch(const struct device * dev,enum sensor_channel chan)80 static int tmp114_sample_fetch(const struct device *dev,
81 enum sensor_channel chan)
82 {
83 struct tmp114_data *drv_data = dev->data;
84 uint16_t value;
85 uint16_t cfg_reg = 0;
86 int rc;
87
88 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL ||
89 chan == SENSOR_CHAN_AMBIENT_TEMP);
90
91 /* clear sensor values */
92 drv_data->sample = 0U;
93
94 /* Check alert register to make sure that a data is available */
95 rc = tmp114_reg_read(dev, TMP114_REG_ALERT, &cfg_reg);
96 if (rc < 0) {
97 LOG_ERR("%s, Failed to read from CFGR register", dev->name);
98 return rc;
99 }
100
101 if ((cfg_reg & TMP114_ALERT_DATA_READY) == 0) {
102 LOG_DBG("%s: no data ready", dev->name);
103 return -EBUSY;
104 }
105
106 /* Get the most recent temperature measurement */
107 rc = tmp114_reg_read(dev, TMP114_REG_TEMP, &value);
108 if (rc < 0) {
109 LOG_ERR("%s: Failed to read from TEMP register!", dev->name);
110 return rc;
111 }
112
113 /* store measurements to the driver */
114 drv_data->sample = (int16_t)value;
115
116 return 0;
117 }
118
tmp114_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)119 static int tmp114_channel_get(const struct device *dev,
120 enum sensor_channel chan,
121 struct sensor_value *val)
122 {
123 struct tmp114_data *drv_data = dev->data;
124 int32_t tmp;
125
126 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
127 return -ENOTSUP;
128 }
129
130 /*
131 * See datasheet for tmp114, section 'Temp_Result Register' section
132 * for more details on processing sample data.
133 */
134 tmp = ((int16_t)drv_data->sample * (int32_t)TMP114_RESOLUTION) / 10;
135 val->val1 = tmp / 1000000; /* uCelsius */
136 val->val2 = tmp % 1000000;
137
138 return 0;
139 }
140
tmp114_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)141 static int tmp114_attr_get(const struct device *dev, enum sensor_channel chan,
142 enum sensor_attribute attr, struct sensor_value *val)
143 {
144 uint16_t data;
145 int rc;
146
147 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
148 return -ENOTSUP;
149 }
150
151 switch (attr) {
152 case SENSOR_ATTR_CONFIGURATION:
153 rc = tmp114_reg_read(dev, TMP114_REG_CFGR, &data);
154 if (rc < 0) {
155 return rc;
156 }
157 break;
158 default:
159 return -ENOTSUP;
160 }
161
162 val->val1 = data;
163 val->val2 = 0;
164
165 return 0;
166 }
167
tmp114_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)168 static int tmp114_attr_set(const struct device *dev,
169 enum sensor_channel chan,
170 enum sensor_attribute attr,
171 const struct sensor_value *val)
172 {
173 int16_t value;
174 int rc;
175
176 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
177 return -ENOTSUP;
178 }
179
180 switch (attr) {
181 case SENSOR_ATTR_OVERSAMPLING:
182 /* Enable the AVG in tmp114. The chip will do 8 avg of 8 samples
183 * to get a more accurate value.
184 */
185 rc = tmp114_reg_read(dev, TMP114_REG_CFGR, &value);
186 if (rc < 0) {
187 return rc;
188 }
189 value = value & ~TMP114_AVG_MASK;
190 if (val->val1) {
191 value |= TMP114_AVG_MASK;
192 }
193
194 return tmp114_reg_write(dev, TMP114_REG_CFGR, value);
195 default:
196 return -ENOTSUP;
197 }
198 }
199
200 static DEVICE_API(sensor, tmp114_driver_api) = {
201 .attr_get = tmp114_attr_get,
202 .attr_set = tmp114_attr_set,
203 .sample_fetch = tmp114_sample_fetch,
204 .channel_get = tmp114_channel_get
205 };
206
tmp114_init(const struct device * dev)207 static int tmp114_init(const struct device *dev)
208 {
209 struct tmp114_data *drv_data = dev->data;
210 const struct tmp114_dev_config *cfg = dev->config;
211 int rc;
212 uint16_t id;
213
214 if (!i2c_is_ready_dt(&cfg->bus)) {
215 LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name);
216 return -EINVAL;
217 }
218
219 /* Check the Device ID */
220 rc = tmp114_device_id_check(dev, &id);
221 if (rc < 0) {
222 return rc;
223 }
224 LOG_INF("Got device ID: %x", id);
225 drv_data->id = id;
226
227 return 0;
228 }
229
230 #define DEFINE_TMP114(_num) \
231 static struct tmp114_data tmp114_data_##_num; \
232 static const struct tmp114_dev_config tmp114_config_##_num = { \
233 .bus = I2C_DT_SPEC_INST_GET(_num) \
234 }; \
235 SENSOR_DEVICE_DT_INST_DEFINE(_num, tmp114_init, NULL, \
236 &tmp114_data_##_num, &tmp114_config_##_num, POST_KERNEL, \
237 CONFIG_SENSOR_INIT_PRIORITY, &tmp114_driver_api);
238
239 DT_INST_FOREACH_STATUS_OKAY(DEFINE_TMP114)
240