Skip to content

Commit b8244fd

Browse files
talih0MaureenHelm
authored andcommitted
drivers: sensor: Add adt7310 temperature sensor
Adds adt7310 temperature controlled via spi. Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
1 parent 8fba8aa commit b8244fd

File tree

8 files changed

+570
-0
lines changed

8 files changed

+570
-0
lines changed

drivers/sensor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# SPDX-License-Identifier: Apache-2.0
22

3+
add_subdirectory_ifdef(CONFIG_ADT7310 adt7310)
34
add_subdirectory_ifdef(CONFIG_ADT7420 adt7420)
45
add_subdirectory_ifdef(CONFIG_ADXL345 adxl345)
56
add_subdirectory_ifdef(CONFIG_ADXL362 adxl362)

drivers/sensor/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ config SENSOR_INFO
4141

4242
comment "Device Drivers"
4343

44+
source "drivers/sensor/adt7310/Kconfig"
45+
4446
source "drivers/sensor/adt7420/Kconfig"
4547

4648
source "drivers/sensor/adxl345/Kconfig"

drivers/sensor/adt7310/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
5+
zephyr_library_sources_ifdef(CONFIG_ADT7310 adt7310.c)
6+
zephyr_library_sources_ifdef(CONFIG_ADT7310_TRIGGER adt7310_trigger.c)

drivers/sensor/adt7310/Kconfig

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# ADT7310 temperature sensor configuration options
2+
3+
# Copyright (c) 2023 Andriy Gelman
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
menuconfig ADT7310
7+
bool "ADT7310 Temperature Sensor"
8+
default y
9+
depends on DT_HAS_ADI_ADT7310_ENABLED
10+
select SPI
11+
help
12+
Enable the driver for Analog Devices ADT7310 High-Accuracy
13+
16-bit Digital SPI Temperature Sensors.
14+
15+
if ADT7310
16+
17+
config ADT7310_TRIGGER
18+
bool
19+
depends on GPIO
20+
21+
choice
22+
prompt "Sets trigger mode"
23+
default ADT7310_TRIGGER_NONE
24+
help
25+
Sets thread type for the interrupt handler.
26+
27+
config ADT7310_TRIGGER_NONE
28+
bool "No trigger"
29+
30+
config ADT7310_TRIGGER_GLOBAL_THREAD
31+
bool "Use global thread"
32+
select ADT7310_TRIGGER
33+
help
34+
Use a global thread for the interrupt handler.
35+
36+
config ADT7310_TRIGGER_OWN_THREAD
37+
bool "Use own thread"
38+
select ADT7310_TRIGGER
39+
help
40+
Use a separate thread for the interrupt handler.
41+
42+
endchoice
43+
44+
if ADT7310_TRIGGER_OWN_THREAD
45+
46+
config ADT7310_THREAD_PRIORITY
47+
int "Thread priority of the interrupt handler"
48+
default 1
49+
help
50+
Thread priority of the interrupt handler. A higher number implies a
51+
higher priority. The thread is cooperative and will not be interrupted by
52+
another thread until execution is released.
53+
54+
config ADT7310_THREAD_STACK_SIZE
55+
int "Stack size of the interrupt handler thread"
56+
default 1024
57+
help
58+
Stack size of the interrupt handler thread.
59+
60+
endif # ADT7310_TRIGGER_OWN_THREAD
61+
62+
endif # ADT7310

drivers/sensor/adt7310/adt7310.c

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
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+
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+
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+
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+
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+
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+
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+
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, &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+
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+
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+
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 const struct sensor_driver_api 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)

0 commit comments

Comments
 (0)