1 /*
2 * Copyright (c) 2023 Andriy Gelman <andriy.gelman@gmail.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT adi_adt7310
8
9 #include <string.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/drivers/spi.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/sys/byteorder.h>
14 #include <zephyr/sys/util.h>
15
16 #include "adt7310.h"
17
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(ADT7310, CONFIG_SENSOR_LOG_LEVEL);
20
21 #define ADT7310_READ_CMD BIT(6)
22 #define ADT7310_WRITE_CMD 0
23
24 #define ADT7310_REG_STATUS 0x00
25 #define ADT7310_REG_CONFIG 0x01
26 #define ADT7310_REG_TEMP 0x02
27 #define ADT7310_REG_ID 0x03
28 #define ADT7310_REG_HYST 0x05
29 #define ADT7310_REG_THRESH_HIGH 0x06
30 #define ADT7310_REG_THRESH_LOW 0x07
31
32 #define ADT7310_ID 0xc0
33 #define ADT7310_CONFIG_OP_MODE_MASK (0x3 << 5)
34 #define ADT7310_CONFIG_OP_MODE_CONTINUOUS (0x0 << 5)
35 #define ADT7310_CONFIG_OP_MODE_1SPS (0x2 << 5)
36
37 #define ADT7310_HYSTERESIS_TEMP_MAX 15
38 #define ADT7310_CONFIG_RESOLUTION_16BIT BIT(7)
39 #define ADT7310_CONFIG_INT_COMPARATOR_MODE BIT(4)
40
41 /* Continuous conversion time = 240ms -> 1/0.240*1000000 */
42 #define ADT7310_MAX_SAMPLE_RATE 4166666
43
44 /* The quantization step size at 16-bit resolution is 0.0078125. */
45 /* Ref ADT7310 Reference manual */
46 #define ADT7310_SAMPLE_TO_MICRO_DEG(x) ((x) * 15625 >> 1)
47 #define ADT7310_MICRO_DEG_TO_SAMPLE(x) ((x) / 15625 << 1)
48
adt7310_temp_reg_read(const struct device * dev,uint8_t reg,int16_t * val)49 static int adt7310_temp_reg_read(const struct device *dev, uint8_t reg, int16_t *val)
50 {
51 const struct adt7310_dev_config *cfg = dev->config;
52 uint8_t cmd_buf[3] = { ADT7310_READ_CMD | (reg << 3) };
53 int ret;
54 const struct spi_buf tx_buf = { .buf = cmd_buf, .len = sizeof(cmd_buf) };
55 const struct spi_buf rx_buf = { .buf = cmd_buf, .len = sizeof(cmd_buf) };
56 const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
57 const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
58
59 ret = spi_transceive_dt(&cfg->bus, &tx, &rx);
60 if (ret < 0) {
61 return ret;
62 }
63
64 memcpy(val, cmd_buf + 1, 2);
65 *val = sys_be16_to_cpu(*val);
66
67 return 0;
68 }
69
adt7310_temp_reg_write(const struct device * dev,uint8_t reg,int16_t val)70 static int adt7310_temp_reg_write(const struct device *dev, uint8_t reg, int16_t val)
71 {
72 const struct adt7310_dev_config *cfg = dev->config;
73 uint8_t cmd_buf[3];
74 const struct spi_buf tx_buf = { .buf = cmd_buf, .len = sizeof(cmd_buf) };
75 const struct spi_buf rx_buf = { .buf = cmd_buf, .len = sizeof(cmd_buf) };
76 const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
77 const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
78
79 cmd_buf[0] = ADT7310_WRITE_CMD | (reg << 3);
80 val = sys_cpu_to_be16(val);
81 memcpy(&cmd_buf[1], &val, sizeof(val));
82
83 return spi_transceive_dt(&cfg->bus, &tx, &rx);
84 }
85
adt7310_reg_read(const struct device * dev,uint8_t reg,uint8_t * val)86 static int adt7310_reg_read(const struct device *dev, uint8_t reg, uint8_t *val)
87 {
88 const struct adt7310_dev_config *cfg = dev->config;
89 uint8_t cmd_buf[2] = { ADT7310_READ_CMD | (reg << 3) };
90 const struct spi_buf tx_buf = { .buf = cmd_buf, .len = sizeof(cmd_buf) };
91 const struct spi_buf rx_buf = { .buf = cmd_buf, .len = sizeof(cmd_buf) };
92 const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
93 const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
94 int ret;
95
96 ret = spi_transceive_dt(&cfg->bus, &tx, &rx);
97 if (ret < 0) {
98 return ret;
99 }
100
101 *val = cmd_buf[1];
102
103 return 0;
104 }
105
adt7310_reg_write(const struct device * dev,uint8_t reg,uint8_t val)106 static int adt7310_reg_write(const struct device *dev, uint8_t reg, uint8_t val)
107 {
108 const struct adt7310_dev_config *cfg = dev->config;
109 uint8_t cmd_buf[2] = { ADT7310_WRITE_CMD | (reg << 3), val };
110 const struct spi_buf tx_buf = { .buf = cmd_buf, .len = sizeof(cmd_buf) };
111 const struct spi_buf rx_buf = { .buf = cmd_buf, .len = sizeof(cmd_buf) };
112 const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
113 const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
114
115 return spi_transceive_dt(&cfg->bus, &tx, &rx);
116 }
117
adt7310_sample_fetch(const struct device * dev,enum sensor_channel chan)118 static int adt7310_sample_fetch(const struct device *dev, enum sensor_channel chan)
119 {
120 struct adt7310_data *drv_data = dev->data;
121 int16_t value;
122 int ret;
123
124 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
125 return -ENOTSUP;
126 }
127
128 ret = adt7310_temp_reg_read(dev, ADT7310_REG_TEMP, &value);
129 if (ret < 0) {
130 return ret;
131 }
132
133 drv_data->sample = value;
134
135 return 0;
136 }
137
adt7310_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)138 static int adt7310_channel_get(const struct device *dev, enum sensor_channel chan,
139 struct sensor_value *val)
140 {
141 int32_t value;
142 struct adt7310_data *drv_data = dev->data;
143
144 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
145 return -ENOTSUP;
146 }
147
148 value = ADT7310_SAMPLE_TO_MICRO_DEG((int32_t)drv_data->sample);
149 val->val1 = value / 1000000;
150 val->val2 = value % 1000000;
151
152 return 0;
153 }
154
adt7310_update_reg(const struct device * dev,uint8_t reg,uint8_t value,uint8_t mask)155 static int adt7310_update_reg(const struct device *dev, uint8_t reg, uint8_t value, uint8_t mask)
156 {
157 int ret;
158 uint8_t reg_value;
159
160 ret = adt7310_reg_read(dev, reg, ®_value);
161 if (ret < 0) {
162 return ret;
163 }
164
165 reg_value &= ~mask;
166 reg_value |= value;
167
168 return adt7310_reg_write(dev, reg, reg_value);
169 }
170
adt7310_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)171 static int adt7310_attr_set(const struct device *dev, enum sensor_channel chan,
172 enum sensor_attribute attr, const struct sensor_value *val)
173 {
174 int32_t rate, value;
175 uint8_t reg = 0;
176
177 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
178 return -ENOTSUP;
179 }
180
181 if (val->val1 > INT32_MAX/1000000 - 1 || val->val1 < INT32_MIN/1000000 + 1) {
182 return -EINVAL;
183 }
184
185 switch (attr) {
186 case SENSOR_ATTR_SAMPLING_FREQUENCY:
187 rate = val->val1 * 1000000 + val->val2;
188
189 if (rate > ADT7310_MAX_SAMPLE_RATE || rate < 0) {
190 return -EINVAL;
191 }
192
193 if (rate > 1000000) {
194 return adt7310_update_reg(dev, ADT7310_REG_CONFIG,
195 ADT7310_CONFIG_OP_MODE_CONTINUOUS,
196 ADT7310_CONFIG_OP_MODE_MASK);
197 } else {
198 return adt7310_update_reg(dev, ADT7310_REG_CONFIG,
199 ADT7310_CONFIG_OP_MODE_1SPS,
200 ADT7310_CONFIG_OP_MODE_MASK);
201 }
202 case SENSOR_ATTR_HYSTERESIS:
203 if (val->val1 < 0 || val->val1 > ADT7310_HYSTERESIS_TEMP_MAX || val->val2 != 0) {
204 return -EINVAL;
205 }
206 return adt7310_reg_write(dev, ADT7310_REG_HYST, val->val1);
207 case SENSOR_ATTR_UPPER_THRESH:
208 reg = ADT7310_REG_THRESH_HIGH;
209 __fallthrough;
210 case SENSOR_ATTR_LOWER_THRESH:
211 if (!reg) {
212 reg = ADT7310_REG_THRESH_LOW;
213 }
214
215 value = val->val1 * 1000000 + val->val2;
216 value = ADT7310_MICRO_DEG_TO_SAMPLE(value);
217
218 if (value < INT16_MIN || value > INT16_MAX) {
219 return -EINVAL;
220 }
221 return adt7310_temp_reg_write(dev, reg, value);
222 default:
223 return -ENOTSUP;
224 }
225
226 return 0;
227 }
228
adt7310_probe(const struct device * dev)229 static int adt7310_probe(const struct device *dev)
230 {
231 uint8_t value;
232 int ret;
233
234 ret = adt7310_reg_read(dev, ADT7310_REG_ID, &value);
235
236 if (ret) {
237 return ret;
238 }
239
240 value &= 0xf8;
241 if (value != ADT7310_ID) {
242 LOG_ERR("Invalid device ID");
243 return -ENODEV;
244 }
245
246 return adt7310_reg_write(dev, ADT7310_REG_CONFIG,
247 ADT7310_CONFIG_RESOLUTION_16BIT |
248 ADT7310_CONFIG_INT_COMPARATOR_MODE);
249 }
250
251
adt7310_init(const struct device * dev)252 static int adt7310_init(const struct device *dev)
253 {
254 const struct adt7310_dev_config *cfg = dev->config;
255 int ret;
256
257 if (!spi_is_ready_dt(&cfg->bus)) {
258 LOG_ERR("SPI bus %s not ready", cfg->bus.bus->name);
259 return -ENODEV;
260 }
261
262 ret = adt7310_probe(dev);
263 if (ret) {
264 return ret;
265 }
266
267 #if defined(CONFIG_ADT7310_TRIGGER)
268 if (cfg->int_gpio.port) {
269 ret = adt7310_init_interrupt(dev);
270 if (ret) {
271 LOG_ERR("Failed to initialize interrupt");
272 return ret;
273 }
274 }
275 #endif
276 return ret;
277 }
278
279 static DEVICE_API(sensor, adt7310_driver_api) = {
280 .attr_set = adt7310_attr_set,
281 .sample_fetch = adt7310_sample_fetch,
282 .channel_get = adt7310_channel_get,
283 #if defined(CONFIG_ADT7310_TRIGGER)
284 .trigger_set = adt7310_trigger_set,
285 #endif
286 };
287
288 #define ADT7310_DEFINE(inst) \
289 static struct adt7310_data adt7310_data_##inst; \
290 \
291 static const struct adt7310_dev_config adt7310_config_##inst = { \
292 .bus = SPI_DT_SPEC_INST_GET( \
293 inst, \
294 (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA), 0), \
295 \
296 IF_ENABLED(CONFIG_ADT7310_TRIGGER, \
297 (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}),))}; \
298 \
299 SENSOR_DEVICE_DT_INST_DEFINE(inst, adt7310_init, NULL, &adt7310_data_##inst, \
300 &adt7310_config_##inst, POST_KERNEL, \
301 CONFIG_SENSOR_INIT_PRIORITY, &adt7310_driver_api);
302
303 DT_INST_FOREACH_STATUS_OKAY(ADT7310_DEFINE)
304