drivers/sensor: add support to IIS2ICLX accelerometer

The IIS2ICLX is a high-accuracy. ultra-low noise, low-power
two-axis linear accelerometer which can be interfaced through
either I2C or SPI bus.
Its high accuracy, stability over temperature and repeatability
make IIS2ICLX particularly suitable for inclination measurement
for industrial applications (inclinometers).

https://www.st.com/resource/en/datasheet/iis2iclx.pdf

This driver is based on stmemsc i/f v1.03.

Signed-off-by: Armando Visconti <armando.visconti@st.com>
diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt
index 3fbaaa9..96405b8 100644
--- a/drivers/sensor/CMakeLists.txt
+++ b/drivers/sensor/CMakeLists.txt
@@ -29,6 +29,7 @@
 add_subdirectory_ifdef(CONFIG_HTS221		hts221)
 add_subdirectory_ifdef(CONFIG_IIS2DH		iis2dh)
 add_subdirectory_ifdef(CONFIG_IIS2DLPC		iis2dlpc)
+add_subdirectory_ifdef(CONFIG_IIS2ICLX		iis2iclx)
 add_subdirectory_ifdef(CONFIG_IIS2MDC		iis2mdc)
 add_subdirectory_ifdef(CONFIG_IIS3DHHC		iis3dhhc)
 add_subdirectory_ifdef(CONFIG_ISL29035		isl29035)
diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig
index 16d69bc..047843d 100644
--- a/drivers/sensor/Kconfig
+++ b/drivers/sensor/Kconfig
@@ -95,6 +95,8 @@
 
 source "drivers/sensor/iis2dlpc/Kconfig"
 
+source "drivers/sensor/iis2iclx/Kconfig"
+
 source "drivers/sensor/iis2mdc/Kconfig"
 
 source "drivers/sensor/iis3dhhc/Kconfig"
diff --git a/drivers/sensor/iis2iclx/CMakeLists.txt b/drivers/sensor/iis2iclx/CMakeLists.txt
new file mode 100644
index 0000000..481798b
--- /dev/null
+++ b/drivers/sensor/iis2iclx/CMakeLists.txt
@@ -0,0 +1,13 @@
+# ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
+#
+# Copyright (c) 2020 STMicroelectronics
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+zephyr_library()
+
+zephyr_library_sources_ifdef(CONFIG_IIS2ICLX            iis2iclx.c)
+zephyr_library_sources_ifdef(CONFIG_IIS2ICLX            iis2iclx_i2c.c)
+zephyr_library_sources_ifdef(CONFIG_IIS2ICLX            iis2iclx_spi.c)
+zephyr_library_sources_ifdef(CONFIG_IIS2ICLX_SENSORHUB  iis2iclx_shub.c)
+zephyr_library_sources_ifdef(CONFIG_IIS2ICLX_TRIGGER    iis2iclx_trigger.c)
diff --git a/drivers/sensor/iis2iclx/Kconfig b/drivers/sensor/iis2iclx/Kconfig
new file mode 100644
index 0000000..cb287a6
--- /dev/null
+++ b/drivers/sensor/iis2iclx/Kconfig
@@ -0,0 +1,138 @@
+# ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
+
+# Copyright (c) 2020 STMicroelectronics
+# SPDX-License-Identifier: Apache-2.0
+
+menuconfig IIS2ICLX
+	bool "IIS2ICLX I2C/SPI accelerometer Chip"
+	depends on I2C || SPI
+	select HAS_STMEMSC
+	select USE_STDC_IIS2ICLX
+	help
+	  Enable driver for IIS2ICLX accelerometer
+	  sensor.
+
+if IIS2ICLX
+
+choice IIS2ICLX_TRIGGER_MODE
+	prompt "Trigger mode"
+	help
+	  Specify the type of triggering to be used by the driver.
+
+config IIS2ICLX_TRIGGER_NONE
+	bool "No trigger"
+
+config IIS2ICLX_TRIGGER_GLOBAL_THREAD
+	bool "Use global thread"
+	depends on GPIO
+	select IIS2ICLX_TRIGGER
+
+config IIS2ICLX_TRIGGER_OWN_THREAD
+	bool "Use own thread"
+	depends on GPIO
+	select IIS2ICLX_TRIGGER
+
+endchoice
+
+config IIS2ICLX_TRIGGER
+	bool
+
+if IIS2ICLX_TRIGGER
+
+config IIS2ICLX_THREAD_PRIORITY
+	int "Thread priority"
+	depends on IIS2ICLX_TRIGGER_OWN_THREAD
+	default 10
+	help
+	  Priority of thread used by the driver to handle interrupts.
+
+config IIS2ICLX_THREAD_STACK_SIZE
+	int "Thread stack size"
+	depends on IIS2ICLX_TRIGGER_OWN_THREAD
+	default 1024
+	help
+	  Stack size of thread used by the driver to handle interrupts.
+
+choice IIS2ICLX_INT_PIN
+	prompt "Sensor INT pin number"
+	default IIS2ICLX_INT_PIN_1
+	help
+	  The number of IIS2ICLX int pin used to generate interrupt to cpu.
+	  Supported values are int1 or int2
+
+config IIS2ICLX_INT_PIN_1
+	bool "int1"
+
+config IIS2ICLX_INT_PIN_2
+	bool "int2"
+endchoice
+
+endif # IIS2ICLX_TRIGGER
+
+config IIS2ICLX_ENABLE_TEMP
+	bool "Enable temperature"
+	help
+	  Enable/disable temperature
+
+config IIS2ICLX_SENSORHUB
+	bool "Enable I2C sensorhub feature"
+	help
+	  Enable/disable internal sensorhub. You can enable
+	  a maximum of two external sensors (if more than two are enabled
+	  the system would enumerate only the first two found)
+
+if IIS2ICLX_SENSORHUB
+
+config IIS2ICLX_EXT_LIS2MDL
+	bool "Enable LIS2MDL as external sensor"
+
+config IIS2ICLX_EXT_IIS2MDC
+	bool "Enable IIS2MDC as external sensor"
+
+config IIS2ICLX_EXT_LPS22HH
+	bool "Enable LPS22HH as external sensor"
+
+config IIS2ICLX_EXT_HTS221
+	bool "Enable HTS221 as external sensor"
+
+config IIS2ICLX_EXT_LPS22HB
+	bool "Enable LPS22HB as external sensor"
+
+endif # IIS2ICLX_SENSORHUB
+
+menu "Attributes"
+
+config IIS2ICLX_ACCEL_FS
+	int "Accelerometer full-scale range"
+	default 0
+	help
+	  Specify the default accelerometer full-scale range.
+	  An X value for the config represents a range of +/- X G. Valid values
+	  are:
+	  0:  Full Scale selected at runtime
+	  500:  +/- 500mg
+	  1000: +/- 1g
+	  2000: +/- 2g
+	  3000: +/- 3g
+
+config IIS2ICLX_ACCEL_ODR
+	int "Accelerometer Output data rate frequency"
+	range 0 10
+	default 0
+	help
+	  Specify the default accelerometer output data rate expressed in
+	  samples per second (Hz).
+	  0: ODR selected at runtime
+	  1: 12.5Hz
+	  2: 26Hz
+	  3: 52Hz
+	  4: 104Hz
+	  5: 208Hz
+	  6: 416Hz
+	  7: 833Hz
+	  8: 1660Hz
+	  9: 3330Hz
+	  10: 6660Hz
+endmenu
+
+endif # IIS2ICLX
diff --git a/drivers/sensor/iis2iclx/iis2iclx.c b/drivers/sensor/iis2iclx/iis2iclx.c
new file mode 100644
index 0000000..5b2aa2b
--- /dev/null
+++ b/drivers/sensor/iis2iclx/iis2iclx.c
@@ -0,0 +1,657 @@
+/* ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
+ *
+ * Copyright (c) 2020 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Datasheet:
+ * https://www.st.com/resource/en/datasheet/iis2iclx.pdf
+ */
+
+#define DT_DRV_COMPAT st_iis2iclx
+
+#include <drivers/sensor.h>
+#include <kernel.h>
+#include <device.h>
+#include <init.h>
+#include <string.h>
+#include <sys/byteorder.h>
+#include <sys/__assert.h>
+#include <logging/log.h>
+
+#include "iis2iclx.h"
+
+LOG_MODULE_REGISTER(IIS2ICLX, CONFIG_SENSOR_LOG_LEVEL);
+
+static const uint16_t iis2iclx_odr_map[] = {0, 12, 26, 52, 104, 208, 416, 833,
+					1660, 3330, 6660};
+
+#if defined(IIS2ICLX_ACCEL_ODR_RUNTIME)
+static int iis2iclx_freq_to_odr_val(uint16_t freq)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(iis2iclx_odr_map); i++) {
+		if (freq == iis2iclx_odr_map[i]) {
+			return i;
+		}
+	}
+
+	return -EINVAL;
+}
+#endif
+
+static int iis2iclx_odr_to_freq_val(uint16_t odr)
+{
+	/* for valid index, return value from map */
+	if (odr < ARRAY_SIZE(iis2iclx_odr_map)) {
+		return iis2iclx_odr_map[odr];
+	}
+
+	/* invalid index, return last entry */
+	return iis2iclx_odr_map[ARRAY_SIZE(iis2iclx_odr_map) - 1];
+}
+
+#ifdef IIS2ICLX_ACCEL_FS_RUNTIME
+static const uint16_t iis2iclx_accel_fs_map[] = {500, 3000, 1000, 2000};
+static const uint16_t iis2iclx_accel_fs_sens[] = {1, 8, 2, 4};
+
+static int iis2iclx_accel_range_to_fs_val(int32_t range)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(iis2iclx_accel_fs_map); i++) {
+		if (range == iis2iclx_accel_fs_map[i]) {
+			return i;
+		}
+	}
+
+	return -EINVAL;
+}
+#endif
+
+static inline int iis2iclx_reboot(const struct device *dev)
+{
+	struct iis2iclx_data *data = dev->data;
+
+	if (iis2iclx_boot_set(data->ctx, 1) < 0) {
+		return -EIO;
+	}
+
+	/* Wait sensor turn-on time as per datasheet */
+	k_msleep(35);
+
+	return 0;
+}
+
+static int iis2iclx_accel_set_fs_raw(const struct device *dev, uint8_t fs)
+{
+	struct iis2iclx_data *data = dev->data;
+
+	if (iis2iclx_xl_full_scale_set(data->ctx, fs) < 0) {
+		return -EIO;
+	}
+
+	data->accel_fs = fs;
+
+	return 0;
+}
+
+static int iis2iclx_accel_set_odr_raw(const struct device *dev, uint8_t odr)
+{
+	struct iis2iclx_data *data = dev->data;
+
+	if (iis2iclx_xl_data_rate_set(data->ctx, odr) < 0) {
+		return -EIO;
+	}
+
+	data->accel_freq = iis2iclx_odr_to_freq_val(odr);
+
+	return 0;
+}
+
+#ifdef IIS2ICLX_ACCEL_ODR_RUNTIME
+static int iis2iclx_accel_odr_set(const struct device *dev, uint16_t freq)
+{
+	int odr;
+
+	odr = iis2iclx_freq_to_odr_val(freq);
+	if (odr < 0) {
+		return odr;
+	}
+
+	if (iis2iclx_accel_set_odr_raw(dev, odr) < 0) {
+		LOG_ERR("failed to set accelerometer sampling rate");
+		return -EIO;
+	}
+
+	return 0;
+}
+#endif
+
+#ifdef IIS2ICLX_ACCEL_FS_RUNTIME
+static int iis2iclx_accel_range_set(const struct device *dev, int32_t range)
+{
+	int fs;
+	struct iis2iclx_data *data = dev->data;
+
+	fs = iis2iclx_accel_range_to_fs_val(range);
+	if (fs < 0) {
+		return fs;
+	}
+
+	if (iis2iclx_accel_set_fs_raw(dev, fs) < 0) {
+		LOG_ERR("failed to set accelerometer full-scale");
+		return -EIO;
+	}
+
+	data->acc_gain = (iis2iclx_accel_fs_sens[fs] * GAIN_UNIT_XL);
+	return 0;
+}
+#endif
+
+static int iis2iclx_accel_config(const struct device *dev,
+				   enum sensor_channel chan,
+				   enum sensor_attribute attr,
+				   const struct sensor_value *val)
+{
+	switch (attr) {
+#ifdef IIS2ICLX_ACCEL_FS_RUNTIME
+	case SENSOR_ATTR_FULL_SCALE:
+		return iis2iclx_accel_range_set(dev, sensor_ms2_to_g(val));
+#endif
+#ifdef IIS2ICLX_ACCEL_ODR_RUNTIME
+	case SENSOR_ATTR_SAMPLING_FREQUENCY:
+		return iis2iclx_accel_odr_set(dev, val->val1);
+#endif
+	default:
+		LOG_ERR("Accel attribute not supported.");
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+static int iis2iclx_attr_set(const struct device *dev,
+			       enum sensor_channel chan,
+			       enum sensor_attribute attr,
+			       const struct sensor_value *val)
+{
+	switch (chan) {
+	case SENSOR_CHAN_ACCEL_XYZ:
+		return iis2iclx_accel_config(dev, chan, attr, val);
+#if defined(CONFIG_IIS2ICLX_SENSORHUB)
+	case SENSOR_CHAN_MAGN_XYZ:
+	case SENSOR_CHAN_PRESS:
+	case SENSOR_CHAN_HUMIDITY:
+		return iis2iclx_shub_config(dev, chan, attr, val);
+#endif /* CONFIG_IIS2ICLX_SENSORHUB */
+	default:
+		LOG_ERR("attr_set() not supported on this channel.");
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+static int iis2iclx_sample_fetch_accel(const struct device *dev)
+{
+	struct iis2iclx_data *data = dev->data;
+	int16_t buf[2];
+
+	if (iis2iclx_acceleration_raw_get(data->ctx, buf) < 0) {
+		LOG_ERR("Failed to read sample");
+		return -EIO;
+	}
+
+	data->acc[0] = sys_le16_to_cpu(buf[0]);
+	data->acc[1] = sys_le16_to_cpu(buf[1]);
+
+	return 0;
+}
+
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+static int iis2iclx_sample_fetch_temp(const struct device *dev)
+{
+	struct iis2iclx_data *data = dev->data;
+	int16_t buf;
+
+	if (iis2iclx_temperature_raw_get(data->ctx, &buf) < 0) {
+		LOG_ERR("Failed to read sample");
+		return -EIO;
+	}
+
+	data->temp_sample = sys_le16_to_cpu(buf);
+
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_IIS2ICLX_SENSORHUB)
+static int iis2iclx_sample_fetch_shub(const struct device *dev)
+{
+	if (iis2iclx_shub_fetch_external_devs(dev) < 0) {
+		LOG_ERR("failed to read ext shub devices");
+		return -EIO;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IIS2ICLX_SENSORHUB */
+
+static int iis2iclx_sample_fetch(const struct device *dev,
+				   enum sensor_channel chan)
+{
+	switch (chan) {
+	case SENSOR_CHAN_ACCEL_XYZ:
+		iis2iclx_sample_fetch_accel(dev);
+#if defined(CONFIG_IIS2ICLX_SENSORHUB)
+		iis2iclx_sample_fetch_shub(dev);
+#endif
+		break;
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+	case SENSOR_CHAN_DIE_TEMP:
+		iis2iclx_sample_fetch_temp(dev);
+		break;
+#endif
+	case SENSOR_CHAN_ALL:
+		iis2iclx_sample_fetch_accel(dev);
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+		iis2iclx_sample_fetch_temp(dev);
+#endif
+#if defined(CONFIG_IIS2ICLX_SENSORHUB)
+		iis2iclx_sample_fetch_shub(dev);
+#endif
+		break;
+	default:
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+static inline void iis2iclx_accel_convert(struct sensor_value *val, int raw_val,
+					    uint32_t sensitivity)
+{
+	int64_t dval;
+
+	/* Sensitivity is exposed in ug/LSB */
+	/* Convert to m/s^2 */
+	dval = (int64_t)(raw_val) * sensitivity * SENSOR_G_DOUBLE;
+	val->val1 = (int32_t)(dval / 1000000);
+	val->val2 = (int32_t)(dval % 1000000);
+
+}
+
+static inline int iis2iclx_accel_get_channel(enum sensor_channel chan,
+					       struct sensor_value *val,
+					       struct iis2iclx_data *data,
+					       uint32_t sensitivity)
+{
+	uint8_t i;
+
+	switch (chan) {
+	case SENSOR_CHAN_ACCEL_X:
+		iis2iclx_accel_convert(val, data->acc[0], sensitivity);
+		break;
+	case SENSOR_CHAN_ACCEL_Y:
+		iis2iclx_accel_convert(val, data->acc[1], sensitivity);
+		break;
+	case SENSOR_CHAN_ACCEL_XYZ:
+		for (i = 0; i < 2; i++) {
+			iis2iclx_accel_convert(val++, data->acc[i], sensitivity);
+		}
+		break;
+	default:
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+static int iis2iclx_accel_channel_get(enum sensor_channel chan,
+					struct sensor_value *val,
+					struct iis2iclx_data *data)
+{
+	return iis2iclx_accel_get_channel(chan, val, data, data->acc_gain);
+}
+
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+static void iis2iclx_temp_channel_get(struct sensor_value *val,
+					  struct iis2iclx_data *data)
+{
+	/* val = temp_sample / 256 + 25 */
+	val->val1 = data->temp_sample / 256 + 25;
+	val->val2 = (data->temp_sample % 256) * (1000000 / 256);
+}
+#endif
+
+#if defined(CONFIG_IIS2ICLX_SENSORHUB)
+static inline void iis2iclx_magn_convert(struct sensor_value *val, int raw_val,
+					   uint16_t sensitivity)
+{
+	double dval;
+
+	/* Sensitivity is exposed in mgauss/LSB */
+	dval = (double)(raw_val * sensitivity);
+	val->val1 = (int32_t)dval / 1000000;
+	val->val2 = (int32_t)dval % 1000000;
+}
+
+static inline int iis2iclx_magn_get_channel(enum sensor_channel chan,
+					      struct sensor_value *val,
+					      struct iis2iclx_data *data)
+{
+	int16_t sample[3];
+	int idx;
+
+	idx = iis2iclx_shub_get_idx(SENSOR_CHAN_MAGN_XYZ);
+	if (idx < 0) {
+		LOG_ERR("external magn not supported");
+		return -ENOTSUP;
+	}
+
+
+	sample[0] = (int16_t)(data->ext_data[idx][0] |
+			    (data->ext_data[idx][1] << 8));
+	sample[1] = (int16_t)(data->ext_data[idx][2] |
+			    (data->ext_data[idx][3] << 8));
+	sample[2] = (int16_t)(data->ext_data[idx][4] |
+			    (data->ext_data[idx][5] << 8));
+
+	switch (chan) {
+	case SENSOR_CHAN_MAGN_X:
+		iis2iclx_magn_convert(val, sample[0], data->magn_gain);
+		break;
+	case SENSOR_CHAN_MAGN_Y:
+		iis2iclx_magn_convert(val, sample[1], data->magn_gain);
+		break;
+	case SENSOR_CHAN_MAGN_Z:
+		iis2iclx_magn_convert(val, sample[2], data->magn_gain);
+		break;
+	case SENSOR_CHAN_MAGN_XYZ:
+		iis2iclx_magn_convert(val, sample[0], data->magn_gain);
+		iis2iclx_magn_convert(val + 1, sample[1], data->magn_gain);
+		iis2iclx_magn_convert(val + 2, sample[2], data->magn_gain);
+		break;
+	default:
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+static inline void iis2iclx_hum_convert(struct sensor_value *val,
+					  struct iis2iclx_data *data)
+{
+	float rh;
+	int16_t raw_val;
+	struct hts221_data *ht = &data->hts221;
+	int idx;
+
+	idx = iis2iclx_shub_get_idx(SENSOR_CHAN_HUMIDITY);
+	if (idx < 0) {
+		LOG_DBG("external press/temp not supported");
+		return;
+	}
+
+	raw_val = ((int16_t)(data->ext_data[idx][0] |
+			   (data->ext_data[idx][1] << 8)));
+
+	/* find relative humidty by linear interpolation */
+	rh = (ht->y1 - ht->y0) * raw_val + ht->x1 * ht->y0 - ht->x0 * ht->y1;
+	rh /= (ht->x1 - ht->x0);
+
+	/* convert humidity to integer and fractional part */
+	val->val1 = rh;
+	val->val2 = rh * 1000000;
+}
+
+static inline void iis2iclx_press_convert(struct sensor_value *val,
+					    struct iis2iclx_data *data)
+{
+	int32_t raw_val;
+	int idx;
+
+	idx = iis2iclx_shub_get_idx(SENSOR_CHAN_PRESS);
+	if (idx < 0) {
+		LOG_DBG("external press/temp not supported");
+		return;
+	}
+
+	raw_val = (int32_t)(data->ext_data[idx][0] |
+			  (data->ext_data[idx][1] << 8) |
+			  (data->ext_data[idx][2] << 16));
+
+	/* Pressure sensitivity is 4096 LSB/hPa */
+	/* Convert raw_val to val in kPa */
+	val->val1 = (raw_val >> 12) / 10;
+	val->val2 = (raw_val >> 12) % 10 * 100000 +
+		(((int32_t)((raw_val) & 0x0FFF) * 100000L) >> 12);
+}
+
+static inline void iis2iclx_temp_convert(struct sensor_value *val,
+					   struct iis2iclx_data *data)
+{
+	int16_t raw_val;
+	int idx;
+
+	idx = iis2iclx_shub_get_idx(SENSOR_CHAN_PRESS);
+	if (idx < 0) {
+		LOG_DBG("external press/temp not supported");
+		return;
+	}
+
+	raw_val = (int16_t)(data->ext_data[idx][3] |
+			  (data->ext_data[idx][4] << 8));
+
+	/* Temperature sensitivity is 100 LSB/deg C */
+	val->val1 = raw_val / 100;
+	val->val2 = (int32_t)raw_val % 100 * (10000);
+}
+#endif
+
+static int iis2iclx_channel_get(const struct device *dev,
+				  enum sensor_channel chan,
+				  struct sensor_value *val)
+{
+	struct iis2iclx_data *data = dev->data;
+
+	switch (chan) {
+	case SENSOR_CHAN_ACCEL_X:
+	case SENSOR_CHAN_ACCEL_Y:
+	case SENSOR_CHAN_ACCEL_Z:
+	case SENSOR_CHAN_ACCEL_XYZ:
+		iis2iclx_accel_channel_get(chan, val, data);
+		break;
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+	case SENSOR_CHAN_DIE_TEMP:
+		iis2iclx_temp_channel_get(val, data);
+		break;
+#endif
+#if defined(CONFIG_IIS2ICLX_SENSORHUB)
+	case SENSOR_CHAN_MAGN_X:
+	case SENSOR_CHAN_MAGN_Y:
+	case SENSOR_CHAN_MAGN_Z:
+	case SENSOR_CHAN_MAGN_XYZ:
+		iis2iclx_magn_get_channel(chan, val, data);
+		break;
+
+	case SENSOR_CHAN_HUMIDITY:
+		iis2iclx_hum_convert(val, data);
+		break;
+
+	case SENSOR_CHAN_PRESS:
+		iis2iclx_press_convert(val, data);
+		break;
+
+	case SENSOR_CHAN_AMBIENT_TEMP:
+		iis2iclx_temp_convert(val, data);
+		break;
+#endif
+	default:
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+static const struct sensor_driver_api iis2iclx_api_funcs = {
+	.attr_set = iis2iclx_attr_set,
+#if CONFIG_IIS2ICLX_TRIGGER
+	.trigger_set = iis2iclx_trigger_set,
+#endif
+	.sample_fetch = iis2iclx_sample_fetch,
+	.channel_get = iis2iclx_channel_get,
+};
+
+static int iis2iclx_init_chip(const struct device *dev)
+{
+	struct iis2iclx_data *iis2iclx = dev->data;
+	uint8_t chip_id;
+
+	iis2iclx->dev = dev;
+
+	if (iis2iclx_device_id_get(iis2iclx->ctx, &chip_id) < 0) {
+		LOG_ERR("Failed reading chip id");
+		return -EIO;
+	}
+
+	LOG_INF("chip id 0x%x", chip_id);
+
+	if (chip_id != IIS2ICLX_ID) {
+		LOG_ERR("Invalid chip id 0x%x", chip_id);
+		return -EIO;
+	}
+
+	/* reset device */
+	if (iis2iclx_reset_set(iis2iclx->ctx, 1) < 0) {
+		return -EIO;
+	}
+
+	k_usleep(100);
+
+	if (iis2iclx_accel_set_fs_raw(dev,
+				     IIS2ICLX_DEFAULT_ACCEL_FULLSCALE) < 0) {
+		LOG_ERR("failed to set accelerometer full-scale");
+		return -EIO;
+	}
+	iis2iclx->acc_gain = IIS2ICLX_DEFAULT_ACCEL_SENSITIVITY;
+
+	iis2iclx->accel_freq = iis2iclx_odr_to_freq_val(CONFIG_IIS2ICLX_ACCEL_ODR);
+	if (iis2iclx_accel_set_odr_raw(dev, CONFIG_IIS2ICLX_ACCEL_ODR) < 0) {
+		LOG_ERR("failed to set accelerometer sampling rate");
+		return -EIO;
+	}
+
+	/* Set FIFO bypass mode */
+	if (iis2iclx_fifo_mode_set(iis2iclx->ctx, IIS2ICLX_BYPASS_MODE) < 0) {
+		LOG_ERR("failed to set FIFO mode");
+		return -EIO;
+	}
+
+	if (iis2iclx_block_data_update_set(iis2iclx->ctx, 1) < 0) {
+		LOG_ERR("failed to set BDU mode");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static struct iis2iclx_data iis2iclx_data;
+
+static const struct iis2iclx_config iis2iclx_config = {
+	.bus_name = DT_INST_BUS_LABEL(0),
+#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
+	.bus_init = iis2iclx_spi_init,
+	.spi_conf.frequency = DT_INST_PROP(0, spi_max_frequency),
+	.spi_conf.operation = (SPI_OP_MODE_MASTER | SPI_MODE_CPOL |
+			       SPI_MODE_CPHA | SPI_WORD_SET(8) |
+			       SPI_LINES_SINGLE),
+	.spi_conf.slave     = DT_INST_REG_ADDR(0),
+#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
+	.gpio_cs_port	    = DT_INST_SPI_DEV_CS_GPIOS_LABEL(0),
+	.cs_gpio	    = DT_INST_SPI_DEV_CS_GPIOS_PIN(0),
+	.cs_gpio_flags	    = DT_INST_SPI_DEV_CS_GPIOS_FLAGS(0),
+
+	.spi_conf.cs        =  &iis2iclx_data.cs_ctrl,
+#else
+	.spi_conf.cs        = NULL,
+#endif
+#elif DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
+	.bus_init = iis2iclx_i2c_init,
+	.i2c_slv_addr = DT_INST_REG_ADDR(0),
+#else
+#error "BUS MACRO NOT DEFINED IN DTS"
+#endif
+#ifdef CONFIG_IIS2ICLX_TRIGGER
+#if DT_INST_PROP_HAS_IDX(0, drdy_gpios, 1)
+	/* Two gpio pins declared in DTS */
+#if defined(CONFIG_IIS2ICLX_INT_PIN_1)
+	.int_gpio_port = DT_INST_GPIO_LABEL_BY_IDX(0, drdy_gpios, 0),
+	.int_gpio_pin = DT_INST_GPIO_PIN_BY_IDX(0, drdy_gpios, 0),
+	.int_gpio_flags = DT_INST_GPIO_FLAGS_BY_IDX(0, drdy_gpios, 0),
+	.int_pin = 1,
+#elif defined(CONFIG_IIS2ICLX_INT_PIN_2)
+	.int_gpio_port = DT_INST_GPIO_LABEL_BY_IDX(0, drdy_gpios, 1),
+	.int_gpio_pin = DT_INST_GPIO_PIN_BY_IDX(0, drdy_gpios, 1),
+	.int_gpio_flags = DT_INST_GPIO_FLAGS_BY_IDX(0, drdy_gpios, 1),
+	.int_pin = 2,
+#endif /* CONFIG_IIS2ICLX_INT_PIN_* */
+#else
+	/* One gpio pin declared in DTS */
+	.int_gpio_port = DT_INST_GPIO_LABEL(0, drdy_gpios),
+	.int_gpio_pin = DT_INST_GPIO_PIN(0, drdy_gpios),
+	.int_gpio_flags = DT_INST_GPIO_FLAGS(0, drdy_gpios),
+#if defined(CONFIG_IIS2ICLX_INT_PIN_1)
+	.int_pin = 1,
+#elif defined(CONFIG_IIS2ICLX_INT_PIN_2)
+	.int_pin = 2,
+#endif /* CONFIG_IIS2ICLX_INT_PIN_* */
+#endif /* DT_INST_PROP_HAS_IDX(0, drdy_gpios, 1) */
+
+#endif /* CONFIG_IIS2ICLX_TRIGGER */
+};
+
+static int iis2iclx_init(const struct device *dev)
+{
+	const struct iis2iclx_config * const config = dev->config;
+	struct iis2iclx_data *data = dev->data;
+
+	data->bus = device_get_binding(config->bus_name);
+	if (!data->bus) {
+		LOG_DBG("master not found: %s",
+			    config->bus_name);
+		return -EINVAL;
+	}
+
+	config->bus_init(dev);
+
+	if (iis2iclx_init_chip(dev) < 0) {
+		LOG_ERR("failed to initialize chip");
+		return -EIO;
+	}
+
+#ifdef CONFIG_IIS2ICLX_TRIGGER
+	if (iis2iclx_init_interrupt(dev) < 0) {
+		LOG_ERR("Failed to initialize interrupt.");
+		return -EIO;
+	}
+#endif
+
+#ifdef CONFIG_IIS2ICLX_SENSORHUB
+	if (iis2iclx_shub_init(dev) < 0) {
+		LOG_ERR("failed to initialize external chip");
+		return -EIO;
+	}
+#endif
+
+	return 0;
+}
+
+
+static struct iis2iclx_data iis2iclx_data;
+
+DEVICE_AND_API_INIT(iis2iclx, DT_INST_LABEL(0), iis2iclx_init,
+		    &iis2iclx_data, &iis2iclx_config, POST_KERNEL,
+		    CONFIG_SENSOR_INIT_PRIORITY, &iis2iclx_api_funcs);
diff --git a/drivers/sensor/iis2iclx/iis2iclx.h b/drivers/sensor/iis2iclx/iis2iclx.h
new file mode 100644
index 0000000..d4cbd04
--- /dev/null
+++ b/drivers/sensor/iis2iclx/iis2iclx.h
@@ -0,0 +1,162 @@
+/* ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
+ *
+ * Copyright (c) 2020 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Datasheet:
+ * https://www.st.com/resource/en/datasheet/iis2iclx.pdf
+ */
+
+#ifndef ZEPHYR_DRIVERS_SENSOR_IIS2ICLX_IIS2ICLX_H_
+#define ZEPHYR_DRIVERS_SENSOR_IIS2ICLX_IIS2ICLX_H_
+
+#include <drivers/sensor.h>
+#include <zephyr/types.h>
+#include <drivers/gpio.h>
+#include <drivers/spi.h>
+#include <sys/util.h>
+#include "iis2iclx_reg.h"
+
+#define IIS2ICLX_EN_BIT					0x01
+#define IIS2ICLX_DIS_BIT					0x00
+
+/* Accel sensor sensitivity grain is 15 ug/LSB */
+#define GAIN_UNIT_XL				(15LL)
+
+#define SENSOR_PI_DOUBLE			(SENSOR_PI / 1000000.0)
+#define SENSOR_DEG2RAD_DOUBLE			(SENSOR_PI_DOUBLE / 180)
+#define SENSOR_G_DOUBLE				(SENSOR_G / 1000000.0)
+
+#if CONFIG_IIS2ICLX_ACCEL_FS == 0
+	#define IIS2ICLX_ACCEL_FS_RUNTIME 1
+	#define IIS2ICLX_DEFAULT_ACCEL_FULLSCALE		0
+	#define IIS2ICLX_DEFAULT_ACCEL_SENSITIVITY	GAIN_UNIT_XL
+#elif CONFIG_IIS2ICLX_ACCEL_FS == 500
+	#define IIS2ICLX_DEFAULT_ACCEL_FULLSCALE		0
+	#define IIS2ICLX_DEFAULT_ACCEL_SENSITIVITY	GAIN_UNIT_XL
+#elif CONFIG_IIS2ICLX_ACCEL_FS == 1000
+	#define IIS2ICLX_DEFAULT_ACCEL_FULLSCALE		2
+	#define IIS2ICLX_DEFAULT_ACCEL_SENSITIVITY	(2.0 * GAIN_UNIT_XL)
+#elif CONFIG_IIS2ICLX_ACCEL_FS == 2000
+	#define IIS2ICLX_DEFAULT_ACCEL_FULLSCALE		3
+	#define IIS2ICLX_DEFAULT_ACCEL_SENSITIVITY	(4.0 * GAIN_UNIT_XL)
+#elif CONFIG_IIS2ICLX_ACCEL_FS == 3000
+	#define IIS2ICLX_DEFAULT_ACCEL_FULLSCALE		1
+	#define IIS2ICLX_DEFAULT_ACCEL_SENSITIVITY	(8.0 * GAIN_UNIT_XL)
+#endif
+
+#if (CONFIG_IIS2ICLX_ACCEL_ODR == 0)
+#define IIS2ICLX_ACCEL_ODR_RUNTIME 1
+#endif
+
+struct iis2iclx_config {
+	char *bus_name;
+	int (*bus_init)(const struct device *dev);
+#ifdef CONFIG_IIS2ICLX_TRIGGER
+	const char *int_gpio_port;
+	uint8_t int_gpio_pin;
+	uint8_t int_gpio_flags;
+	uint8_t int_pin;
+#endif /* CONFIG_IIS2ICLX_TRIGGER */
+#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
+	uint16_t i2c_slv_addr;
+#elif DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
+	struct spi_config spi_conf;
+#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
+	const char *gpio_cs_port;
+	uint8_t cs_gpio;
+	uint8_t cs_gpio_flags;
+#endif /* DT_INST_SPI_DEV_HAS_CS_GPIOS(0) */
+#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
+};
+
+/* sensor data forward declaration (member definition is below) */
+struct iis2iclx_data;
+
+struct iis2iclx_tf {
+	int (*read_data)(struct iis2iclx_data *data, uint8_t reg_addr,
+			 uint8_t *value, uint8_t len);
+	int (*write_data)(struct iis2iclx_data *data, uint8_t reg_addr,
+			  uint8_t *value, uint8_t len);
+	int (*read_reg)(struct iis2iclx_data *data, uint8_t reg_addr,
+			uint8_t *value);
+	int (*write_reg)(struct iis2iclx_data *data, uint8_t reg_addr,
+			uint8_t value);
+	int (*update_reg)(struct iis2iclx_data *data, uint8_t reg_addr,
+			  uint8_t mask, uint8_t value);
+};
+
+#define IIS2ICLX_SHUB_MAX_NUM_SLVS			2
+
+struct iis2iclx_data {
+	const struct device *dev;
+	const struct device *bus;
+	int16_t acc[2];
+	uint32_t acc_gain;
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+	int temp_sample;
+#endif
+#if defined(CONFIG_IIS2ICLX_SENSORHUB)
+	uint8_t ext_data[2][6];
+	uint16_t magn_gain;
+
+	struct hts221_data {
+		int16_t x0;
+		int16_t x1;
+		int16_t y0;
+		int16_t y1;
+	} hts221;
+#endif /* CONFIG_IIS2ICLX_SENSORHUB */
+
+	stmdev_ctx_t *ctx;
+
+	#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
+	stmdev_ctx_t ctx_i2c;
+	#elif DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
+	stmdev_ctx_t ctx_spi;
+	#endif
+
+	uint16_t accel_freq;
+	uint8_t accel_fs;
+
+#ifdef CONFIG_IIS2ICLX_TRIGGER
+	const struct device *gpio;
+	struct gpio_callback gpio_cb;
+	sensor_trigger_handler_t handler_drdy_acc;
+	sensor_trigger_handler_t handler_drdy_temp;
+
+#if defined(CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD)
+	K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_IIS2ICLX_THREAD_STACK_SIZE);
+	struct k_thread thread;
+	struct k_sem gpio_sem;
+#elif defined(CONFIG_IIS2ICLX_TRIGGER_GLOBAL_THREAD)
+	struct k_work work;
+#endif
+#endif /* CONFIG_IIS2ICLX_TRIGGER */
+
+#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
+	struct spi_cs_control cs_ctrl;
+#endif
+};
+
+int iis2iclx_spi_init(const struct device *dev);
+int iis2iclx_i2c_init(const struct device *dev);
+#if defined(CONFIG_IIS2ICLX_SENSORHUB)
+int iis2iclx_shub_init(const struct device *dev);
+int iis2iclx_shub_fetch_external_devs(const struct device *dev);
+int iis2iclx_shub_get_idx(enum sensor_channel type);
+int iis2iclx_shub_config(const struct device *dev, enum sensor_channel chan,
+			   enum sensor_attribute attr,
+			   const struct sensor_value *val);
+#endif /* CONFIG_IIS2ICLX_SENSORHUB */
+
+#ifdef CONFIG_IIS2ICLX_TRIGGER
+int iis2iclx_trigger_set(const struct device *dev,
+			   const struct sensor_trigger *trig,
+			   sensor_trigger_handler_t handler);
+
+int iis2iclx_init_interrupt(const struct device *dev);
+#endif
+
+#endif /* ZEPHYR_DRIVERS_SENSOR_IIS2ICLX_IIS2ICLX_H_ */
diff --git a/drivers/sensor/iis2iclx/iis2iclx_i2c.c b/drivers/sensor/iis2iclx/iis2iclx_i2c.c
new file mode 100644
index 0000000..19afe2a
--- /dev/null
+++ b/drivers/sensor/iis2iclx/iis2iclx_i2c.c
@@ -0,0 +1,53 @@
+/* ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
+ *
+ * Copyright (c) 2020 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Datasheet:
+ * https://www.st.com/resource/en/datasheet/iis2iclx.pdf
+ */
+
+#define DT_DRV_COMPAT st_iis2iclx
+
+#include <string.h>
+#include <drivers/i2c.h>
+#include <logging/log.h>
+
+#include "iis2iclx.h"
+
+#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
+
+LOG_MODULE_DECLARE(IIS2ICLX, CONFIG_SENSOR_LOG_LEVEL);
+
+static int iis2iclx_i2c_read(struct iis2iclx_data *data, uint8_t reg_addr,
+			       uint8_t *value, uint8_t len)
+{
+	const struct iis2iclx_config *cfg = data->dev->config;
+
+	return i2c_burst_read(data->bus, cfg->i2c_slv_addr,
+			      reg_addr, value, len);
+}
+
+static int iis2iclx_i2c_write(struct iis2iclx_data *data, uint8_t reg_addr,
+				uint8_t *value, uint8_t len)
+{
+	const struct iis2iclx_config *cfg = data->dev->config;
+
+	return i2c_burst_write(data->bus, cfg->i2c_slv_addr,
+			       reg_addr, value, len);
+}
+
+int iis2iclx_i2c_init(const struct device *dev)
+{
+	struct iis2iclx_data *data = dev->data;
+
+	data->ctx_i2c.read_reg = (stmdev_read_ptr) iis2iclx_i2c_read,
+	data->ctx_i2c.write_reg = (stmdev_write_ptr) iis2iclx_i2c_write,
+
+	data->ctx = &data->ctx_i2c;
+	data->ctx->handle = data;
+
+	return 0;
+}
+#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
diff --git a/drivers/sensor/iis2iclx/iis2iclx_shub.c b/drivers/sensor/iis2iclx/iis2iclx_shub.c
new file mode 100644
index 0000000..c7e3183
--- /dev/null
+++ b/drivers/sensor/iis2iclx/iis2iclx_shub.c
@@ -0,0 +1,793 @@
+/* ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
+ *
+ * Copyright (c) 2020 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Datasheet:
+ * https://www.st.com/resource/en/datasheet/iis2iclx.pdf
+ */
+
+#define DT_DRV_COMPAT st_iis2iclx
+
+#include <device.h>
+#include <drivers/i2c.h>
+#include <sys/byteorder.h>
+#include <sys/__assert.h>
+#include <sys/util.h>
+#include <kernel.h>
+#include <drivers/sensor.h>
+#include <logging/log.h>
+
+#include "iis2iclx.h"
+
+LOG_MODULE_DECLARE(IIS2ICLX, CONFIG_SENSOR_LOG_LEVEL);
+
+#define IIS2ICLX_SHUB_DATA_OUT				0x02
+
+#define IIS2ICLX_SHUB_SLV0_ADDR				0x15
+#define IIS2ICLX_SHUB_SLV0_SUBADDR			0x16
+#define IIS2ICLX_SHUB_SLV0_CONFIG			0x17
+#define IIS2ICLX_SHUB_SLV1_ADDR				0x18
+#define IIS2ICLX_SHUB_SLV1_SUBADDR			0x19
+#define IIS2ICLX_SHUB_SLV1_CONFIG			0x1A
+#define IIS2ICLX_SHUB_SLV2_ADDR				0x1B
+#define IIS2ICLX_SHUB_SLV2_SUBADDR			0x1C
+#define IIS2ICLX_SHUB_SLV2_CONFIG			0x1D
+#define IIS2ICLX_SHUB_SLV3_ADDR				0x1E
+#define IIS2ICLX_SHUB_SLV3_SUBADDR			0x1F
+#define IIS2ICLX_SHUB_SLV3_CONFIG			0x20
+#define IIS2ICLX_SHUB_SLV0_DATAWRITE			0x21
+
+#define IIS2ICLX_SHUB_STATUS_MASTER			0x22
+#define IIS2ICLX_SHUB_STATUS_SLV0_NACK			BIT(3)
+#define IIS2ICLX_SHUB_STATUS_ENDOP			BIT(0)
+
+#define IIS2ICLX_SHUB_SLVX_WRITE				0x0
+#define IIS2ICLX_SHUB_SLVX_READ				0x1
+
+static uint8_t num_ext_dev;
+static uint8_t shub_ext[IIS2ICLX_SHUB_MAX_NUM_SLVS];
+
+static int iis2iclx_shub_write_slave_reg(struct iis2iclx_data *data,
+					uint8_t slv_addr, uint8_t slv_reg,
+					uint8_t *value, uint16_t len);
+static int iis2iclx_shub_read_slave_reg(struct iis2iclx_data *data,
+				       uint8_t slv_addr, uint8_t slv_reg,
+				       uint8_t *value, uint16_t len);
+static void iis2iclx_shub_enable(struct iis2iclx_data *data, uint8_t enable);
+
+/*
+ * LIS2MDL magn device specific part
+ */
+#if defined(CONFIG_IIS2ICLX_EXT_LIS2MDL) || defined(CONFIG_IIS2ICLX_EXT_IIS2MDC)
+
+#define LIS2MDL_CFG_REG_A		0x60
+#define LIS2MDL_CFG_REG_B		0x61
+#define LIS2MDL_CFG_REG_C		0x62
+#define LIS2MDL_STATUS_REG		0x67
+
+#define LIS2MDL_SW_RESET		0x20
+#define LIS2MDL_ODR_10HZ		0x00
+#define LIS2MDL_ODR_100HZ		0x0C
+#define LIS2MDL_OFF_CANC		0x02
+#define LIS2MDL_SENSITIVITY		1500
+
+static int iis2iclx_lis2mdl_init(struct iis2iclx_data *data, uint8_t i2c_addr)
+{
+	uint8_t mag_cfg[2];
+
+	data->magn_gain = LIS2MDL_SENSITIVITY;
+
+	/* sw reset device */
+	mag_cfg[0] = LIS2MDL_SW_RESET;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LIS2MDL_CFG_REG_A, mag_cfg, 1);
+
+	k_sleep(K_MSEC(10)); /* turn-on time in ms */
+
+	/* configure mag */
+	mag_cfg[0] = LIS2MDL_ODR_10HZ;
+	mag_cfg[1] = LIS2MDL_OFF_CANC;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LIS2MDL_CFG_REG_A, mag_cfg, 2);
+
+	return 0;
+}
+
+static const uint16_t lis2mdl_map[] = {10, 20, 50, 100};
+
+static int iis2iclx_lis2mdl_odr_set(struct iis2iclx_data *data,
+				   uint8_t i2c_addr, uint16_t freq)
+{
+	uint8_t odr, cfg;
+
+	for (odr = 0; odr < ARRAY_SIZE(lis2mdl_map); odr++) {
+		if (freq == lis2mdl_map[odr]) {
+			break;
+		}
+	}
+
+	if (odr == ARRAY_SIZE(lis2mdl_map)) {
+		LOG_ERR("shub: LIS2MDL freq val %d not supported.", freq);
+		return -ENOTSUP;
+	}
+
+	cfg = (odr << 2);
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LIS2MDL_CFG_REG_A, &cfg, 1);
+
+	iis2iclx_shub_enable(data, 1);
+	return 0;
+}
+
+static int iis2iclx_lis2mdl_conf(struct iis2iclx_data *data, uint8_t i2c_addr,
+				enum sensor_channel chan,
+				enum sensor_attribute attr,
+				const struct sensor_value *val)
+{
+	switch (attr) {
+	case SENSOR_ATTR_SAMPLING_FREQUENCY:
+		return iis2iclx_lis2mdl_odr_set(data, i2c_addr, val->val1);
+	default:
+		LOG_ERR("shub: LIS2MDL attribute not supported.");
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IIS2ICLX_EXT_LIS2MDL || CONFIG_IIS2ICLX_EXT_IIS2MDC */
+
+/*
+ * HTS221 humidity device specific part
+ */
+#ifdef CONFIG_IIS2ICLX_EXT_HTS221
+
+#define HTS221_AUTOINCREMENT		BIT(7)
+
+#define HTS221_REG_CTRL1		0x20
+#define HTS221_ODR_1HZ			0x01
+#define HTS221_BDU			0x04
+#define HTS221_PD			0x80
+
+#define HTS221_REG_CONV_START		0x30
+
+static int lsmdso_hts221_read_conv_data(struct iis2iclx_data *data,
+					uint8_t i2c_addr)
+{
+	uint8_t buf[16], i;
+	struct hts221_data *ht = &data->hts221;
+
+	for (i = 0; i < sizeof(buf); i += 7) {
+		unsigned char len = MIN(7, sizeof(buf) - i);
+
+		if (iis2iclx_shub_read_slave_reg(data, i2c_addr,
+						(HTS221_REG_CONV_START + i) |
+						HTS221_AUTOINCREMENT,
+						&buf[i], len) < 0) {
+			LOG_ERR("shub: failed to read hts221 conv data");
+			return -EIO;
+		}
+	}
+
+	ht->y0 = buf[0] / 2;
+	ht->y1 = buf[1] / 2;
+	ht->x0 = sys_le16_to_cpu(buf[6] | (buf[7] << 8));
+	ht->x1 = sys_le16_to_cpu(buf[10] | (buf[11] << 8));
+
+	return 0;
+}
+
+static int iis2iclx_hts221_init(struct iis2iclx_data *data, uint8_t i2c_addr)
+{
+	uint8_t hum_cfg;
+
+	/* configure ODR and BDU */
+	hum_cfg = HTS221_ODR_1HZ | HTS221_BDU | HTS221_PD;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     HTS221_REG_CTRL1, &hum_cfg, 1);
+
+	return lsmdso_hts221_read_conv_data(data, i2c_addr);
+}
+
+static const uint16_t hts221_map[] = {0, 1, 7, 12};
+
+static int iis2iclx_hts221_odr_set(struct iis2iclx_data *data,
+				   uint8_t i2c_addr, uint16_t freq)
+{
+	uint8_t odr, cfg;
+
+	for (odr = 0; odr < ARRAY_SIZE(hts221_map); odr++) {
+		if (freq == hts221_map[odr]) {
+			break;
+		}
+	}
+
+	if (odr == ARRAY_SIZE(hts221_map)) {
+		LOG_ERR("shub: HTS221 freq val %d not supported.", freq);
+		return -ENOTSUP;
+	}
+
+	cfg = odr | HTS221_BDU | HTS221_PD;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     HTS221_REG_CTRL1, &cfg, 1);
+
+	iis2iclx_shub_enable(data, 1);
+	return 0;
+}
+
+static int iis2iclx_hts221_conf(struct iis2iclx_data *data, uint8_t i2c_addr,
+				enum sensor_channel chan,
+				enum sensor_attribute attr,
+				const struct sensor_value *val)
+{
+	switch (attr) {
+	case SENSOR_ATTR_SAMPLING_FREQUENCY:
+		return iis2iclx_hts221_odr_set(data, i2c_addr, val->val1);
+	default:
+		LOG_ERR("shub: HTS221 attribute not supported.");
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IIS2ICLX_EXT_HTS221 */
+
+/*
+ * LPS22HB baro/temp device specific part
+ */
+#ifdef CONFIG_IIS2ICLX_EXT_LPS22HB
+
+#define LPS22HB_CTRL_REG1		0x10
+#define LPS22HB_CTRL_REG2		0x11
+
+#define LPS22HB_SW_RESET		0x04
+#define LPS22HB_ODR_10HZ		0x20
+#define LPS22HB_LPF_EN			0x08
+#define LPS22HB_BDU_EN			0x02
+
+static int iis2iclx_lps22hb_init(struct iis2iclx_data *data, uint8_t i2c_addr)
+{
+	uint8_t baro_cfg[2];
+
+	/* sw reset device */
+	baro_cfg[0] = LPS22HB_SW_RESET;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LPS22HB_CTRL_REG2, baro_cfg, 1);
+
+	k_sleep(K_MSEC(1)); /* turn-on time in ms */
+
+	/* configure device */
+	baro_cfg[0] = LPS22HB_ODR_10HZ | LPS22HB_LPF_EN | LPS22HB_BDU_EN;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LPS22HB_CTRL_REG1, baro_cfg, 1);
+
+	return 0;
+}
+#endif /* CONFIG_IIS2ICLX_EXT_LPS22HB */
+
+/*
+ * LPS22HH baro/temp device specific part
+ */
+#ifdef CONFIG_IIS2ICLX_EXT_LPS22HH
+
+#define LPS22HH_CTRL_REG1		0x10
+#define LPS22HH_CTRL_REG2		0x11
+
+#define LPS22HH_SW_RESET		0x04
+#define LPS22HH_IF_ADD_INC		0x10
+#define LPS22HH_ODR_10HZ		0x20
+#define LPS22HH_LPF_EN			0x08
+#define LPS22HH_BDU_EN			0x02
+
+static int iis2iclx_lps22hh_init(struct iis2iclx_data *data, uint8_t i2c_addr)
+{
+	uint8_t baro_cfg[2];
+
+	/* sw reset device */
+	baro_cfg[0] = LPS22HH_SW_RESET;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LPS22HH_CTRL_REG2, baro_cfg, 1);
+
+	k_sleep(K_MSEC(100)); /* turn-on time in ms */
+
+	/* configure device */
+	baro_cfg[0] = LPS22HH_IF_ADD_INC;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LPS22HH_CTRL_REG2, baro_cfg, 1);
+
+	baro_cfg[0] = LPS22HH_ODR_10HZ | LPS22HH_LPF_EN | LPS22HH_BDU_EN;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LPS22HH_CTRL_REG1, baro_cfg, 1);
+
+	return 0;
+}
+
+static const uint16_t lps22hh_map[] = {0, 1, 10, 25, 50, 75, 100, 200};
+
+static int iis2iclx_lps22hh_odr_set(struct iis2iclx_data *data,
+				   uint8_t i2c_addr, uint16_t freq)
+{
+	uint8_t odr, cfg;
+
+	for (odr = 0; odr < ARRAY_SIZE(lps22hh_map); odr++) {
+		if (freq == lps22hh_map[odr]) {
+			break;
+		}
+	}
+
+	if (odr == ARRAY_SIZE(lps22hh_map)) {
+		LOG_ERR("shub: LPS22HH freq val %d not supported.", freq);
+		return -ENOTSUP;
+	}
+
+	cfg = (odr << 4) | LPS22HH_LPF_EN | LPS22HH_BDU_EN;
+	iis2iclx_shub_write_slave_reg(data, i2c_addr,
+				     LPS22HH_CTRL_REG1, &cfg, 1);
+
+	iis2iclx_shub_enable(data, 1);
+	return 0;
+}
+
+static int iis2iclx_lps22hh_conf(struct iis2iclx_data *data, uint8_t i2c_addr,
+				enum sensor_channel chan,
+				enum sensor_attribute attr,
+				const struct sensor_value *val)
+{
+	switch (attr) {
+	case SENSOR_ATTR_SAMPLING_FREQUENCY:
+		return iis2iclx_lps22hh_odr_set(data, i2c_addr, val->val1);
+	default:
+		LOG_ERR("shub: LPS22HH attribute not supported.");
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IIS2ICLX_EXT_LPS22HH */
+
+/* List of supported external sensors */
+static struct iis2iclx_shub_slist {
+	enum sensor_channel type;
+	uint8_t i2c_addr[2];
+	uint8_t ext_i2c_addr;
+	uint8_t wai_addr;
+	uint8_t wai_val;
+	uint8_t out_data_addr;
+	uint8_t out_data_len;
+	uint8_t sh_out_reg;
+	int (*dev_init)(struct iis2iclx_data *data, uint8_t i2c_addr);
+	int (*dev_conf)(struct iis2iclx_data *data, uint8_t i2c_addr,
+			enum sensor_channel chan, enum sensor_attribute attr,
+			const struct sensor_value *val);
+} iis2iclx_shub_slist[] = {
+#if defined(CONFIG_IIS2ICLX_EXT_LIS2MDL) || defined(CONFIG_IIS2ICLX_EXT_IIS2MDC)
+	{
+		/* LIS2MDL */
+		.type		= SENSOR_CHAN_MAGN_XYZ,
+		.i2c_addr       = { 0x1E },
+		.wai_addr       = 0x4F,
+		.wai_val        = 0x40,
+		.out_data_addr  = 0x68,
+		.out_data_len   = 0x06,
+		.dev_init       = (iis2iclx_lis2mdl_init),
+		.dev_conf       = (iis2iclx_lis2mdl_conf),
+	},
+#endif /* CONFIG_IIS2ICLX_EXT_LIS2MDL || CONFIG_IIS2ICLX_EXT_IIS2MDC */
+
+#ifdef CONFIG_IIS2ICLX_EXT_HTS221
+	{
+		/* HTS221 */
+		.type		= SENSOR_CHAN_HUMIDITY,
+		.i2c_addr       = { 0x5F },
+		.wai_addr       = 0x0F,
+		.wai_val        = 0xBC,
+		.out_data_addr  = 0x28 | HTS221_AUTOINCREMENT,
+		.out_data_len   = 0x02,
+		.dev_init       = (iis2iclx_hts221_init),
+		.dev_conf       = (iis2iclx_hts221_conf),
+	},
+#endif /* CONFIG_IIS2ICLX_EXT_HTS221 */
+
+#ifdef CONFIG_IIS2ICLX_EXT_LPS22HB
+	{
+		/* LPS22HB */
+		.type		= SENSOR_CHAN_PRESS,
+		.i2c_addr       = { 0x5C, 0x5D },
+		.wai_addr       = 0x0F,
+		.wai_val        = 0xB1,
+		.out_data_addr  = 0x28,
+		.out_data_len   = 0x05,
+		.dev_init       = (iis2iclx_lps22hb_init),
+	},
+#endif /* CONFIG_IIS2ICLX_EXT_LPS22HB */
+
+#ifdef CONFIG_IIS2ICLX_EXT_LPS22HH
+	{
+		/* LPS22HH */
+		.type		= SENSOR_CHAN_PRESS,
+		.i2c_addr       = { 0x5C, 0x5D },
+		.wai_addr       = 0x0F,
+		.wai_val        = 0xB3,
+		.out_data_addr  = 0x28,
+		.out_data_len   = 0x05,
+		.dev_init       = (iis2iclx_lps22hh_init),
+		.dev_conf       = (iis2iclx_lps22hh_conf),
+	},
+#endif /* CONFIG_IIS2ICLX_EXT_LPS22HH */
+};
+
+static inline void iis2iclx_shub_wait_completed(struct iis2iclx_data *data)
+{
+	iis2iclx_status_master_t status;
+
+	do {
+		k_msleep(1);
+		iis2iclx_sh_status_get(data->ctx, &status);
+	} while (status.sens_hub_endop == 0);
+}
+
+static inline void iis2iclx_shub_embedded_en(struct iis2iclx_data *data, bool on)
+{
+	if (on) {
+		(void) iis2iclx_mem_bank_set(data->ctx, IIS2ICLX_SENSOR_HUB_BANK);
+	} else {
+		(void) iis2iclx_mem_bank_set(data->ctx, IIS2ICLX_USER_BANK);
+	}
+
+	k_busy_wait(150);
+}
+
+static int iis2iclx_shub_read_embedded_regs(struct iis2iclx_data *data,
+					      uint8_t reg_addr,
+					      uint8_t *value, int len)
+{
+	iis2iclx_shub_embedded_en(data, true);
+
+	if (iis2iclx_read_reg(data->ctx, reg_addr, value, len) < 0) {
+		LOG_ERR("shub: failed to read external reg: %02x", reg_addr);
+		iis2iclx_shub_embedded_en(data, false);
+		return -EIO;
+	}
+
+	iis2iclx_shub_embedded_en(data, false);
+
+	return 0;
+}
+
+static int iis2iclx_shub_write_embedded_regs(struct iis2iclx_data *data,
+					       uint8_t reg_addr,
+					       uint8_t *value, uint8_t len)
+{
+	iis2iclx_shub_embedded_en(data, true);
+
+	if (iis2iclx_write_reg(data->ctx, reg_addr, value, len) < 0) {
+		LOG_ERR("shub: failed to write external reg: %02x", reg_addr);
+		iis2iclx_shub_embedded_en(data, false);
+		return -EIO;
+	}
+
+	iis2iclx_shub_embedded_en(data, false);
+
+	return 0;
+}
+
+static void iis2iclx_shub_enable(struct iis2iclx_data *data, uint8_t enable)
+{
+	/* Enable Accel @26hz */
+	if (!data->accel_freq) {
+		uint8_t odr = (enable) ? 2 : 0;
+
+		if (iis2iclx_xl_data_rate_set(data->ctx, odr) < 0) {
+			LOG_DBG("shub: failed to set XL sampling rate");
+			return;
+		}
+	}
+
+	iis2iclx_shub_embedded_en(data, true);
+
+	if (iis2iclx_sh_master_set(data->ctx, enable) < 0) {
+		LOG_DBG("shub: failed to set master on");
+		iis2iclx_shub_embedded_en(data, false);
+		return;
+	}
+
+	iis2iclx_shub_embedded_en(data, false);
+}
+
+/* must be called with master on */
+static int iis2iclx_shub_check_slv0_nack(struct iis2iclx_data *data)
+{
+	uint8_t status;
+
+	if (iis2iclx_shub_read_embedded_regs(data, IIS2ICLX_SHUB_STATUS_MASTER,
+					       &status, 1) < 0) {
+		LOG_ERR("shub: error reading embedded reg");
+		return -EIO;
+	}
+
+	if (status & (IIS2ICLX_SHUB_STATUS_SLV0_NACK)) {
+		LOG_ERR("shub: SLV0 nacked");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * use SLV0 for generic read to slave device
+ */
+static int iis2iclx_shub_read_slave_reg(struct iis2iclx_data *data,
+					  uint8_t slv_addr, uint8_t slv_reg,
+					  uint8_t *value, uint16_t len)
+{
+	uint8_t slave[3];
+
+	slave[0] = (slv_addr << 1) | IIS2ICLX_SHUB_SLVX_READ;
+	slave[1] = slv_reg;
+	slave[2] = (len & 0x7);
+
+	if (iis2iclx_shub_write_embedded_regs(data, IIS2ICLX_SHUB_SLV0_ADDR,
+						slave, 3) < 0) {
+		LOG_ERR("shub: error writing embedded reg");
+		return -EIO;
+	}
+
+	/* turn SH on */
+	iis2iclx_shub_enable(data, 1);
+	iis2iclx_shub_wait_completed(data);
+
+	if (iis2iclx_shub_check_slv0_nack(data) < 0) {
+		iis2iclx_shub_enable(data, 0);
+		return -EIO;
+	}
+
+	/* read data from external slave */
+	iis2iclx_shub_embedded_en(data, true);
+	if (iis2iclx_read_reg(data->ctx, IIS2ICLX_SHUB_DATA_OUT,
+				value, len) < 0) {
+		LOG_ERR("shub: error reading sensor data");
+		iis2iclx_shub_embedded_en(data, false);
+		return -EIO;
+	}
+	iis2iclx_shub_embedded_en(data, false);
+
+	iis2iclx_shub_enable(data, 0);
+	return 0;
+}
+
+/*
+ * use SLV0 to configure slave device
+ */
+static int iis2iclx_shub_write_slave_reg(struct iis2iclx_data *data,
+					   uint8_t slv_addr, uint8_t slv_reg,
+					   uint8_t *value, uint16_t len)
+{
+	uint8_t slv_cfg[3];
+	uint8_t cnt = 0U;
+
+	while (cnt < len) {
+		slv_cfg[0] = (slv_addr << 1) & ~IIS2ICLX_SHUB_SLVX_READ;
+		slv_cfg[1] = slv_reg + cnt;
+
+		if (iis2iclx_shub_write_embedded_regs(data,
+							IIS2ICLX_SHUB_SLV0_ADDR,
+							slv_cfg, 2) < 0) {
+			LOG_ERR("shub: error writing embedded reg");
+			return -EIO;
+		}
+
+		slv_cfg[0] = value[cnt];
+		if (iis2iclx_shub_write_embedded_regs(data,
+					IIS2ICLX_SHUB_SLV0_DATAWRITE,
+					slv_cfg, 1) < 0) {
+			LOG_ERR("shub: error writing embedded reg");
+			return -EIO;
+		}
+
+		/* turn SH on */
+		iis2iclx_shub_enable(data, 1);
+		iis2iclx_shub_wait_completed(data);
+
+		if (iis2iclx_shub_check_slv0_nack(data) < 0) {
+			iis2iclx_shub_enable(data, 0);
+			return -EIO;
+		}
+
+		iis2iclx_shub_enable(data, 0);
+
+		cnt++;
+	}
+
+	/* Put SLV0 in IDLE mode */
+	slv_cfg[0] = 0x7;
+	slv_cfg[1] = 0x0;
+	slv_cfg[2] = 0x0;
+	if (iis2iclx_shub_write_embedded_regs(data, IIS2ICLX_SHUB_SLV0_ADDR,
+						slv_cfg, 3) < 0) {
+		LOG_ERR("shub: error writing embedded reg");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * SLAVEs configurations:
+ *
+ *  - SLAVE 0: used for configuring all slave devices
+ *  - SLAVE 1: used as data read channel for external slave device #1
+ *  - SLAVE 2: used as data read channel for external slave device #2
+ *  - SLAVE 3: used for generic reads while data channel is enabled
+ */
+static int iis2iclx_shub_set_data_channel(struct iis2iclx_data *data)
+{
+	uint8_t n, i, slv_cfg[6];
+	struct iis2iclx_shub_slist *sp;
+
+	/* Set data channel for slave devices */
+	for (n = 0; n < num_ext_dev; n++) {
+		sp = &iis2iclx_shub_slist[shub_ext[n]];
+
+		i = n * 3;
+		slv_cfg[i] = (sp->ext_i2c_addr << 1) | IIS2ICLX_SHUB_SLVX_READ;
+		slv_cfg[i + 1] = sp->out_data_addr;
+		slv_cfg[i + 2] = sp->out_data_len;
+	}
+
+	if (iis2iclx_shub_write_embedded_regs(data,
+						IIS2ICLX_SHUB_SLV1_ADDR,
+						slv_cfg, n*3) < 0) {
+		LOG_ERR("shub: error writing embedded reg");
+		return -EIO;
+	}
+
+	/* Configure the master */
+	iis2iclx_aux_sens_on_t aux = IIS2ICLX_SLV_0_1_2;
+
+	if (iis2iclx_sh_slave_connected_set(data->ctx, aux) < 0) {
+		LOG_ERR("shub: error setting aux sensors");
+		return -EIO;
+	}
+
+	iis2iclx_write_once_t wo = IIS2ICLX_ONLY_FIRST_CYCLE;
+
+	if (iis2iclx_sh_write_mode_set(data->ctx, wo) < 0) {
+		LOG_ERR("shub: error setting write once");
+		return -EIO;
+	}
+
+
+	/* turn SH on */
+	iis2iclx_shub_enable(data, 1);
+	iis2iclx_shub_wait_completed(data);
+
+	return 0;
+}
+
+int iis2iclx_shub_get_idx(enum sensor_channel type)
+{
+	uint8_t n;
+	struct iis2iclx_shub_slist *sp;
+
+	for (n = 0; n < num_ext_dev; n++) {
+		sp = &iis2iclx_shub_slist[shub_ext[n]];
+
+		if (sp->type == type)
+			return n;
+	}
+
+	return -ENOTSUP;
+}
+
+int iis2iclx_shub_fetch_external_devs(const struct device *dev)
+{
+	uint8_t n;
+	struct iis2iclx_data *data = dev->data;
+	struct iis2iclx_shub_slist *sp;
+
+	/* read data from external slave */
+	iis2iclx_shub_embedded_en(data, true);
+
+	for (n = 0; n < num_ext_dev; n++) {
+		sp = &iis2iclx_shub_slist[shub_ext[n]];
+
+		if (iis2iclx_read_reg(data->ctx, sp->sh_out_reg,
+				     data->ext_data[n], sp->out_data_len) < 0) {
+			LOG_ERR("shub: failed to read sample");
+			iis2iclx_shub_embedded_en(data, false);
+			return -EIO;
+		}
+	}
+
+	iis2iclx_shub_embedded_en(data, false);
+
+	return 0;
+}
+
+int iis2iclx_shub_config(const struct device *dev, enum sensor_channel chan,
+			   enum sensor_attribute attr,
+			   const struct sensor_value *val)
+{
+	struct iis2iclx_data *data = dev->data;
+	struct iis2iclx_shub_slist *sp = NULL;
+	uint8_t n;
+
+	for (n = 0; n < num_ext_dev; n++) {
+		sp = &iis2iclx_shub_slist[shub_ext[n]];
+
+		if (sp->type == chan)
+			break;
+	}
+
+	if (n == num_ext_dev) {
+		LOG_ERR("shub: chan not supported");
+		return -ENOTSUP;
+	}
+
+	if (sp == NULL || sp->dev_conf == NULL) {
+		LOG_ERR("shub: chan not configurable");
+		return -ENOTSUP;
+	}
+
+	return sp->dev_conf(data, sp->ext_i2c_addr, chan, attr, val);
+}
+
+int iis2iclx_shub_init(const struct device *dev)
+{
+	struct iis2iclx_data *data = dev->data;
+	uint8_t i, n = 0, regn;
+	uint8_t chip_id;
+	struct iis2iclx_shub_slist *sp;
+
+	for (n = 0; n < ARRAY_SIZE(iis2iclx_shub_slist); n++) {
+		if (num_ext_dev >= IIS2ICLX_SHUB_MAX_NUM_SLVS)
+			break;
+
+		chip_id = 0;
+		sp = &iis2iclx_shub_slist[n];
+
+		/*
+		 * The external sensor may have different I2C address.
+		 * So, try them one by one until we read the correct
+		 * chip ID.
+		 */
+		for (i = 0U; i < ARRAY_SIZE(sp->i2c_addr); i++) {
+			if (iis2iclx_shub_read_slave_reg(data,
+							   sp->i2c_addr[i],
+							   sp->wai_addr,
+							   &chip_id, 1) < 0) {
+				continue;
+			}
+			if (chip_id == sp->wai_val) {
+				break;
+			}
+		}
+
+		if (i >= ARRAY_SIZE(sp->i2c_addr)) {
+			LOG_DBG("shub: invalid chip id 0x%x", chip_id);
+			continue;
+		}
+		LOG_INF("shub: Ext Device Chip Id: 0x%02x", chip_id);
+		sp->ext_i2c_addr = sp->i2c_addr[i];
+
+		shub_ext[num_ext_dev++] = n;
+	}
+
+	if (num_ext_dev == 0) {
+		LOG_ERR("shub: no slave devices found");
+		return -EINVAL;
+	}
+
+	/* init external devices */
+	for (n = 0, regn = 0; n < num_ext_dev; n++) {
+		sp = &iis2iclx_shub_slist[shub_ext[n]];
+		sp->sh_out_reg = IIS2ICLX_SHUB_DATA_OUT + regn;
+		regn += sp->out_data_len;
+		sp->dev_init(data, sp->ext_i2c_addr);
+	}
+
+	iis2iclx_shub_set_data_channel(data);
+
+	return 0;
+}
diff --git a/drivers/sensor/iis2iclx/iis2iclx_spi.c b/drivers/sensor/iis2iclx/iis2iclx_spi.c
new file mode 100644
index 0000000..0c8d895
--- /dev/null
+++ b/drivers/sensor/iis2iclx/iis2iclx_spi.c
@@ -0,0 +1,127 @@
+/* ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
+ *
+ * Copyright (c) 2020 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Datasheet:
+ * https://www.st.com/resource/en/datasheet/iis2iclx.pdf
+ */
+
+#define DT_DRV_COMPAT st_iis2iclx
+
+#include <string.h>
+#include "iis2iclx.h"
+#include <logging/log.h>
+
+#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
+
+#define IIS2ICLX_SPI_READ		(1 << 7)
+
+LOG_MODULE_DECLARE(IIS2ICLX, CONFIG_SENSOR_LOG_LEVEL);
+
+static int iis2iclx_spi_read(struct iis2iclx_data *data, uint8_t reg_addr,
+			       uint8_t *value, uint8_t len)
+{
+	const struct iis2iclx_config *cfg = data->dev->config;
+	const struct spi_config *spi_cfg = &cfg->spi_conf;
+	uint8_t buffer_tx[2] = { reg_addr | IIS2ICLX_SPI_READ, 0 };
+	const struct spi_buf tx_buf = {
+			.buf = buffer_tx,
+			.len = 2,
+	};
+	const struct spi_buf_set tx = {
+		.buffers = &tx_buf,
+		.count = 1
+	};
+	const struct spi_buf rx_buf[2] = {
+		{
+			.buf = NULL,
+			.len = 1,
+		},
+		{
+			.buf = value,
+			.len = len,
+		}
+	};
+	const struct spi_buf_set rx = {
+		.buffers = rx_buf,
+		.count = 2
+	};
+
+
+	if (len > 64) {
+		return -EIO;
+	}
+
+	if (spi_transceive(data->bus, spi_cfg, &tx, &rx)) {
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int iis2iclx_spi_write(struct iis2iclx_data *data, uint8_t reg_addr,
+				uint8_t *value, uint8_t len)
+{
+	const struct iis2iclx_config *cfg = data->dev->config;
+	const struct spi_config *spi_cfg = &cfg->spi_conf;
+	uint8_t buffer_tx[1] = { reg_addr & ~IIS2ICLX_SPI_READ };
+	const struct spi_buf tx_buf[2] = {
+		{
+			.buf = buffer_tx,
+			.len = 1,
+		},
+		{
+			.buf = value,
+			.len = len,
+		}
+	};
+	const struct spi_buf_set tx = {
+		.buffers = tx_buf,
+		.count = 2
+	};
+
+
+	if (len > 64) {
+		return -EIO;
+	}
+
+	if (spi_write(data->bus, spi_cfg, &tx)) {
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int iis2iclx_spi_init(const struct device *dev)
+{
+	struct iis2iclx_data *data = dev->data;
+
+	data->ctx_spi.read_reg = (stmdev_read_ptr) iis2iclx_spi_read,
+	data->ctx_spi.write_reg = (stmdev_write_ptr) iis2iclx_spi_write,
+
+	data->ctx = &data->ctx_spi;
+	data->ctx->handle = data;
+
+#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
+	const struct iis2iclx_config *cfg = dev->config;
+
+	/* handle SPI CS thru GPIO if it is the case */
+	data->cs_ctrl.gpio_dev = device_get_binding(cfg->gpio_cs_port);
+	if (!data->cs_ctrl.gpio_dev) {
+		LOG_ERR("Unable to get GPIO SPI CS device");
+		return -ENODEV;
+	}
+
+	data->cs_ctrl.gpio_pin = cfg->cs_gpio;
+	data->cs_ctrl.gpio_dt_flags = cfg->cs_gpio_flags;
+	data->cs_ctrl.delay = 0;
+
+	LOG_DBG("SPI GPIO CS configured on %s:%u",
+		cfg->gpio_cs_port, cfg->cs_gpio);
+#endif
+
+	return 0;
+}
+#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
diff --git a/drivers/sensor/iis2iclx/iis2iclx_trigger.c b/drivers/sensor/iis2iclx/iis2iclx_trigger.c
new file mode 100644
index 0000000..3e1f23a
--- /dev/null
+++ b/drivers/sensor/iis2iclx/iis2iclx_trigger.c
@@ -0,0 +1,250 @@
+/* ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
+ *
+ * Copyright (c) 2020 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Datasheet:
+ * https://www.st.com/resource/en/datasheet/iis2iclx.pdf
+ */
+
+#define DT_DRV_COMPAT st_iis2iclx
+
+#include <kernel.h>
+#include <drivers/sensor.h>
+#include <drivers/gpio.h>
+#include <logging/log.h>
+
+#include "iis2iclx.h"
+
+LOG_MODULE_DECLARE(IIS2ICLX, CONFIG_SENSOR_LOG_LEVEL);
+
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+/**
+ * iis2iclx_enable_t_int - TEMP enable selected int pin to generate interrupt
+ */
+static int iis2iclx_enable_t_int(const struct device *dev, int enable)
+{
+	const struct iis2iclx_config *cfg = dev->config;
+	struct iis2iclx_data *iis2iclx = dev->data;
+	iis2iclx_pin_int2_route_t int2_route;
+
+	if (enable) {
+		int16_t buf;
+
+		/* dummy read: re-trigger interrupt */
+		iis2iclx_temperature_raw_get(iis2iclx->ctx, &buf);
+	}
+
+	/* set interrupt (TEMP DRDY interrupt is only on INT2) */
+	if (cfg->int_pin == 1)
+		return -EIO;
+
+	iis2iclx_read_reg(iis2iclx->ctx, IIS2ICLX_INT2_CTRL,
+			    (uint8_t *)&int2_route.int2_ctrl, 1);
+	int2_route.int2_ctrl.int2_drdy_temp = enable;
+	return iis2iclx_write_reg(iis2iclx->ctx, IIS2ICLX_INT2_CTRL,
+				    (uint8_t *)&int2_route.int2_ctrl, 1);
+}
+#endif
+
+/**
+ * iis2iclx_enable_xl_int - XL enable selected int pin to generate interrupt
+ */
+static int iis2iclx_enable_xl_int(const struct device *dev, int enable)
+{
+	const struct iis2iclx_config *cfg = dev->config;
+	struct iis2iclx_data *iis2iclx = dev->data;
+
+	if (enable) {
+		int16_t buf[3];
+
+		/* dummy read: re-trigger interrupt */
+		iis2iclx_acceleration_raw_get(iis2iclx->ctx, buf);
+	}
+
+	/* set interrupt */
+	if (cfg->int_pin == 1) {
+		iis2iclx_pin_int1_route_t int1_route;
+
+		iis2iclx_read_reg(iis2iclx->ctx, IIS2ICLX_INT1_CTRL,
+				    (uint8_t *)&int1_route.int1_ctrl, 1);
+
+		int1_route.int1_ctrl.int1_drdy_xl = enable;
+		return iis2iclx_write_reg(iis2iclx->ctx, IIS2ICLX_INT1_CTRL,
+					    (uint8_t *)&int1_route.int1_ctrl, 1);
+	} else {
+		iis2iclx_pin_int2_route_t int2_route;
+
+		iis2iclx_read_reg(iis2iclx->ctx, IIS2ICLX_INT2_CTRL,
+				    (uint8_t *)&int2_route.int2_ctrl, 1);
+		int2_route.int2_ctrl.int2_drdy_xl = enable;
+		return iis2iclx_write_reg(iis2iclx->ctx, IIS2ICLX_INT2_CTRL,
+					    (uint8_t *)&int2_route.int2_ctrl, 1);
+	}
+}
+
+/**
+ * iis2iclx_trigger_set - link external trigger to event data ready
+ */
+int iis2iclx_trigger_set(const struct device *dev,
+			   const struct sensor_trigger *trig,
+			   sensor_trigger_handler_t handler)
+{
+	struct iis2iclx_data *iis2iclx = dev->data;
+
+	if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) {
+		iis2iclx->handler_drdy_acc = handler;
+		if (handler) {
+			return iis2iclx_enable_xl_int(dev, IIS2ICLX_EN_BIT);
+		} else {
+			return iis2iclx_enable_xl_int(dev, IIS2ICLX_DIS_BIT);
+		}
+	}
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+	else if (trig->chan == SENSOR_CHAN_DIE_TEMP) {
+		iis2iclx->handler_drdy_temp = handler;
+		if (handler) {
+			return iis2iclx_enable_t_int(dev, IIS2ICLX_EN_BIT);
+		} else {
+			return iis2iclx_enable_t_int(dev, IIS2ICLX_DIS_BIT);
+		}
+	}
+#endif
+
+	return -ENOTSUP;
+}
+
+/**
+ * iis2iclx_handle_interrupt - handle the drdy event
+ * read data and call handler if registered any
+ */
+static void iis2iclx_handle_interrupt(const struct device *dev)
+{
+	struct iis2iclx_data *iis2iclx = dev->data;
+	struct sensor_trigger drdy_trigger = {
+		.type = SENSOR_TRIG_DATA_READY,
+	};
+	const struct iis2iclx_config *cfg = dev->config;
+	iis2iclx_status_reg_t status;
+
+	while (1) {
+		if (iis2iclx_status_reg_get(iis2iclx->ctx, &status) < 0) {
+			LOG_DBG("failed reading status reg");
+			return;
+		}
+
+		if ((status.xlda == 0)
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+					&& (status.tda == 0)
+#endif
+					) {
+			break;
+		}
+
+		if ((status.xlda) && (iis2iclx->handler_drdy_acc != NULL)) {
+			iis2iclx->handler_drdy_acc(dev, &drdy_trigger);
+		}
+
+#if defined(CONFIG_IIS2ICLX_ENABLE_TEMP)
+		if ((status.tda) && (iis2iclx->handler_drdy_temp != NULL)) {
+			iis2iclx->handler_drdy_temp(dev, &drdy_trigger);
+		}
+#endif
+	}
+
+	gpio_pin_interrupt_configure(iis2iclx->gpio, cfg->int_gpio_pin,
+				     GPIO_INT_EDGE_TO_ACTIVE);
+}
+
+static void iis2iclx_gpio_callback(const struct device *dev,
+				     struct gpio_callback *cb, uint32_t pins)
+{
+	struct iis2iclx_data *iis2iclx =
+		CONTAINER_OF(cb, struct iis2iclx_data, gpio_cb);
+	const struct iis2iclx_config *cfg = iis2iclx->dev->config;
+
+	ARG_UNUSED(pins);
+
+	gpio_pin_interrupt_configure(iis2iclx->gpio, cfg->int_gpio_pin,
+				     GPIO_INT_DISABLE);
+
+#if defined(CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD)
+	k_sem_give(&iis2iclx->gpio_sem);
+#elif defined(CONFIG_IIS2ICLX_TRIGGER_GLOBAL_THREAD)
+	k_work_submit(&iis2iclx->work);
+#endif /* CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD */
+}
+
+#ifdef CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD
+static void iis2iclx_thread(struct iis2iclx_data *iis2iclx)
+{
+	while (1) {
+		k_sem_take(&iis2iclx->gpio_sem, K_FOREVER);
+		iis2iclx_handle_interrupt(iis2iclx->dev);
+	}
+}
+#endif /* CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD */
+
+#ifdef CONFIG_IIS2ICLX_TRIGGER_GLOBAL_THREAD
+static void iis2iclx_work_cb(struct k_work *work)
+{
+	struct iis2iclx_data *iis2iclx =
+		CONTAINER_OF(work, struct iis2iclx_data, work);
+
+	iis2iclx_handle_interrupt(iis2iclx->dev);
+}
+#endif /* CONFIG_IIS2ICLX_TRIGGER_GLOBAL_THREAD */
+
+int iis2iclx_init_interrupt(const struct device *dev)
+{
+	struct iis2iclx_data *iis2iclx = dev->data;
+	const struct iis2iclx_config *cfg = dev->config;
+	int ret;
+
+	/* setup data ready gpio interrupt (INT1 or INT2) */
+	iis2iclx->gpio = device_get_binding(cfg->int_gpio_port);
+	if (iis2iclx->gpio == NULL) {
+		LOG_ERR("Cannot get pointer to %s device", cfg->int_gpio_port);
+		return -EINVAL;
+	}
+
+#if defined(CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD)
+	k_sem_init(&iis2iclx->gpio_sem, 0, UINT_MAX);
+
+	k_thread_create(&iis2iclx->thread, iis2iclx->thread_stack,
+			CONFIG_IIS2ICLX_THREAD_STACK_SIZE,
+			(k_thread_entry_t)iis2iclx_thread,
+			iis2iclx, NULL, NULL,
+			K_PRIO_COOP(CONFIG_IIS2ICLX_THREAD_PRIORITY),
+			0, K_NO_WAIT);
+#elif defined(CONFIG_IIS2ICLX_TRIGGER_GLOBAL_THREAD)
+	iis2iclx->work.handler = iis2iclx_work_cb;
+#endif /* CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD */
+
+	ret = gpio_pin_configure(iis2iclx->gpio, cfg->int_gpio_pin,
+				 GPIO_INPUT | cfg->int_gpio_flags);
+	if (ret < 0) {
+		LOG_ERR("Could not configure gpio");
+		return ret;
+	}
+
+	gpio_init_callback(&iis2iclx->gpio_cb,
+			   iis2iclx_gpio_callback,
+			   BIT(cfg->int_gpio_pin));
+
+	if (gpio_add_callback(iis2iclx->gpio, &iis2iclx->gpio_cb) < 0) {
+		LOG_ERR("Could not set gpio callback");
+		return -EIO;
+	}
+
+	/* enable interrupt on int1/int2 in pulse mode */
+	if (iis2iclx_int_notification_set(iis2iclx->ctx,
+					    IIS2ICLX_ALL_INT_PULSED) < 0) {
+		LOG_ERR("Could not set pulse mode");
+		return -EIO;
+	}
+
+	return gpio_pin_interrupt_configure(iis2iclx->gpio, cfg->int_gpio_pin,
+					    GPIO_INT_EDGE_TO_ACTIVE);
+}
diff --git a/dts/bindings/sensor/st,iis2iclx-i2c.yaml b/dts/bindings/sensor/st,iis2iclx-i2c.yaml
new file mode 100644
index 0000000..e1b04a7
--- /dev/null
+++ b/dts/bindings/sensor/st,iis2iclx-i2c.yaml
@@ -0,0 +1,20 @@
+# Copyright (c) 2020 STMicroelectronics
+# SPDX-License-Identifier: Apache-2.0
+
+description: |
+    STMicroelectronics IIS2ICLX 2-axis accelerometer sensor
+    accessed through I2C bus
+
+compatible: "st,iis2iclx"
+
+include: i2c-device.yaml
+
+properties:
+    drdy-gpios:
+      type: phandle-array
+      required: false
+      description: DRDY pin
+
+        This pin defaults to active high when produced by the sensor.
+        The property value should ensure the flags properly describe
+        the signal that is presented to the driver.
diff --git a/dts/bindings/sensor/st,iis2iclx-spi.yaml b/dts/bindings/sensor/st,iis2iclx-spi.yaml
new file mode 100644
index 0000000..0965142
--- /dev/null
+++ b/dts/bindings/sensor/st,iis2iclx-spi.yaml
@@ -0,0 +1,20 @@
+# Copyright (c) 2020 STMicroelectronics
+# SPDX-License-Identifier: Apache-2.0
+
+description: |
+    STMicroelectronics IIS2ICLX 2-axis accelerometer sensor
+    accessed through SPI bus
+
+compatible: "st,iis2iclx"
+
+include: spi-device.yaml
+
+properties:
+    drdy-gpios:
+      type: phandle-array
+      required: false
+      description: DRDY pin
+
+        This pin defaults to active high when produced by the sensor.
+        The property value should ensure the flags properly describe
+        the signal that is presented to the driver.
diff --git a/tests/drivers/build_all/app.overlay b/tests/drivers/build_all/app.overlay
index e7893cd..be52749 100644
--- a/tests/drivers/build_all/app.overlay
+++ b/tests/drivers/build_all/app.overlay
@@ -195,6 +195,11 @@
 };
 
 /* disable device to conflict with i2c version */
+&test_spi_iis2iclx {
+	status = "disabled";
+};
+
+/* disable device to conflict with i2c version */
 &test_spi_iis2mdc {
 	status = "disabled";
 };
diff --git a/tests/drivers/build_all/i2c.dtsi b/tests/drivers/build_all/i2c.dtsi
index 06fe2d6..2e1023f 100644
--- a/tests/drivers/build_all/i2c.dtsi
+++ b/tests/drivers/build_all/i2c.dtsi
@@ -543,6 +543,13 @@
 	drdy-gpios = <&test_gpio 0 0>;
 };
 
+test_i2c_iis2iclx: iis2iclx@6a {
+	compatible = "st,iis2iclx";
+	label = "IIS2ICLX";
+	reg = <0x6a>;
+	drdy-gpios = <&test_gpio 0 0>;
+};
+
 test_i2c_itds: itds@18 {
 	compatible = "we,wsen-itds";
 	label = "WSEN-ITDS";
diff --git a/tests/drivers/build_all/sensors_stmemsc.conf b/tests/drivers/build_all/sensors_stmemsc.conf
index 0e34e30..977ed07 100644
--- a/tests/drivers/build_all/sensors_stmemsc.conf
+++ b/tests/drivers/build_all/sensors_stmemsc.conf
@@ -10,4 +10,5 @@
 CONFIG_STTS751=y
 CONFIG_ISM330DHCX=y
 CONFIG_IIS2DH=y
+CONFIG_IIS2ICLX=y
 CONFIG_IIS2MDC=y
diff --git a/tests/drivers/build_all/sensors_stmemsc_trigger.conf b/tests/drivers/build_all/sensors_stmemsc_trigger.conf
index 75299d6..5712c08 100644
--- a/tests/drivers/build_all/sensors_stmemsc_trigger.conf
+++ b/tests/drivers/build_all/sensors_stmemsc_trigger.conf
@@ -15,5 +15,7 @@
 CONFIG_ISM330DHCX_TRIGGER_OWN_THREAD=y
 CONFIG_IIS2DH=y
 CONFIG_IIS2DH_TRIGGER_OWN_THREAD=y
+CONFIG_IIS2ICLX=y
+CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD=y
 CONFIG_IIS2MDC=y
 CONFIG_IIS2MDC_TRIGGER_OWN_THREAD=y
diff --git a/tests/drivers/build_all/spi.dtsi b/tests/drivers/build_all/spi.dtsi
index 3175f5e..e69ea10 100644
--- a/tests/drivers/build_all/spi.dtsi
+++ b/tests/drivers/build_all/spi.dtsi
@@ -551,3 +551,11 @@
 	int-gpios = <&test_gpio 0 0>;
 	reset-gpios = <&test_gpio 0 0>;
 };
+
+test_spi_iis2iclx: iis2iclx@37 {
+	compatible = "st,iis2iclx";
+	label = "IIS2ICLX";
+	reg = <0x37>;
+	spi-max-frequency = <0>;
+	drdy-gpios = <&test_gpio 0 0>;
+};