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