1 /*
2  * Copyright (c) 2024 Würth Elektronik eiSos GmbH & Co. KG
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT we_wsen_hids_2525020210002
8 
9 #include <stdlib.h>
10 
11 #include <zephyr/sys/__assert.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/logging/log.h>
14 
15 #include "wsen_hids_2525020210002.h"
16 
17 LOG_MODULE_REGISTER(WSEN_HIDS_2525020210002, CONFIG_SENSOR_LOG_LEVEL);
18 
19 static const hids_measureCmd_t precision_cmds[] = {HIDS_MEASURE_LPM, HIDS_MEASURE_MPM,
20 						   HIDS_MEASURE_HPM};
21 
22 static const hids_measureCmd_t heater_cmds[] = {HIDS_HEATER_200_MW_01_S, HIDS_HEATER_200_MW_100_MS,
23 						HIDS_HEATER_110_MW_01_S, HIDS_HEATER_110_MW_100_MS,
24 						HIDS_HEATER_20_MW_01_S,  HIDS_HEATER_20_MW_100_MS};
25 
hids_2525020210002_sample_fetch(const struct device * dev,enum sensor_channel chan)26 static int hids_2525020210002_sample_fetch(const struct device *dev, enum sensor_channel chan)
27 {
28 	struct hids_2525020210002_data *data = dev->data;
29 
30 	hids_measureCmd_t cmd;
31 
32 	int32_t raw_temperature;
33 	int32_t raw_humidity;
34 
35 	switch (chan) {
36 	case SENSOR_CHAN_ALL:
37 	case SENSOR_CHAN_AMBIENT_TEMP:
38 	case SENSOR_CHAN_HUMIDITY:
39 		break;
40 	default:
41 		LOG_ERR("Fetching is not supported on channel %d.", chan);
42 		return -ENOTSUP;
43 	}
44 
45 	if (data->sensor_precision == hids_2525020210002_precision_High &&
46 	    data->sensor_heater != hids_2525020210002_heater_Off) {
47 		cmd = heater_cmds[data->sensor_heater - 1];
48 	} else {
49 		cmd = precision_cmds[data->sensor_precision];
50 	}
51 
52 	if (HIDS_Sensor_Measure_Raw(&data->sensor_interface, cmd, &raw_temperature,
53 				    &raw_humidity) != WE_SUCCESS) {
54 		LOG_ERR("Failed to fetch data sample");
55 		return -EIO;
56 	}
57 
58 	switch (chan) {
59 	case SENSOR_CHAN_ALL:
60 		data->temperature = raw_temperature;
61 		data->humidity = raw_humidity;
62 		break;
63 	case SENSOR_CHAN_AMBIENT_TEMP:
64 		data->temperature = raw_temperature;
65 		break;
66 	case SENSOR_CHAN_HUMIDITY:
67 		data->humidity = raw_humidity;
68 		break;
69 	default:
70 		return -ENOTSUP;
71 	}
72 
73 	return 0;
74 }
75 
hids_2525020210002_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)76 static int hids_2525020210002_channel_get(const struct device *dev, enum sensor_channel chan,
77 					  struct sensor_value *val)
78 {
79 	struct hids_2525020210002_data *data = dev->data;
80 
81 	switch (chan) {
82 	case SENSOR_CHAN_AMBIENT_TEMP:
83 		val->val1 = data->temperature / 1000;
84 		val->val2 = ((int32_t)data->temperature % 1000) * (1000000 / 1000);
85 		break;
86 	case SENSOR_CHAN_HUMIDITY:
87 		val->val1 = data->humidity / 1000;
88 		val->val2 = ((int32_t)data->humidity % 1000) * (1000000 / 1000);
89 		break;
90 	default:
91 		LOG_ERR("Channel not supported %d", chan);
92 		return -ENOTSUP;
93 	}
94 
95 	return 0;
96 }
97 
98 /* Set precision configuration. */
hids_2525020210002_precision_set(const struct device * dev,const struct sensor_value * precision)99 static int hids_2525020210002_precision_set(const struct device *dev,
100 					    const struct sensor_value *precision)
101 {
102 	struct hids_2525020210002_data *data = dev->data;
103 
104 	if (precision->val1 < hids_2525020210002_precision_Low ||
105 	    precision->val1 > hids_2525020210002_precision_High || precision->val2 != 0) {
106 		LOG_ERR("Bad precision configuration %d", precision->val1);
107 		return -EINVAL;
108 	}
109 
110 	data->sensor_precision = (hids_2525020210002_precision_t)precision->val1;
111 
112 	return 0;
113 }
114 
115 /* Set heater option. */
hids_2525020210002_heater_set(const struct device * dev,const struct sensor_value * heater)116 static int hids_2525020210002_heater_set(const struct device *dev,
117 					 const struct sensor_value *heater)
118 {
119 	struct hids_2525020210002_data *data = dev->data;
120 
121 	if (heater->val1 < hids_2525020210002_heater_Off ||
122 	    heater->val1 > hids_2525020210002_heater_On_20mW_100ms || heater->val2 != 0) {
123 		LOG_ERR("Bad heater option %d", heater->val1);
124 		return -EINVAL;
125 	}
126 
127 	data->sensor_heater = (hids_2525020210002_heater_t)heater->val1;
128 
129 	return 0;
130 }
131 
hids_2525020210002_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)132 static int hids_2525020210002_attr_set(const struct device *dev, enum sensor_channel chan,
133 				       enum sensor_attribute attr, const struct sensor_value *val)
134 {
135 
136 	if (chan != SENSOR_CHAN_ALL) {
137 		LOG_WRN("attr_set() is not supported on channel %d.", chan);
138 		return -ENOTSUP;
139 	}
140 
141 	switch ((int)attr) {
142 	case SENSOR_ATTR_WSEN_HIDS_2525020210002_PRECISION:
143 		return hids_2525020210002_precision_set(dev, val);
144 	case SENSOR_ATTR_WSEN_HIDS_2525020210002_HEATER:
145 		return hids_2525020210002_heater_set(dev, val);
146 	default:
147 		LOG_ERR("Operation not supported.");
148 		return -ENOTSUP;
149 	}
150 
151 	return 0;
152 }
153 
hids_2525020210002_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)154 static int hids_2525020210002_attr_get(const struct device *dev, enum sensor_channel chan,
155 				       enum sensor_attribute attr, struct sensor_value *val)
156 {
157 	struct hids_2525020210002_data *data = dev->data;
158 
159 	if (chan != SENSOR_CHAN_ALL) {
160 		LOG_WRN("attr_get() is not supported on channel %d.", chan);
161 		return -ENOTSUP;
162 	}
163 
164 	if (val == NULL) {
165 		LOG_WRN("address of passed value is NULL.");
166 		return -EFAULT;
167 	}
168 
169 	switch ((int)attr) {
170 	case SENSOR_ATTR_WSEN_HIDS_2525020210002_PRECISION:
171 		val->val1 = data->sensor_precision;
172 		val->val2 = 0;
173 		break;
174 	case SENSOR_ATTR_WSEN_HIDS_2525020210002_HEATER:
175 		val->val1 = data->sensor_heater;
176 		val->val2 = 0;
177 		break;
178 	default:
179 		LOG_ERR("Operation not supported.");
180 		return -ENOTSUP;
181 	}
182 
183 	return 0;
184 }
185 
186 static DEVICE_API(sensor, hids_2525020210002_driver_api) = {
187 	.attr_set = hids_2525020210002_attr_set,
188 	.attr_get = hids_2525020210002_attr_get,
189 	.sample_fetch = hids_2525020210002_sample_fetch,
190 	.channel_get = hids_2525020210002_channel_get,
191 };
192 
hids_2525020210002_init(const struct device * dev)193 static int hids_2525020210002_init(const struct device *dev)
194 {
195 	const struct hids_2525020210002_config *const config = dev->config;
196 	struct hids_2525020210002_data *data = dev->data;
197 	struct sensor_value precision, heater;
198 
199 	/* Initialize WE sensor interface */
200 	HIDS_Get_Default_Interface(&data->sensor_interface);
201 	data->sensor_interface.interfaceType = WE_i2c;
202 	if (!i2c_is_ready_dt(&config->bus_cfg.i2c)) {
203 		LOG_ERR("I2C bus device not ready");
204 		return -ENODEV;
205 	}
206 	data->sensor_interface.handle = (void *)&config->bus_cfg.i2c;
207 
208 	/* First communication test - check device ID */
209 	if (HIDS_Sensor_Init(&data->sensor_interface) != WE_SUCCESS) {
210 		LOG_ERR("Failed to read device ID.");
211 		return -EIO;
212 	}
213 
214 	precision.val1 = config->precision;
215 	precision.val2 = 0;
216 
217 	if (hids_2525020210002_precision_set(dev, &precision) < 0) {
218 		LOG_ERR("Failed to set precision configuration.");
219 		return -EIO;
220 	}
221 
222 	heater.val1 = config->heater;
223 	heater.val2 = 0;
224 
225 	if (hids_2525020210002_heater_set(dev, &heater) < 0) {
226 		LOG_ERR("Failed to set heater option.");
227 		return -EIO;
228 	}
229 
230 	return 0;
231 }
232 
233 /*
234  * Main instantiation macro.
235  */
236 #define HIDS_2525020210002_DEFINE(inst)                                                            \
237 	static struct hids_2525020210002_data hids_2525020210002_data_##inst;                      \
238 	static const struct hids_2525020210002_config hids_2525020210002_config_##inst = {         \
239 		.bus_cfg = {.i2c = I2C_DT_SPEC_INST_GET(inst)},                                    \
240 		.precision = (hids_2525020210002_precision_t)(DT_INST_ENUM_IDX(inst, precision)),  \
241 		.heater = (hids_2525020210002_heater_t)(DT_INST_ENUM_IDX(inst, heater)),           \
242 	};                                                                                         \
243 	SENSOR_DEVICE_DT_INST_DEFINE(inst, hids_2525020210002_init, NULL,                          \
244 				     &hids_2525020210002_data_##inst,                              \
245 				     &hids_2525020210002_config_##inst, POST_KERNEL,               \
246 				     CONFIG_SENSOR_INIT_PRIORITY, &hids_2525020210002_driver_api);
247 
248 DT_INST_FOREACH_STATUS_OKAY(HIDS_2525020210002_DEFINE)
249