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