1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT st_hts221
8
9 #include <zephyr/drivers/i2c.h>
10 #include <zephyr/init.h>
11 #include <zephyr/sys/__assert.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <string.h>
14 #include <zephyr/logging/log.h>
15
16 #include "hts221.h"
17
18 LOG_MODULE_REGISTER(HTS221, CONFIG_SENSOR_LOG_LEVEL);
19
20 struct str2odr {
21 const char *str;
22 hts221_odr_t odr;
23 };
24
25 static const struct str2odr hts221_odrs[] = {
26 { "1", HTS221_ODR_1Hz },
27 { "7", HTS221_ODR_7Hz },
28 { "12.5", HTS221_ODR_12Hz5 },
29 };
30
hts221_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)31 static int hts221_channel_get(const struct device *dev,
32 enum sensor_channel chan,
33 struct sensor_value *val)
34 {
35 struct hts221_data *data = dev->data;
36 int32_t conv_val;
37
38 /*
39 * see "Interpreting humidity and temperature readings" document
40 * for more details
41 */
42 if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
43 conv_val = (int32_t)(data->t1_degc_x8 - data->t0_degc_x8) *
44 (data->t_sample - data->t0_out) /
45 (data->t1_out - data->t0_out) +
46 data->t0_degc_x8;
47
48 /* convert temperature x8 to degrees Celsius */
49 val->val1 = conv_val / 8;
50 val->val2 = (conv_val % 8) * (1000000 / 8);
51 } else if (chan == SENSOR_CHAN_HUMIDITY) {
52 conv_val = (int32_t)(data->h1_rh_x2 - data->h0_rh_x2) *
53 (data->rh_sample - data->h0_t0_out) /
54 (data->h1_t0_out - data->h0_t0_out) +
55 data->h0_rh_x2;
56
57 /* convert humidity x2 to percent */
58 val->val1 = conv_val / 2;
59 val->val2 = (conv_val % 2) * 500000;
60 } else {
61 return -ENOTSUP;
62 }
63
64 return 0;
65 }
66
hts221_sample_fetch(const struct device * dev,enum sensor_channel chan)67 static int hts221_sample_fetch(const struct device *dev,
68 enum sensor_channel chan)
69 {
70 struct hts221_data *data = dev->data;
71 const struct hts221_config *cfg = dev->config;
72 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
73 uint8_t buf[4];
74 int status;
75
76 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
77
78 status = hts221_read_reg(ctx, HTS221_HUMIDITY_OUT_L |
79 HTS221_AUTOINCREMENT_ADDR, buf, 4);
80 if (status < 0) {
81 LOG_ERR("Failed to fetch data sample.");
82 return status;
83 }
84
85 data->rh_sample = sys_le16_to_cpu(buf[0] | (buf[1] << 8));
86 data->t_sample = sys_le16_to_cpu(buf[2] | (buf[3] << 8));
87
88 return 0;
89 }
90
hts221_read_conversion_data(const struct device * dev)91 static int hts221_read_conversion_data(const struct device *dev)
92 {
93 struct hts221_data *data = dev->data;
94 const struct hts221_config *cfg = dev->config;
95 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
96 uint8_t buf[16];
97 int status;
98
99 status = hts221_read_reg(ctx, HTS221_H0_RH_X2 |
100 HTS221_AUTOINCREMENT_ADDR, buf, 16);
101 if (status < 0) {
102 LOG_ERR("Failed to read conversion data.");
103 return status;
104 }
105
106 data->h0_rh_x2 = buf[0];
107 data->h1_rh_x2 = buf[1];
108 data->t0_degc_x8 = sys_le16_to_cpu(buf[2] | ((buf[5] & 0x3) << 8));
109 data->t1_degc_x8 = sys_le16_to_cpu(buf[3] | ((buf[5] & 0xC) << 6));
110 data->h0_t0_out = sys_le16_to_cpu(buf[6] | (buf[7] << 8));
111 data->h1_t0_out = sys_le16_to_cpu(buf[10] | (buf[11] << 8));
112 data->t0_out = sys_le16_to_cpu(buf[12] | (buf[13] << 8));
113 data->t1_out = sys_le16_to_cpu(buf[14] | (buf[15] << 8));
114
115 return 0;
116 }
117
118 static const struct sensor_driver_api hts221_driver_api = {
119 #ifdef CONFIG_HTS221_TRIGGER
120 .trigger_set = hts221_trigger_set,
121 #endif
122 .sample_fetch = hts221_sample_fetch,
123 .channel_get = hts221_channel_get,
124 };
125
hts221_init(const struct device * dev)126 int hts221_init(const struct device *dev)
127 {
128 const struct hts221_config *cfg = dev->config;
129 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
130 uint8_t id, idx;
131 int status;
132
133 /* check chip ID */
134
135 status = hts221_device_id_get(ctx, &id);
136 if (status < 0) {
137 LOG_ERR("Failed to read chip ID.");
138 return status;
139 }
140
141 if (id != HTS221_ID) {
142 LOG_ERR("Invalid chip ID.");
143 return -EINVAL;
144 }
145
146 /* check if CONFIG_HTS221_ODR is valid */
147 for (idx = 0U; idx < ARRAY_SIZE(hts221_odrs); idx++) {
148 if (!strcmp(hts221_odrs[idx].str, CONFIG_HTS221_ODR)) {
149 break;
150 }
151 }
152
153 if (idx == ARRAY_SIZE(hts221_odrs)) {
154 LOG_ERR("Invalid ODR value %s.", CONFIG_HTS221_ODR);
155 return -EINVAL;
156 }
157
158 status = hts221_data_rate_set(ctx, hts221_odrs[idx].odr);
159 if (status < 0) {
160 LOG_ERR("Could not set output data rate");
161 return status;
162 }
163
164 status = hts221_block_data_update_set(ctx, 1);
165 if (status < 0) {
166 LOG_ERR("Could not set BDU bit");
167 return status;
168 }
169
170 status = hts221_power_on_set(ctx, 1);
171 if (status < 0) {
172 LOG_ERR("Could not set PD bit");
173 return status;
174 }
175
176 /*
177 * the device requires about 2.2 ms to download the flash content
178 * into the volatile mem
179 */
180 k_sleep(K_MSEC(3));
181
182 status = hts221_read_conversion_data(dev);
183 if (status < 0) {
184 LOG_ERR("Failed to read conversion data.");
185 return status;
186 }
187
188 #ifdef CONFIG_HTS221_TRIGGER
189 status = hts221_init_interrupt(dev);
190 if (status < 0) {
191 LOG_ERR("Failed to initialize interrupt.");
192 return status;
193 }
194 #else
195 LOG_INF("Cannot enable trigger without drdy-gpios");
196 #endif
197
198 return 0;
199 }
200
201 #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
202 #warning "HTS221 driver enabled without any devices"
203 #endif
204
205 /*
206 * Device creation macros
207 */
208
209 #define HTS221_DEVICE_INIT(inst) \
210 SENSOR_DEVICE_DT_INST_DEFINE(inst, \
211 hts221_init, \
212 NULL, \
213 &hts221_data_##inst, \
214 &hts221_config_##inst, \
215 POST_KERNEL, \
216 CONFIG_SENSOR_INIT_PRIORITY, \
217 &hts221_driver_api);
218
219 /*
220 * Instantiation macros used when a device is on a SPI bus.
221 */
222
223 #ifdef CONFIG_HTS221_TRIGGER
224 #define HTS221_CFG_IRQ(inst) \
225 .gpio_drdy = GPIO_DT_SPEC_INST_GET(inst, drdy_gpios)
226 #else
227 #define HTS221_CFG_IRQ(inst)
228 #endif /* CONFIG_HTS221_TRIGGER */
229
230 #define HTS221_CONFIG_COMMON(inst) \
231 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, drdy_gpios), \
232 (HTS221_CFG_IRQ(inst)), ())
233
234 #define HTS221_SPI_OPERATION (SPI_WORD_SET(8) | \
235 SPI_OP_MODE_MASTER | \
236 SPI_MODE_CPOL | \
237 SPI_MODE_CPHA | \
238 SPI_HALF_DUPLEX) \
239
240 #define HTS221_CONFIG_SPI(inst) \
241 { \
242 STMEMSC_CTX_SPI(&hts221_config_##inst.stmemsc_cfg), \
243 .stmemsc_cfg = { \
244 .spi = SPI_DT_SPEC_INST_GET(inst, \
245 HTS221_SPI_OPERATION, \
246 0), \
247 }, \
248 HTS221_CONFIG_COMMON(inst) \
249 }
250
251 /*
252 * Instantiation macros used when a device is on an I2C bus.
253 */
254
255 #define HTS221_CONFIG_I2C(inst) \
256 { \
257 STMEMSC_CTX_I2C(&hts221_config_##inst.stmemsc_cfg), \
258 .stmemsc_cfg = { \
259 .i2c = I2C_DT_SPEC_INST_GET(inst), \
260 }, \
261 HTS221_CONFIG_COMMON(inst) \
262 }
263
264 /*
265 * Main instantiation macro. Use of COND_CODE_1() selects the right
266 * bus-specific macro at preprocessor time.
267 */
268
269 #define HTS221_DEFINE(inst) \
270 static struct hts221_data hts221_data_##inst; \
271 static const struct hts221_config hts221_config_##inst = \
272 COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
273 (HTS221_CONFIG_SPI(inst)), \
274 (HTS221_CONFIG_I2C(inst))); \
275 HTS221_DEVICE_INIT(inst)
276
277 DT_INST_FOREACH_STATUS_OKAY(HTS221_DEFINE)
278