1 /* ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
2  *
3  * Copyright (c) 2020 STMicroelectronics
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Datasheet:
8  * https://www.st.com/resource/en/datasheet/iis2iclx.pdf
9  */
10 
11 #define DT_DRV_COMPAT st_iis2iclx
12 
13 #include <drivers/sensor.h>
14 #include <kernel.h>
15 #include <device.h>
16 #include <init.h>
17 #include <string.h>
18 #include <sys/byteorder.h>
19 #include <sys/__assert.h>
20 #include <logging/log.h>
21 
22 #include "iis2iclx.h"
23 
24 LOG_MODULE_REGISTER(IIS2ICLX, CONFIG_SENSOR_LOG_LEVEL);
25 
26 static const uint16_t iis2iclx_odr_map[] = {0, 12, 26, 52, 104, 208, 416, 833,
27 					1660, 3330, 6660};
28 
iis2iclx_freq_to_odr_val(uint16_t freq)29 static int iis2iclx_freq_to_odr_val(uint16_t freq)
30 {
31 	size_t i;
32 
33 	for (i = 0; i < ARRAY_SIZE(iis2iclx_odr_map); i++) {
34 		if (freq == iis2iclx_odr_map[i]) {
35 			return i;
36 		}
37 	}
38 
39 	return -EINVAL;
40 }
41 
iis2iclx_odr_to_freq_val(uint16_t odr)42 static int iis2iclx_odr_to_freq_val(uint16_t odr)
43 {
44 	/* for valid index, return value from map */
45 	if (odr < ARRAY_SIZE(iis2iclx_odr_map)) {
46 		return iis2iclx_odr_map[odr];
47 	}
48 
49 	/* invalid index, return last entry */
50 	return iis2iclx_odr_map[ARRAY_SIZE(iis2iclx_odr_map) - 1];
51 }
52 
53 static const uint16_t iis2iclx_accel_fs_map[] = {500, 3000, 1000, 2000};
54 static const uint16_t iis2iclx_accel_fs_sens[] = {1, 8, 2, 4};
55 
iis2iclx_accel_range_to_fs_val(int32_t range)56 static int iis2iclx_accel_range_to_fs_val(int32_t range)
57 {
58 	size_t i;
59 
60 	for (i = 0; i < ARRAY_SIZE(iis2iclx_accel_fs_map); i++) {
61 		if (range == iis2iclx_accel_fs_map[i]) {
62 			return i;
63 		}
64 	}
65 
66 	return -EINVAL;
67 }
68 
iis2iclx_reboot(const struct device * dev)69 static inline int iis2iclx_reboot(const struct device *dev)
70 {
71 	const struct iis2iclx_config *cfg = dev->config;
72 
73 	if (iis2iclx_boot_set((stmdev_ctx_t *)&cfg->ctx, 1) < 0) {
74 		return -EIO;
75 	}
76 
77 	/* Wait sensor turn-on time as per datasheet */
78 	k_msleep(35);
79 
80 	return 0;
81 }
82 
iis2iclx_accel_set_fs_raw(const struct device * dev,uint8_t fs)83 static int iis2iclx_accel_set_fs_raw(const struct device *dev, uint8_t fs)
84 {
85 	const struct iis2iclx_config *cfg = dev->config;
86 	struct iis2iclx_data *data = dev->data;
87 
88 	if (iis2iclx_xl_full_scale_set((stmdev_ctx_t *)&cfg->ctx, fs) < 0) {
89 		return -EIO;
90 	}
91 
92 	data->accel_fs = fs;
93 
94 	return 0;
95 }
96 
iis2iclx_accel_set_odr_raw(const struct device * dev,uint8_t odr)97 static int iis2iclx_accel_set_odr_raw(const struct device *dev, uint8_t odr)
98 {
99 	const struct iis2iclx_config *cfg = dev->config;
100 	struct iis2iclx_data *data = dev->data;
101 
102 	if (iis2iclx_xl_data_rate_set((stmdev_ctx_t *)&cfg->ctx, odr) < 0) {
103 		return -EIO;
104 	}
105 
106 	data->accel_freq = iis2iclx_odr_to_freq_val(odr);
107 
108 	return 0;
109 }
110 
iis2iclx_accel_odr_set(const struct device * dev,uint16_t freq)111 static int iis2iclx_accel_odr_set(const struct device *dev, uint16_t freq)
112 {
113 	int odr;
114 
115 	odr = iis2iclx_freq_to_odr_val(freq);
116 	if (odr < 0) {
117 		return odr;
118 	}
119 
120 	if (iis2iclx_accel_set_odr_raw(dev, odr) < 0) {
121 		LOG_ERR("failed to set accelerometer sampling rate");
122 		return -EIO;
123 	}
124 
125 	return 0;
126 }
127 
iis2iclx_accel_range_set(const struct device * dev,int32_t range)128 static int iis2iclx_accel_range_set(const struct device *dev, int32_t range)
129 {
130 	int fs;
131 	struct iis2iclx_data *data = dev->data;
132 
133 	fs = iis2iclx_accel_range_to_fs_val(range);
134 	if (fs < 0) {
135 		return fs;
136 	}
137 
138 	if (iis2iclx_accel_set_fs_raw(dev, fs) < 0) {
139 		LOG_ERR("failed to set accelerometer full-scale");
140 		return -EIO;
141 	}
142 
143 	data->acc_gain = (iis2iclx_accel_fs_sens[fs] * GAIN_UNIT_XL);
144 	return 0;
145 }
146 
iis2iclx_accel_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)147 static int iis2iclx_accel_config(const struct device *dev,
148 				   enum sensor_channel chan,
149 				   enum sensor_attribute attr,
150 				   const struct sensor_value *val)
151 {
152 	switch (attr) {
153 	case SENSOR_ATTR_FULL_SCALE:
154 		return iis2iclx_accel_range_set(dev, sensor_ms2_to_g(val));
155 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
156 		return iis2iclx_accel_odr_set(dev, val->val1);
157 	default:
158 		LOG_ERR("Accel attribute not supported.");
159 		return -ENOTSUP;
160 	}
161 
162 	return 0;
163 }
164 
iis2iclx_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)165 static int iis2iclx_attr_set(const struct device *dev,
166 			       enum sensor_channel chan,
167 			       enum sensor_attribute attr,
168 			       const struct sensor_value *val)
169 {
170 #if defined(CONFIG_IIS2ICLX_SENSORHUB)
171 	struct iis2iclx_data *data = dev->data;
172 #endif /* CONFIG_IIS2ICLX_SENSORHUB */
173 
174 	switch (chan) {
175 	case SENSOR_CHAN_ACCEL_XYZ:
176 		return iis2iclx_accel_config(dev, chan, attr, val);
177 #if defined(CONFIG_IIS2ICLX_SENSORHUB)
178 	case SENSOR_CHAN_MAGN_XYZ:
179 	case SENSOR_CHAN_PRESS:
180 	case SENSOR_CHAN_HUMIDITY:
181 		if (!data->shub_inited) {
182 			LOG_ERR("shub not inited.");
183 			return -ENOTSUP;
184 		}
185 
186 		return iis2iclx_shub_config(dev, chan, attr, val);
187 #endif /* CONFIG_IIS2ICLX_SENSORHUB */
188 	default:
189 		LOG_ERR("attr_set() not supported on this channel.");
190 		return -ENOTSUP;
191 	}
192 
193 	return 0;
194 }
195 
iis2iclx_sample_fetch_accel(const struct device * dev)196 static int iis2iclx_sample_fetch_accel(const struct device *dev)
197 {
198 	const struct iis2iclx_config *cfg = dev->config;
199 	struct iis2iclx_data *data = dev->data;
200 	int16_t buf[2];
201 
202 	if (iis2iclx_acceleration_raw_get((stmdev_ctx_t *)&cfg->ctx, buf) < 0) {
203 		LOG_ERR("Failed to read sample");
204 		return -EIO;
205 	}
206 
207 	data->acc[0] = sys_le16_to_cpu(buf[0]);
208 	data->acc[1] = sys_le16_to_cpu(buf[1]);
209 
210 	return 0;
211 }
212 
213 #if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
iis2iclx_sample_fetch_temp(const struct device * dev)214 static int iis2iclx_sample_fetch_temp(const struct device *dev)
215 {
216 	struct iis2iclx_data *data = dev->data;
217 	int16_t buf;
218 
219 	if (iis2iclx_temperature_raw_get(&data->ctx, &buf) < 0) {
220 		LOG_ERR("Failed to read sample");
221 		return -EIO;
222 	}
223 
224 	data->temp_sample = sys_le16_to_cpu(buf);
225 
226 	return 0;
227 }
228 #endif
229 
230 #if defined(CONFIG_IIS2ICLX_SENSORHUB)
iis2iclx_sample_fetch_shub(const struct device * dev)231 static int iis2iclx_sample_fetch_shub(const struct device *dev)
232 {
233 	if (iis2iclx_shub_fetch_external_devs(dev) < 0) {
234 		LOG_ERR("failed to read ext shub devices");
235 		return -EIO;
236 	}
237 
238 	return 0;
239 }
240 #endif /* CONFIG_IIS2ICLX_SENSORHUB */
241 
iis2iclx_sample_fetch(const struct device * dev,enum sensor_channel chan)242 static int iis2iclx_sample_fetch(const struct device *dev,
243 				   enum sensor_channel chan)
244 {
245 #if defined(CONFIG_IIS2ICLX_SENSORHUB)
246 	struct iis2iclx_data *data = dev->data;
247 #endif /* CONFIG_IIS2ICLX_SENSORHUB */
248 
249 	switch (chan) {
250 	case SENSOR_CHAN_ACCEL_XYZ:
251 		iis2iclx_sample_fetch_accel(dev);
252 		break;
253 #if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
254 	case SENSOR_CHAN_DIE_TEMP:
255 		iis2iclx_sample_fetch_temp(dev);
256 		break;
257 #endif
258 	case SENSOR_CHAN_ALL:
259 		iis2iclx_sample_fetch_accel(dev);
260 #if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
261 		iis2iclx_sample_fetch_temp(dev);
262 #endif
263 #if defined(CONFIG_IIS2ICLX_SENSORHUB)
264 		if (data->shub_inited) {
265 			iis2iclx_sample_fetch_shub(dev);
266 		}
267 #endif
268 		break;
269 	default:
270 		return -ENOTSUP;
271 	}
272 
273 	return 0;
274 }
275 
iis2iclx_accel_convert(struct sensor_value * val,int raw_val,uint32_t sensitivity)276 static inline void iis2iclx_accel_convert(struct sensor_value *val, int raw_val,
277 					    uint32_t sensitivity)
278 {
279 	int64_t dval;
280 
281 	/* Sensitivity is exposed in ug/LSB */
282 	/* Convert to m/s^2 */
283 	dval = (int64_t)(raw_val) * sensitivity * SENSOR_G_DOUBLE;
284 	val->val1 = (int32_t)(dval / 1000000);
285 	val->val2 = (int32_t)(dval % 1000000);
286 
287 }
288 
iis2iclx_accel_get_channel(enum sensor_channel chan,struct sensor_value * val,struct iis2iclx_data * data,uint32_t sensitivity)289 static inline int iis2iclx_accel_get_channel(enum sensor_channel chan,
290 					       struct sensor_value *val,
291 					       struct iis2iclx_data *data,
292 					       uint32_t sensitivity)
293 {
294 	uint8_t i;
295 
296 	switch (chan) {
297 	case SENSOR_CHAN_ACCEL_X:
298 		iis2iclx_accel_convert(val, data->acc[0], sensitivity);
299 		break;
300 	case SENSOR_CHAN_ACCEL_Y:
301 		iis2iclx_accel_convert(val, data->acc[1], sensitivity);
302 		break;
303 	case SENSOR_CHAN_ACCEL_XYZ:
304 		for (i = 0; i < 2; i++) {
305 			iis2iclx_accel_convert(val++, data->acc[i], sensitivity);
306 		}
307 		break;
308 	default:
309 		return -ENOTSUP;
310 	}
311 
312 	return 0;
313 }
314 
iis2iclx_accel_channel_get(enum sensor_channel chan,struct sensor_value * val,struct iis2iclx_data * data)315 static int iis2iclx_accel_channel_get(enum sensor_channel chan,
316 					struct sensor_value *val,
317 					struct iis2iclx_data *data)
318 {
319 	return iis2iclx_accel_get_channel(chan, val, data, data->acc_gain);
320 }
321 
322 #if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
iis2iclx_temp_channel_get(struct sensor_value * val,struct iis2iclx_data * data)323 static void iis2iclx_temp_channel_get(struct sensor_value *val,
324 					  struct iis2iclx_data *data)
325 {
326 	/* val = temp_sample / 256 + 25 */
327 	val->val1 = data->temp_sample / 256 + 25;
328 	val->val2 = (data->temp_sample % 256) * (1000000 / 256);
329 }
330 #endif
331 
332 #if defined(CONFIG_IIS2ICLX_SENSORHUB)
iis2iclx_magn_convert(struct sensor_value * val,int raw_val,uint16_t sensitivity)333 static inline void iis2iclx_magn_convert(struct sensor_value *val, int raw_val,
334 					   uint16_t sensitivity)
335 {
336 	double dval;
337 
338 	/* Sensitivity is exposed in mgauss/LSB */
339 	dval = (double)(raw_val * sensitivity);
340 	val->val1 = (int32_t)dval / 1000000;
341 	val->val2 = (int32_t)dval % 1000000;
342 }
343 
iis2iclx_magn_get_channel(enum sensor_channel chan,struct sensor_value * val,struct iis2iclx_data * data)344 static inline int iis2iclx_magn_get_channel(enum sensor_channel chan,
345 					      struct sensor_value *val,
346 					      struct iis2iclx_data *data)
347 {
348 	int16_t sample[3];
349 	int idx;
350 
351 	idx = iis2iclx_shub_get_idx(data->dev, SENSOR_CHAN_MAGN_XYZ);
352 	if (idx < 0) {
353 		LOG_ERR("external magn not supported");
354 		return -ENOTSUP;
355 	}
356 
357 
358 	sample[0] = (int16_t)(data->ext_data[idx][0] |
359 			    (data->ext_data[idx][1] << 8));
360 	sample[1] = (int16_t)(data->ext_data[idx][2] |
361 			    (data->ext_data[idx][3] << 8));
362 	sample[2] = (int16_t)(data->ext_data[idx][4] |
363 			    (data->ext_data[idx][5] << 8));
364 
365 	switch (chan) {
366 	case SENSOR_CHAN_MAGN_X:
367 		iis2iclx_magn_convert(val, sample[0], data->magn_gain);
368 		break;
369 	case SENSOR_CHAN_MAGN_Y:
370 		iis2iclx_magn_convert(val, sample[1], data->magn_gain);
371 		break;
372 	case SENSOR_CHAN_MAGN_Z:
373 		iis2iclx_magn_convert(val, sample[2], data->magn_gain);
374 		break;
375 	case SENSOR_CHAN_MAGN_XYZ:
376 		iis2iclx_magn_convert(val, sample[0], data->magn_gain);
377 		iis2iclx_magn_convert(val + 1, sample[1], data->magn_gain);
378 		iis2iclx_magn_convert(val + 2, sample[2], data->magn_gain);
379 		break;
380 	default:
381 		return -ENOTSUP;
382 	}
383 
384 	return 0;
385 }
386 
iis2iclx_hum_convert(struct sensor_value * val,struct iis2iclx_data * data)387 static inline void iis2iclx_hum_convert(struct sensor_value *val,
388 					  struct iis2iclx_data *data)
389 {
390 	float rh;
391 	int16_t raw_val;
392 	struct hts221_data *ht = &data->hts221;
393 	int idx;
394 
395 	idx = iis2iclx_shub_get_idx(data->dev, SENSOR_CHAN_HUMIDITY);
396 	if (idx < 0) {
397 		LOG_DBG("external press/temp not supported");
398 		return;
399 	}
400 
401 	raw_val = ((int16_t)(data->ext_data[idx][0] |
402 			   (data->ext_data[idx][1] << 8)));
403 
404 	/* find relative humidty by linear interpolation */
405 	rh = (ht->y1 - ht->y0) * raw_val + ht->x1 * ht->y0 - ht->x0 * ht->y1;
406 	rh /= (ht->x1 - ht->x0);
407 
408 	/* convert humidity to integer and fractional part */
409 	val->val1 = rh;
410 	val->val2 = rh * 1000000;
411 }
412 
iis2iclx_press_convert(struct sensor_value * val,struct iis2iclx_data * data)413 static inline void iis2iclx_press_convert(struct sensor_value *val,
414 					    struct iis2iclx_data *data)
415 {
416 	int32_t raw_val;
417 	int idx;
418 
419 	idx = iis2iclx_shub_get_idx(data->dev, SENSOR_CHAN_PRESS);
420 	if (idx < 0) {
421 		LOG_DBG("external press/temp not supported");
422 		return;
423 	}
424 
425 	raw_val = (int32_t)(data->ext_data[idx][0] |
426 			  (data->ext_data[idx][1] << 8) |
427 			  (data->ext_data[idx][2] << 16));
428 
429 	/* Pressure sensitivity is 4096 LSB/hPa */
430 	/* Convert raw_val to val in kPa */
431 	val->val1 = (raw_val >> 12) / 10;
432 	val->val2 = (raw_val >> 12) % 10 * 100000 +
433 		(((int32_t)((raw_val) & 0x0FFF) * 100000L) >> 12);
434 }
435 
iis2iclx_temp_convert(struct sensor_value * val,struct iis2iclx_data * data)436 static inline void iis2iclx_temp_convert(struct sensor_value *val,
437 					   struct iis2iclx_data *data)
438 {
439 	int16_t raw_val;
440 	int idx;
441 
442 	idx = iis2iclx_shub_get_idx(data->dev, SENSOR_CHAN_PRESS);
443 	if (idx < 0) {
444 		LOG_DBG("external press/temp not supported");
445 		return;
446 	}
447 
448 	raw_val = (int16_t)(data->ext_data[idx][3] |
449 			  (data->ext_data[idx][4] << 8));
450 
451 	/* Temperature sensitivity is 100 LSB/deg C */
452 	val->val1 = raw_val / 100;
453 	val->val2 = (int32_t)raw_val % 100 * (10000);
454 }
455 #endif
456 
iis2iclx_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)457 static int iis2iclx_channel_get(const struct device *dev,
458 				  enum sensor_channel chan,
459 				  struct sensor_value *val)
460 {
461 	struct iis2iclx_data *data = dev->data;
462 
463 	switch (chan) {
464 	case SENSOR_CHAN_ACCEL_X:
465 	case SENSOR_CHAN_ACCEL_Y:
466 	case SENSOR_CHAN_ACCEL_Z:
467 	case SENSOR_CHAN_ACCEL_XYZ:
468 		iis2iclx_accel_channel_get(chan, val, data);
469 		break;
470 #if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
471 	case SENSOR_CHAN_DIE_TEMP:
472 		iis2iclx_temp_channel_get(val, data);
473 		break;
474 #endif
475 #if defined(CONFIG_IIS2ICLX_SENSORHUB)
476 	case SENSOR_CHAN_MAGN_X:
477 	case SENSOR_CHAN_MAGN_Y:
478 	case SENSOR_CHAN_MAGN_Z:
479 	case SENSOR_CHAN_MAGN_XYZ:
480 		if (!data->shub_inited) {
481 			LOG_ERR("attr_set() shub not inited.");
482 			return -ENOTSUP;
483 		}
484 
485 		iis2iclx_magn_get_channel(chan, val, data);
486 		break;
487 
488 	case SENSOR_CHAN_HUMIDITY:
489 		if (!data->shub_inited) {
490 			LOG_ERR("attr_set() shub not inited.");
491 			return -ENOTSUP;
492 		}
493 
494 		iis2iclx_hum_convert(val, data);
495 		break;
496 
497 	case SENSOR_CHAN_PRESS:
498 		if (!data->shub_inited) {
499 			LOG_ERR("attr_set() shub not inited.");
500 			return -ENOTSUP;
501 		}
502 
503 		iis2iclx_press_convert(val, data);
504 		break;
505 
506 	case SENSOR_CHAN_AMBIENT_TEMP:
507 		if (!data->shub_inited) {
508 			LOG_ERR("attr_set() shub not inited.");
509 			return -ENOTSUP;
510 		}
511 
512 		iis2iclx_temp_convert(val, data);
513 		break;
514 #endif
515 	default:
516 		return -ENOTSUP;
517 	}
518 
519 	return 0;
520 }
521 
522 static const struct sensor_driver_api iis2iclx_driver_api = {
523 	.attr_set = iis2iclx_attr_set,
524 #if CONFIG_IIS2ICLX_TRIGGER
525 	.trigger_set = iis2iclx_trigger_set,
526 #endif
527 	.sample_fetch = iis2iclx_sample_fetch,
528 	.channel_get = iis2iclx_channel_get,
529 };
530 
iis2iclx_init_chip(const struct device * dev)531 static int iis2iclx_init_chip(const struct device *dev)
532 {
533 	const struct iis2iclx_config * const cfg = dev->config;
534 	struct iis2iclx_data *iis2iclx = dev->data;
535 	uint8_t chip_id;
536 	uint8_t odr = cfg->odr;
537 	uint8_t fs = cfg->range;
538 
539 	iis2iclx->dev = dev;
540 
541 	if (iis2iclx_device_id_get((stmdev_ctx_t *)&cfg->ctx, &chip_id) < 0) {
542 		LOG_ERR("Failed reading chip id");
543 		return -EIO;
544 	}
545 
546 	LOG_INF("chip id 0x%x", chip_id);
547 
548 	if (chip_id != IIS2ICLX_ID) {
549 		LOG_ERR("Invalid chip id 0x%x", chip_id);
550 		return -EIO;
551 	}
552 
553 	/* reset device */
554 	if (iis2iclx_reset_set((stmdev_ctx_t *)&cfg->ctx, 1) < 0) {
555 		return -EIO;
556 	}
557 
558 	k_usleep(100);
559 
560 	LOG_DBG("range is %d", fs);
561 	if (iis2iclx_accel_set_fs_raw(dev, fs) < 0) {
562 		LOG_ERR("failed to set accelerometer full-scale");
563 		return -EIO;
564 	}
565 	iis2iclx->acc_gain = (iis2iclx_accel_fs_sens[fs] * GAIN_UNIT_XL);
566 
567 	LOG_DBG("odr is %d", odr);
568 	if (iis2iclx_accel_set_odr_raw(dev, odr) < 0) {
569 		LOG_ERR("failed to set accelerometer sampling rate");
570 		return -EIO;
571 	}
572 
573 	/* Set FIFO bypass mode */
574 	if (iis2iclx_fifo_mode_set((stmdev_ctx_t *)&cfg->ctx,
575 				   IIS2ICLX_BYPASS_MODE) < 0) {
576 		LOG_ERR("failed to set FIFO mode");
577 		return -EIO;
578 	}
579 
580 	if (iis2iclx_block_data_update_set((stmdev_ctx_t *)&cfg->ctx, 1) < 0) {
581 		LOG_ERR("failed to set BDU mode");
582 		return -EIO;
583 	}
584 
585 	return 0;
586 }
587 
iis2iclx_init(const struct device * dev)588 static int iis2iclx_init(const struct device *dev)
589 {
590 #ifdef CONFIG_IIS2ICLX_TRIGGER
591 	const struct iis2iclx_config *cfg = dev->config;
592 #endif
593 	struct iis2iclx_data *data = dev->data;
594 
595 	LOG_INF("Initialize device %s", dev->name);
596 	data->dev = dev;
597 	if (iis2iclx_init_chip(dev) < 0) {
598 		LOG_ERR("failed to initialize chip");
599 		return -EIO;
600 	}
601 
602 #ifdef CONFIG_IIS2ICLX_TRIGGER
603 	if (cfg->trig_enabled) {
604 		if (iis2iclx_init_interrupt(dev) < 0) {
605 			LOG_ERR("Failed to initialize interrupt.");
606 			return -EIO;
607 		}
608 	}
609 #endif
610 
611 #ifdef CONFIG_IIS2ICLX_SENSORHUB
612 	data->shub_inited = true;
613 	if (iis2iclx_shub_init(dev) < 0) {
614 		LOG_INF("shub: no external chips found");
615 		data->shub_inited = false;
616 	}
617 #endif
618 
619 	return 0;
620 }
621 
622 #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
623 #warning "IIS2ICLX driver enabled without any devices"
624 #endif
625 
626 /*
627  * Device creation macro, shared by IIS2ICLX_DEFINE_SPI() and
628  * IIS2ICLX_DEFINE_I2C().
629  */
630 
631 #define IIS2ICLX_DEVICE_INIT(inst)					\
632 	DEVICE_DT_INST_DEFINE(inst,					\
633 			    iis2iclx_init,				\
634 			    NULL,					\
635 			    &iis2iclx_data_##inst,			\
636 			    &iis2iclx_config_##inst,			\
637 			    POST_KERNEL,				\
638 			    CONFIG_SENSOR_INIT_PRIORITY,		\
639 			    &iis2iclx_driver_api);
640 
641 /*
642  * Instantiation macros used when a device is on a SPI bus.
643  */
644 
645 #ifdef CONFIG_IIS2ICLX_TRIGGER
646 #define IIS2ICLX_CFG_IRQ(inst) \
647 	.trig_enabled = true,						\
648 	.gpio_drdy = GPIO_DT_SPEC_INST_GET(inst, drdy_gpios),		\
649 	.int_pin = DT_INST_PROP(inst, int_pin)
650 #else
651 #define IIS2ICLX_CFG_IRQ(inst)
652 #endif /* CONFIG_IIS2ICLX_TRIGGER */
653 
654 #define IIS2ICLX_SPI_OPERATION (SPI_WORD_SET(8) |			\
655 				SPI_OP_MODE_MASTER |			\
656 				SPI_MODE_CPOL |				\
657 				SPI_MODE_CPHA)				\
658 
659 #define IIS2ICLX_CONFIG_SPI(inst)					\
660 	{								\
661 		.ctx = {						\
662 			.read_reg =					\
663 			   (stmdev_read_ptr) stmemsc_spi_read,		\
664 			.write_reg =					\
665 			   (stmdev_write_ptr) stmemsc_spi_write,	\
666 			.handle =					\
667 			   (void *)&iis2iclx_config_##inst.stmemsc_cfg,	\
668 		},							\
669 		.stmemsc_cfg.spi = {					\
670 			.bus = DEVICE_DT_GET(DT_INST_BUS(inst)),	\
671 			.spi_cfg = SPI_CONFIG_DT_INST(inst,		\
672 					   IIS2ICLX_SPI_OPERATION,	\
673 					   0),				\
674 		},							\
675 		.odr = DT_INST_PROP(inst, odr),				\
676 		.range = DT_INST_PROP(inst, range),			\
677 		COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, drdy_gpios),	\
678 			(IIS2ICLX_CFG_IRQ(inst)), ())			\
679 	}
680 
681 /*
682  * Instantiation macros used when a device is on an I2C bus.
683  */
684 
685 #define IIS2ICLX_CONFIG_I2C(inst)					\
686 	{								\
687 		.ctx = {						\
688 			.read_reg =					\
689 			   (stmdev_read_ptr) stmemsc_i2c_read,		\
690 			.write_reg =					\
691 			   (stmdev_write_ptr) stmemsc_i2c_write,	\
692 			.handle =					\
693 			   (void *)&iis2iclx_config_##inst.stmemsc_cfg,	\
694 		},							\
695 		.stmemsc_cfg.i2c = {					\
696 			.bus = DEVICE_DT_GET(DT_INST_BUS(inst)),	\
697 			.i2c_slv_addr = DT_INST_REG_ADDR(inst),		\
698 		},							\
699 		.odr = DT_INST_PROP(inst, odr),				\
700 		.range = DT_INST_PROP(inst, range),			\
701 		COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, drdy_gpios),	\
702 			(IIS2ICLX_CFG_IRQ(inst)), ())			\
703 	}
704 
705 /*
706  * Main instantiation macro. Use of COND_CODE_1() selects the right
707  * bus-specific macro at preprocessor time.
708  */
709 
710 #define IIS2ICLX_DEFINE(inst)						\
711 	static struct iis2iclx_data iis2iclx_data_##inst;		\
712 	static const struct iis2iclx_config iis2iclx_config_##inst =	\
713 		COND_CODE_1(DT_INST_ON_BUS(inst, spi),			\
714 			(IIS2ICLX_CONFIG_SPI(inst)),			\
715 			(IIS2ICLX_CONFIG_I2C(inst)));			\
716 	IIS2ICLX_DEVICE_INIT(inst)
717 
718 DT_INST_FOREACH_STATUS_OKAY(IIS2ICLX_DEFINE)
719