1 /*
2 * Copyright (c) 2018 Analog Devices Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT adi_adt7420
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
17 #include "adt7420.h"
18
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(ADT7420, CONFIG_SENSOR_LOG_LEVEL);
21
adt7420_temp_reg_read(const struct device * dev,uint8_t reg,int16_t * val)22 static int adt7420_temp_reg_read(const struct device *dev, uint8_t reg,
23 int16_t *val)
24 {
25 const struct adt7420_dev_config *cfg = dev->config;
26
27 if (i2c_burst_read_dt(&cfg->i2c, reg, (uint8_t *) val, 2) < 0) {
28 return -EIO;
29 }
30
31 *val = sys_be16_to_cpu(*val);
32
33 return 0;
34 }
35
adt7420_temp_reg_write(const struct device * dev,uint8_t reg,int16_t val)36 static int adt7420_temp_reg_write(const struct device *dev, uint8_t reg,
37 int16_t val)
38 {
39 const struct adt7420_dev_config *cfg = dev->config;
40 uint8_t buf[3] = {reg, val >> 8, val & 0xFF};
41
42 return i2c_write_dt(&cfg->i2c, buf, sizeof(buf));
43 }
44
adt7420_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)45 static int adt7420_attr_set(const struct device *dev,
46 enum sensor_channel chan,
47 enum sensor_attribute attr,
48 const struct sensor_value *val)
49 {
50 const struct adt7420_dev_config *cfg = dev->config;
51 uint8_t val8, reg = 0U;
52 uint16_t rate;
53 int64_t value;
54
55 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
56 return -ENOTSUP;
57 }
58
59 switch (attr) {
60 case SENSOR_ATTR_SAMPLING_FREQUENCY:
61 rate = val->val1 * 1000 + val->val2 / 1000; /* rate in mHz */
62
63 switch (rate) {
64 case 240:
65 val8 = ADT7420_OP_MODE_CONT_CONV;
66 break;
67 case 1000:
68 val8 = ADT7420_OP_MODE_1_SPS;
69 break;
70 default:
71 return -EINVAL;
72 }
73
74 if (i2c_reg_update_byte_dt(&cfg->i2c,
75 ADT7420_REG_CONFIG,
76 ADT7420_CONFIG_OP_MODE(~0),
77 ADT7420_CONFIG_OP_MODE(val8)) < 0) {
78 LOG_DBG("Failed to set attribute!");
79 return -EIO;
80 }
81
82 return 0;
83 case SENSOR_ATTR_UPPER_THRESH:
84 reg = ADT7420_REG_T_HIGH_MSB;
85 __fallthrough;
86 case SENSOR_ATTR_LOWER_THRESH:
87 if (!reg) {
88 reg = ADT7420_REG_T_LOW_MSB;
89 }
90
91 if ((val->val1 > 150) || (val->val1 < -40)) {
92 return -EINVAL;
93 }
94
95 value = (int64_t)val->val1 * 1000000 + val->val2;
96 value = (value / ADT7420_TEMP_SCALE) << 1;
97
98 if (adt7420_temp_reg_write(dev, reg, value) < 0) {
99 LOG_DBG("Failed to set attribute!");
100 return -EIO;
101 }
102
103 return 0;
104 default:
105 return -ENOTSUP;
106 }
107
108 return 0;
109 }
110
adt7420_sample_fetch(const struct device * dev,enum sensor_channel chan)111 static int adt7420_sample_fetch(const struct device *dev,
112 enum sensor_channel chan)
113 {
114 struct adt7420_data *drv_data = dev->data;
115 int16_t value;
116
117 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL ||
118 chan == SENSOR_CHAN_AMBIENT_TEMP);
119
120 if (adt7420_temp_reg_read(dev, ADT7420_REG_TEMP_MSB, &value) < 0) {
121 return -EIO;
122 }
123
124 drv_data->sample = value >> 1; /* use 15-bit only */
125
126 return 0;
127 }
128
adt7420_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)129 static int adt7420_channel_get(const struct device *dev,
130 enum sensor_channel chan,
131 struct sensor_value *val)
132 {
133 struct adt7420_data *drv_data = dev->data;
134 int32_t value;
135
136 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
137 return -ENOTSUP;
138 }
139
140 value = (int32_t)drv_data->sample * ADT7420_TEMP_SCALE;
141 val->val1 = value / 1000000;
142 val->val2 = value % 1000000;
143
144 return 0;
145 }
146
147 static const struct sensor_driver_api adt7420_driver_api = {
148 .attr_set = adt7420_attr_set,
149 .sample_fetch = adt7420_sample_fetch,
150 .channel_get = adt7420_channel_get,
151 #ifdef CONFIG_ADT7420_TRIGGER
152 .trigger_set = adt7420_trigger_set,
153 #endif
154 };
155
adt7420_probe(const struct device * dev)156 static int adt7420_probe(const struct device *dev)
157 {
158 const struct adt7420_dev_config *cfg = dev->config;
159 uint8_t value;
160 int ret;
161
162 ret = i2c_reg_read_byte_dt(&cfg->i2c, ADT7420_REG_ID, &value);
163 if (ret) {
164 return ret;
165 }
166
167 if (value != ADT7420_DEFAULT_ID) {
168 return -ENODEV;
169 }
170
171 ret = i2c_reg_write_byte_dt(&cfg->i2c,
172 ADT7420_REG_CONFIG, ADT7420_CONFIG_RESOLUTION |
173 ADT7420_CONFIG_OP_MODE(ADT7420_OP_MODE_CONT_CONV));
174 if (ret) {
175 return ret;
176 }
177
178 ret = i2c_reg_write_byte_dt(&cfg->i2c,
179 ADT7420_REG_HIST, CONFIG_ADT7420_TEMP_HYST);
180 if (ret) {
181 return ret;
182 }
183 ret = adt7420_temp_reg_write(dev, ADT7420_REG_T_CRIT_MSB,
184 (CONFIG_ADT7420_TEMP_CRIT * 1000000 /
185 ADT7420_TEMP_SCALE) << 1);
186 if (ret) {
187 return ret;
188 }
189
190 #ifdef CONFIG_ADT7420_TRIGGER
191 if (cfg->int_gpio.port) {
192 ret = adt7420_init_interrupt(dev);
193 if (ret < 0) {
194 LOG_ERR("Failed to initialize interrupt!");
195 return ret;
196 }
197 }
198 #endif
199
200 return 0;
201 }
202
adt7420_init(const struct device * dev)203 static int adt7420_init(const struct device *dev)
204 {
205 const struct adt7420_dev_config *cfg = dev->config;
206
207 if (!device_is_ready(cfg->i2c.bus)) {
208 LOG_ERR("Bus device is not ready");
209 return -EINVAL;
210 }
211
212 return adt7420_probe(dev);
213 }
214
215 #define ADT7420_DEFINE(inst) \
216 static struct adt7420_data adt7420_data_##inst; \
217 \
218 static const struct adt7420_dev_config adt7420_config_##inst = { \
219 .i2c = I2C_DT_SPEC_INST_GET(inst), \
220 \
221 IF_ENABLED(CONFIG_ADT7420_TRIGGER, \
222 (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, { 0 }),)) \
223 }; \
224 \
225 SENSOR_DEVICE_DT_INST_DEFINE(inst, adt7420_init, NULL, &adt7420_data_##inst, \
226 &adt7420_config_##inst, POST_KERNEL, \
227 CONFIG_SENSOR_INIT_PRIORITY, &adt7420_driver_api); \
228
229 DT_INST_FOREACH_STATUS_OKAY(ADT7420_DEFINE)
230