1 /* ST Microelectronics STTS22H temperature sensor
2 *
3 * Copyright (c) 2024 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/stts22h.pdf
9 */
10
11 #define DT_DRV_COMPAT st_stts22h
12
13 #include <zephyr/drivers/sensor.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/device.h>
16 #include <zephyr/init.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <zephyr/sys/__assert.h>
19 #include <zephyr/logging/log.h>
20
21 #include "stts22h.h"
22
23 LOG_MODULE_REGISTER(STTS22H, CONFIG_SENSOR_LOG_LEVEL);
24
25 #define ST22H_RANGE_LOWEST_TEMP -40
26 #define ST22H_RANGE_HIGHEST_TEMP 127
27
stts22h_set_odr_raw(const struct device * dev,stts22h_odr_temp_t odr)28 static inline int stts22h_set_odr_raw(const struct device *dev, stts22h_odr_temp_t odr)
29 {
30 const struct stts22h_config *cfg = dev->config;
31 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
32
33 return stts22h_temp_data_rate_set(ctx, odr);
34 }
35
stts22h_sample_fetch(const struct device * dev,enum sensor_channel chan)36 static int stts22h_sample_fetch(const struct device *dev, enum sensor_channel chan)
37 {
38 struct stts22h_data *data = dev->data;
39 const struct stts22h_config *cfg = dev->config;
40 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
41 int16_t raw_temp;
42
43 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
44 LOG_ERR("Invalid channel: %d", chan);
45 return -ENOTSUP;
46 }
47
48 if (stts22h_temperature_raw_get(ctx, &raw_temp) < 0) {
49 LOG_ERR("Failed to read sample");
50 return -EIO;
51 }
52
53 data->sample_temp = raw_temp;
54
55 return 0;
56 }
57
stts22h_temp_convert(struct sensor_value * val,int16_t raw_val)58 static inline void stts22h_temp_convert(struct sensor_value *val, int16_t raw_val)
59 {
60 val->val1 = raw_val / 100;
61 val->val2 = ((int32_t)raw_val % 100) * 10000;
62 }
63
stts22h_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)64 static int stts22h_channel_get(const struct device *dev,
65 enum sensor_channel chan,
66 struct sensor_value *val)
67 {
68 struct stts22h_data *data = dev->data;
69
70 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
71 LOG_ERR("Invalid channel: %d", chan);
72 return -ENOTSUP;
73 }
74
75 stts22h_temp_convert(val, data->sample_temp);
76
77 return 0;
78 }
79
80 static const uint8_t stts22h_map[6] = {0, 1, 25, 50, 100, 200};
81
stts22h_odr_set(const struct device * dev,const struct sensor_value * val)82 static int stts22h_odr_set(const struct device *dev,
83 const struct sensor_value *val)
84 {
85 int odr;
86
87 for (odr = 0; odr < ARRAY_SIZE(stts22h_map); odr++) {
88 if (val->val1 <= stts22h_map[odr]) {
89 break;
90 }
91 }
92
93 switch (odr) {
94 case 0:
95 return stts22h_set_odr_raw(dev, STTS22H_POWER_DOWN);
96 case 1:
97 return stts22h_set_odr_raw(dev, STTS22H_1Hz);
98 case 2:
99 return stts22h_set_odr_raw(dev, STTS22H_25Hz);
100 case 3:
101 return stts22h_set_odr_raw(dev, STTS22H_50Hz);
102 case 4:
103 return stts22h_set_odr_raw(dev, STTS22H_100Hz);
104 case 5:
105 return stts22h_set_odr_raw(dev, STTS22H_200Hz);
106 default:
107 LOG_ERR("bad frequency: %d (odr = %d)", val->val1, odr);
108 return -EINVAL;
109 }
110 }
111 #if CONFIG_STTS22H_TRIGGER
stts22h_val_to_threshold(const struct sensor_value * val)112 static inline uint32_t stts22h_val_to_threshold(const struct sensor_value *val)
113 {
114 if (val->val1 < ST22H_RANGE_LOWEST_TEMP || val->val1 > ST22H_RANGE_HIGHEST_TEMP) {
115 LOG_ERR("Invalid value: %d", val->val1);
116 return UINT32_MAX;
117 }
118 /* The conversion formula is: (degC / 0.64) + 63, we multiply by 100*/
119 int32_t temperature_degree_times100 = val->val1 * 100 + val->val2 / 10000;
120 uint32_t raw_value = (temperature_degree_times100 / 64) + 63;
121
122 if (raw_value > 0xFF) {
123 LOG_ERR("Invalid value: %d", raw_value);
124 return UINT32_MAX;
125 }
126
127 return raw_value;
128 }
129 #endif
130
131
stts22h_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)132 static int stts22h_attr_set(const struct device *dev,
133 enum sensor_channel chan,
134 enum sensor_attribute attr,
135 const struct sensor_value *val)
136 {
137 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
138 LOG_ERR("Invalid channel: %d", chan);
139 return -ENOTSUP;
140 }
141 switch (attr) {
142 case SENSOR_ATTR_SAMPLING_FREQUENCY:
143 return stts22h_odr_set(dev, val);
144 #if CONFIG_STTS22H_TRIGGER
145 case SENSOR_ATTR_UPPER_THRESH: {
146 const struct stts22h_config *cfg = dev->config;
147 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
148
149 uint32_t raw_value = stts22h_val_to_threshold(val);
150
151 if (raw_value == UINT32_MAX) {
152 return -EINVAL;
153 }
154 if (stts22h_temp_trshld_high_set(ctx, (uint8_t)raw_value) < 0) {
155 LOG_DBG("Could not set high threshold");
156 return -EIO;
157 }
158 return 0;
159 }
160 case SENSOR_ATTR_LOWER_THRESH: {
161 const struct stts22h_config *cfg = dev->config;
162 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
163
164 uint32_t raw_value = stts22h_val_to_threshold(val);
165
166 if (raw_value == UINT32_MAX) {
167 return -EINVAL;
168 }
169 if (stts22h_temp_trshld_low_set(ctx, (uint8_t)raw_value) < 0) {
170 LOG_DBG("Could not set low threshold ");
171 return -EIO;
172 }
173 return 0;
174 }
175 #endif
176 default:
177 LOG_ERR("Attribute %d not supported.", attr);
178 return -ENOTSUP;
179 }
180
181 return 0;
182 }
183
184 static DEVICE_API(sensor, stts22h_api_funcs) = {
185 .attr_set = stts22h_attr_set,
186 .sample_fetch = stts22h_sample_fetch,
187 .channel_get = stts22h_channel_get,
188 #if CONFIG_STTS22H_TRIGGER
189 .trigger_set = stts22h_trigger_set,
190 #endif
191 };
192
stts22h_init_chip(const struct device * dev)193 static int stts22h_init_chip(const struct device *dev)
194 {
195 const struct stts22h_config *cfg = dev->config;
196 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
197 uint8_t chip_id, odr;
198
199 if (stts22h_dev_id_get(ctx, &chip_id) < 0) {
200 LOG_ERR("Failed reading chip id");
201 return -EIO;
202 }
203
204 LOG_INF("chip id 0x%02x", chip_id);
205
206 if (stts22h_auto_increment_set(ctx, 1) < 0) {
207 LOG_ERR("Failed to set autoincr");
208 return -EIO;
209 }
210
211 /* set odr from DT */
212 odr = cfg->odr;
213 LOG_INF("sensor odr is %d", odr);
214 if (stts22h_set_odr_raw(dev, odr) < 0) {
215 LOG_ERR("Failed to set sampling rate");
216 return -EIO;
217 }
218
219 return 0;
220 }
221
stts22h_init(const struct device * dev)222 static int stts22h_init(const struct device *dev)
223 {
224 struct stts22h_data *data = dev->data;
225 #ifdef CONFIG_STTS22H_TRIGGER
226 const struct stts22h_config *cfg = dev->config;
227 #endif
228
229 LOG_INF("Initialize device %s", dev->name);
230 data->dev = dev;
231
232 if (stts22h_init_chip(dev) < 0) {
233 LOG_ERR("Failed to initialize chip");
234 return -EIO;
235 }
236
237 #ifdef CONFIG_STTS22H_TRIGGER
238 if (cfg->int_gpio.port) {
239 if (stts22h_init_interrupt(dev) < 0) {
240 LOG_ERR("Failed to initialize interrupt.");
241 return -EIO;
242 }
243 }
244 #endif
245
246 return 0;
247 }
248
249 #define STTS22H_DEFINE(inst) \
250 static struct stts22h_data stts22h_data_##inst; \
251 \
252 static const struct stts22h_config stts22h_config_##inst = { \
253 STMEMSC_CTX_I2C(&stts22h_config_##inst.i2c), \
254 .i2c = I2C_DT_SPEC_INST_GET(inst), \
255 .temp_hi = DT_INST_PROP(inst, temperature_hi_threshold), \
256 .temp_lo = DT_INST_PROP(inst, temperature_lo_threshold), \
257 .odr = DT_INST_PROP(inst, sampling_rate), \
258 IF_ENABLED(CONFIG_STTS22H_TRIGGER, \
259 (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, { 0 }),)) \
260 }; \
261 \
262 SENSOR_DEVICE_DT_INST_DEFINE(inst, stts22h_init, NULL, \
263 &stts22h_data_##inst, &stts22h_config_##inst, POST_KERNEL, \
264 CONFIG_SENSOR_INIT_PRIORITY, &stts22h_api_funcs); \
265
266 DT_INST_FOREACH_STATUS_OKAY(STTS22H_DEFINE)
267