v4.19.13 snapshot.
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
new file mode 100644
index 0000000..1a0d458
--- /dev/null
+++ b/drivers/iio/humidity/Kconfig
@@ -0,0 +1,113 @@
+#
+# humidity sensor drivers
+#
+menu "Humidity sensors"
+
+config AM2315
+    tristate "Aosong AM2315 relative humidity and temperature sensor"
+    depends on I2C
+    select IIO_BUFFER
+    select IIO_TRIGGERED_BUFFER
+    help
+      If you say yes here you get support for the Aosong AM2315
+      relative humidity and ambient temperature sensor.
+
+      This driver can also be built as a module. If so, the module will
+      be called am2315.
+
+config DHT11
+	tristate "DHT11 (and compatible sensors) driver"
+	depends on GPIOLIB || COMPILE_TEST
+	help
+	  This driver supports reading data via a single interrupt
+	  generating GPIO line. Currently tested are DHT11 and DHT22.
+	  Other sensors should work as well as long as they speak the
+	  same protocol.
+
+config HDC100X
+	tristate "TI HDC100x relative humidity and temperature sensor"
+	depends on I2C
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for the Texas Instruments
+	  HDC1000, HDC1008, HDC1010, HDC1050, and HDC1080 relative
+	  humidity and temperature sensors.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called hdc100x.
+
+config HID_SENSOR_HUMIDITY
+	tristate "HID Environmental humidity sensor"
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	select HID_SENSOR_IIO_TRIGGER
+	help
+	  Say yes here to build support for the HID SENSOR
+	  humidity driver
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called hid-sensor-humidity.
+
+config HTS221
+	tristate "STMicroelectronics HTS221 sensor Driver"
+	depends on (I2C || SPI)
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HTS221_I2C if (I2C)
+	select HTS221_SPI if (SPI_MASTER)
+	help
+	  Say yes here to build support for STMicroelectronics HTS221
+	  temperature-humidity sensor
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called hts221.
+
+config HTS221_I2C
+	tristate
+	depends on HTS221
+	select REGMAP_I2C
+
+config HTS221_SPI
+	tristate
+	depends on HTS221
+	select REGMAP_SPI
+
+config HTU21
+	tristate "Measurement Specialties HTU21 humidity & temperature sensor"
+	depends on I2C
+        select IIO_MS_SENSORS_I2C
+	help
+	  If you say yes here you get support for the Measurement Specialties
+	  HTU21 humidity and temperature sensor.
+	  This driver is also used for MS8607 temperature, pressure & humidity
+	  sensor
+
+	  This driver can also be built as a module. If so, the module will
+	  be called htu21.
+
+config SI7005
+	tristate "SI7005 relative humidity and temperature sensor"
+	depends on I2C
+	help
+	  Say yes here to build support for the Silabs Si7005 relative
+	  humidity and temperature sensor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called si7005. This driver also
+	  supports Hoperf TH02 Humidity and Temperature Sensor.
+
+config SI7020
+	tristate "Si7013/20/21 Relative Humidity and Temperature Sensors"
+	depends on I2C
+	help
+	  Say yes here to build support for the Silicon Labs Si7013/20/21
+	  Relative Humidity and Temperature Sensors. This driver also
+	  supports Hoperf TH06 Humidity and Temperature Sensor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called si7020.
+
+endmenu
diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
new file mode 100644
index 0000000..ae42049
--- /dev/null
+++ b/drivers/iio/humidity/Makefile
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for IIO humidity sensor drivers
+#
+
+obj-$(CONFIG_AM2315) += am2315.o
+obj-$(CONFIG_DHT11) += dht11.o
+obj-$(CONFIG_HDC100X) += hdc100x.o
+obj-$(CONFIG_HID_SENSOR_HUMIDITY) += hid-sensor-humidity.o
+
+hts221-y := hts221_core.o \
+	    hts221_buffer.o
+obj-$(CONFIG_HTS221) += hts221.o
+obj-$(CONFIG_HTS221_I2C) += hts221_i2c.o
+obj-$(CONFIG_HTS221_SPI) += hts221_spi.o
+
+obj-$(CONFIG_HTU21) += htu21.o
+obj-$(CONFIG_SI7005) += si7005.o
+obj-$(CONFIG_SI7020) += si7020.o
+
+ccflags-y += -I$(srctree)/drivers/iio/common/hid-sensors
diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c
new file mode 100644
index 0000000..7d8669d
--- /dev/null
+++ b/drivers/iio/humidity/am2315.c
@@ -0,0 +1,301 @@
+/**
+ * Aosong AM2315 relative humidity and temperature
+ *
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * 7-bit I2C address: 0x5C.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define AM2315_REG_HUM_MSB			0x00
+#define AM2315_REG_HUM_LSB			0x01
+#define AM2315_REG_TEMP_MSB			0x02
+#define AM2315_REG_TEMP_LSB			0x03
+
+#define AM2315_FUNCTION_READ			0x03
+#define AM2315_HUM_OFFSET			2
+#define AM2315_TEMP_OFFSET			4
+#define AM2315_ALL_CHANNEL_MASK			GENMASK(1, 0)
+
+#define AM2315_DRIVER_NAME			"am2315"
+
+struct am2315_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	s16 buffer[8]; /* 2x16-bit channels + 2x16 padding + 4x16 timestamp */
+};
+
+struct am2315_sensor_data {
+	s16 hum_data;
+	s16 temp_data;
+};
+
+static const struct iio_chan_spec am2315_channels[] = {
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_CPU,
+		},
+	},
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_CPU,
+		},
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+/* CRC calculation algorithm, as specified in the datasheet (page 13). */
+static u16 am2315_crc(u8 *data, u8 nr_bytes)
+{
+	int i;
+	u16 crc = 0xffff;
+
+	while (nr_bytes--) {
+		crc ^= *data++;
+		for (i = 0; i < 8; i++) {
+			if (crc & 0x01) {
+				crc >>= 1;
+				crc ^= 0xA001;
+			} else {
+				crc >>= 1;
+			}
+		}
+	}
+
+	return crc;
+}
+
+/* Simple function that sends a few bytes to the device to wake it up. */
+static void am2315_ping(struct i2c_client *client)
+{
+	i2c_smbus_read_byte_data(client, AM2315_REG_HUM_MSB);
+}
+
+static int am2315_read_data(struct am2315_data *data,
+			    struct am2315_sensor_data *sensor_data)
+{
+	int ret;
+	/* tx_buf format: <function code> <start addr> <nr of regs to read> */
+	u8 tx_buf[3] = { AM2315_FUNCTION_READ, AM2315_REG_HUM_MSB, 4 };
+	/*
+	 * rx_buf format:
+	 * <function code> <number of registers read>
+	 * <humidity MSB> <humidity LSB> <temp MSB> <temp LSB>
+	 * <CRC LSB> <CRC MSB>
+	 */
+	u8 rx_buf[8];
+	u16 crc;
+
+	/* First wake up the device. */
+	am2315_ping(data->client);
+
+	mutex_lock(&data->lock);
+	ret = i2c_master_send(data->client, tx_buf, sizeof(tx_buf));
+	if (ret < 0) {
+		dev_err(&data->client->dev, "failed to send read request\n");
+		goto exit_unlock;
+	}
+	/* Wait 2-3 ms, then read back the data sent by the device. */
+	usleep_range(2000, 3000);
+	/* Do a bulk data read, then pick out what we need. */
+	ret = i2c_master_recv(data->client, rx_buf, sizeof(rx_buf));
+	if (ret < 0) {
+		dev_err(&data->client->dev, "failed to read sensor data\n");
+		goto exit_unlock;
+	}
+	mutex_unlock(&data->lock);
+	/*
+	 * Do a CRC check on the data and compare it to the value
+	 * calculated by the device.
+	 */
+	crc = am2315_crc(rx_buf, sizeof(rx_buf) - 2);
+	if ((crc & 0xff) != rx_buf[6] || (crc >> 8) != rx_buf[7]) {
+		dev_err(&data->client->dev, "failed to verify sensor data\n");
+		return -EIO;
+	}
+
+	sensor_data->hum_data = (rx_buf[AM2315_HUM_OFFSET] << 8) |
+				 rx_buf[AM2315_HUM_OFFSET + 1];
+	sensor_data->temp_data = (rx_buf[AM2315_TEMP_OFFSET] << 8) |
+				  rx_buf[AM2315_TEMP_OFFSET + 1];
+
+	return ret;
+
+exit_unlock:
+	mutex_unlock(&data->lock);
+	return ret;
+}
+
+static irqreturn_t am2315_trigger_handler(int irq, void *p)
+{
+	int i;
+	int ret;
+	int bit;
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct am2315_data *data = iio_priv(indio_dev);
+	struct am2315_sensor_data sensor_data;
+
+	ret = am2315_read_data(data, &sensor_data);
+	if (ret < 0)
+		goto err;
+
+	mutex_lock(&data->lock);
+	if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) {
+		data->buffer[0] = sensor_data.hum_data;
+		data->buffer[1] = sensor_data.temp_data;
+	} else {
+		i = 0;
+		for_each_set_bit(bit, indio_dev->active_scan_mask,
+				 indio_dev->masklength) {
+			data->buffer[i] = (bit ? sensor_data.temp_data :
+						 sensor_data.hum_data);
+			i++;
+		}
+	}
+	mutex_unlock(&data->lock);
+
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+					   pf->timestamp);
+err:
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
+
+static int am2315_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	int ret;
+	struct am2315_sensor_data sensor_data;
+	struct am2315_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = am2315_read_data(data, &sensor_data);
+		if (ret < 0)
+			return ret;
+		*val = (chan->type == IIO_HUMIDITYRELATIVE) ?
+				sensor_data.hum_data : sensor_data.temp_data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 100;
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info am2315_info = {
+	.read_raw		= am2315_read_raw,
+};
+
+static int am2315_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct am2315_data *data;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev) {
+		dev_err(&client->dev, "iio allocation failed!\n");
+		return -ENOMEM;
+	}
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	i2c_set_clientdata(client, indio_dev);
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &am2315_info;
+	indio_dev->name = AM2315_DRIVER_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = am2315_channels;
+	indio_dev->num_channels = ARRAY_SIZE(am2315_channels);
+
+	ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
+					 am2315_trigger_handler, NULL);
+	if (ret < 0) {
+		dev_err(&client->dev, "iio triggered buffer setup failed\n");
+		return ret;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		goto err_buffer_cleanup;
+
+	return 0;
+
+err_buffer_cleanup:
+	iio_triggered_buffer_cleanup(indio_dev);
+	return ret;
+}
+
+static int am2315_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id am2315_i2c_id[] = {
+	{"am2315", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, am2315_i2c_id);
+
+static const struct acpi_device_id am2315_acpi_id[] = {
+	{"AOS2315", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, am2315_acpi_id);
+
+static struct i2c_driver am2315_driver = {
+	.driver = {
+		.name = "am2315",
+		.acpi_match_table = ACPI_PTR(am2315_acpi_id),
+	},
+	.probe =            am2315_probe,
+	.remove =	    am2315_remove,
+	.id_table =         am2315_i2c_id,
+};
+
+module_i2c_driver(am2315_driver);
+
+MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
+MODULE_DESCRIPTION("Aosong AM2315 relative humidity and temperature");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c
new file mode 100644
index 0000000..1a9f8f4
--- /dev/null
+++ b/drivers/iio/humidity/dht11.c
@@ -0,0 +1,363 @@
+/*
+ * DHT11/DHT22 bit banging GPIO driver
+ *
+ * Copyright (c) Harald Geyer <harald@ccbib.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/sysfs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/timekeeping.h>
+
+#include <linux/iio/iio.h>
+
+#define DRIVER_NAME	"dht11"
+
+#define DHT11_DATA_VALID_TIME	2000000000  /* 2s in ns */
+
+#define DHT11_EDGES_PREAMBLE 2
+#define DHT11_BITS_PER_READ 40
+/*
+ * Note that when reading the sensor actually 84 edges are detected, but
+ * since the last edge is not significant, we only store 83:
+ */
+#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \
+			      DHT11_EDGES_PREAMBLE + 1)
+
+/*
+ * Data transmission timing:
+ * Data bits are encoded as pulse length (high time) on the data line.
+ * 0-bit: 22-30uS -- typically 26uS (AM2302)
+ * 1-bit: 68-75uS -- typically 70uS (AM2302)
+ * The acutal timings also depend on the properties of the cable, with
+ * longer cables typically making pulses shorter.
+ *
+ * Our decoding depends on the time resolution of the system:
+ * timeres > 34uS ... don't know what a 1-tick pulse is
+ * 34uS > timeres > 30uS ... no problem (30kHz and 32kHz clocks)
+ * 30uS > timeres > 23uS ... don't know what a 2-tick pulse is
+ * timeres < 23uS ... no problem
+ *
+ * Luckily clocks in the 33-44kHz range are quite uncommon, so we can
+ * support most systems if the threshold for decoding a pulse as 1-bit
+ * is chosen carefully. If somebody really wants to support clocks around
+ * 40kHz, where this driver is most unreliable, there are two options.
+ * a) select an implementation using busy loop polling on those systems
+ * b) use the checksum to do some probabilistic decoding
+ */
+#define DHT11_START_TRANSMISSION_MIN	18000  /* us */
+#define DHT11_START_TRANSMISSION_MAX	20000  /* us */
+#define DHT11_MIN_TIMERES	34000  /* ns */
+#define DHT11_THRESHOLD		49000  /* ns */
+#define DHT11_AMBIG_LOW		23000  /* ns */
+#define DHT11_AMBIG_HIGH	30000  /* ns */
+
+struct dht11 {
+	struct device			*dev;
+
+	int				gpio;
+	int				irq;
+
+	struct completion		completion;
+	/* The iio sysfs interface doesn't prevent concurrent reads: */
+	struct mutex			lock;
+
+	s64				timestamp;
+	int				temperature;
+	int				humidity;
+
+	/* num_edges: -1 means "no transmission in progress" */
+	int				num_edges;
+	struct {s64 ts; int value; }	edges[DHT11_EDGES_PER_READ];
+};
+
+#ifdef CONFIG_DYNAMIC_DEBUG
+/*
+ * dht11_edges_print: show the data as actually received by the
+ *                    driver.
+ */
+static void dht11_edges_print(struct dht11 *dht11)
+{
+	int i;
+
+	dev_dbg(dht11->dev, "%d edges detected:\n", dht11->num_edges);
+	for (i = 1; i < dht11->num_edges; ++i) {
+		dev_dbg(dht11->dev, "%d: %lld ns %s\n", i,
+			dht11->edges[i].ts - dht11->edges[i - 1].ts,
+			dht11->edges[i - 1].value ? "high" : "low");
+	}
+}
+#endif /* CONFIG_DYNAMIC_DEBUG */
+
+static unsigned char dht11_decode_byte(char *bits)
+{
+	unsigned char ret = 0;
+	int i;
+
+	for (i = 0; i < 8; ++i) {
+		ret <<= 1;
+		if (bits[i])
+			++ret;
+	}
+
+	return ret;
+}
+
+static int dht11_decode(struct dht11 *dht11, int offset)
+{
+	int i, t;
+	char bits[DHT11_BITS_PER_READ];
+	unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
+
+	for (i = 0; i < DHT11_BITS_PER_READ; ++i) {
+		t = dht11->edges[offset + 2 * i + 2].ts -
+			dht11->edges[offset + 2 * i + 1].ts;
+		if (!dht11->edges[offset + 2 * i + 1].value) {
+			dev_dbg(dht11->dev,
+				"lost synchronisation at edge %d\n",
+				offset + 2 * i + 1);
+			return -EIO;
+		}
+		bits[i] = t > DHT11_THRESHOLD;
+	}
+
+	hum_int = dht11_decode_byte(bits);
+	hum_dec = dht11_decode_byte(&bits[8]);
+	temp_int = dht11_decode_byte(&bits[16]);
+	temp_dec = dht11_decode_byte(&bits[24]);
+	checksum = dht11_decode_byte(&bits[32]);
+
+	if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) {
+		dev_dbg(dht11->dev, "invalid checksum\n");
+		return -EIO;
+	}
+
+	dht11->timestamp = ktime_get_boot_ns();
+	if (hum_int < 4) {  /* DHT22: 100000 = (3*256+232)*100 */
+		dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
+					((temp_int & 0x80) ? -100 : 100);
+		dht11->humidity = ((hum_int << 8) + hum_dec) * 100;
+	} else if (temp_dec == 0 && hum_dec == 0) {  /* DHT11 */
+		dht11->temperature = temp_int * 1000;
+		dht11->humidity = hum_int * 1000;
+	} else {
+		dev_err(dht11->dev,
+			"Don't know how to decode data: %d %d %d %d\n",
+			hum_int, hum_dec, temp_int, temp_dec);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * IRQ handler called on GPIO edges
+ */
+static irqreturn_t dht11_handle_irq(int irq, void *data)
+{
+	struct iio_dev *iio = data;
+	struct dht11 *dht11 = iio_priv(iio);
+
+	/* TODO: Consider making the handler safe for IRQ sharing */
+	if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
+		dht11->edges[dht11->num_edges].ts = ktime_get_boot_ns();
+		dht11->edges[dht11->num_edges++].value =
+						gpio_get_value(dht11->gpio);
+
+		if (dht11->num_edges >= DHT11_EDGES_PER_READ)
+			complete(&dht11->completion);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int dht11_read_raw(struct iio_dev *iio_dev,
+			  const struct iio_chan_spec *chan,
+			int *val, int *val2, long m)
+{
+	struct dht11 *dht11 = iio_priv(iio_dev);
+	int ret, timeres, offset;
+
+	mutex_lock(&dht11->lock);
+	if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_boot_ns()) {
+		timeres = ktime_get_resolution_ns();
+		dev_dbg(dht11->dev, "current timeresolution: %dns\n", timeres);
+		if (timeres > DHT11_MIN_TIMERES) {
+			dev_err(dht11->dev, "timeresolution %dns too low\n",
+				timeres);
+			/* In theory a better clock could become available
+			 * at some point ... and there is no error code
+			 * that really fits better.
+			 */
+			ret = -EAGAIN;
+			goto err;
+		}
+		if (timeres > DHT11_AMBIG_LOW && timeres < DHT11_AMBIG_HIGH)
+			dev_warn(dht11->dev,
+				 "timeresolution: %dns - decoding ambiguous\n",
+				 timeres);
+
+		reinit_completion(&dht11->completion);
+
+		dht11->num_edges = 0;
+		ret = gpio_direction_output(dht11->gpio, 0);
+		if (ret)
+			goto err;
+		usleep_range(DHT11_START_TRANSMISSION_MIN,
+			     DHT11_START_TRANSMISSION_MAX);
+		ret = gpio_direction_input(dht11->gpio);
+		if (ret)
+			goto err;
+
+		ret = request_irq(dht11->irq, dht11_handle_irq,
+				  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				  iio_dev->name, iio_dev);
+		if (ret)
+			goto err;
+
+		ret = wait_for_completion_killable_timeout(&dht11->completion,
+							   HZ);
+
+		free_irq(dht11->irq, iio_dev);
+
+#ifdef CONFIG_DYNAMIC_DEBUG
+		dht11_edges_print(dht11);
+#endif
+
+		if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
+			dev_err(dht11->dev, "Only %d signal edges detected\n",
+				dht11->num_edges);
+			ret = -ETIMEDOUT;
+		}
+		if (ret < 0)
+			goto err;
+
+		offset = DHT11_EDGES_PREAMBLE +
+				dht11->num_edges - DHT11_EDGES_PER_READ;
+		for (; offset >= 0; --offset) {
+			ret = dht11_decode(dht11, offset);
+			if (!ret)
+				break;
+		}
+
+		if (ret)
+			goto err;
+	}
+
+	ret = IIO_VAL_INT;
+	if (chan->type == IIO_TEMP)
+		*val = dht11->temperature;
+	else if (chan->type == IIO_HUMIDITYRELATIVE)
+		*val = dht11->humidity;
+	else
+		ret = -EINVAL;
+err:
+	dht11->num_edges = -1;
+	mutex_unlock(&dht11->lock);
+	return ret;
+}
+
+static const struct iio_info dht11_iio_info = {
+	.read_raw		= dht11_read_raw,
+};
+
+static const struct iio_chan_spec dht11_chan_spec[] = {
+	{ .type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), },
+	{ .type = IIO_HUMIDITYRELATIVE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }
+};
+
+static const struct of_device_id dht11_dt_ids[] = {
+	{ .compatible = "dht11", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dht11_dt_ids);
+
+static int dht11_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct dht11 *dht11;
+	struct iio_dev *iio;
+	int ret;
+
+	iio = devm_iio_device_alloc(dev, sizeof(*dht11));
+	if (!iio) {
+		dev_err(dev, "Failed to allocate IIO device\n");
+		return -ENOMEM;
+	}
+
+	dht11 = iio_priv(iio);
+	dht11->dev = dev;
+
+	ret = of_get_gpio(node, 0);
+	if (ret < 0)
+		return ret;
+	dht11->gpio = ret;
+	ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name);
+	if (ret)
+		return ret;
+
+	dht11->irq = gpio_to_irq(dht11->gpio);
+	if (dht11->irq < 0) {
+		dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);
+		return -EINVAL;
+	}
+
+	dht11->timestamp = ktime_get_boot_ns() - DHT11_DATA_VALID_TIME - 1;
+	dht11->num_edges = -1;
+
+	platform_set_drvdata(pdev, iio);
+
+	init_completion(&dht11->completion);
+	mutex_init(&dht11->lock);
+	iio->name = pdev->name;
+	iio->dev.parent = &pdev->dev;
+	iio->info = &dht11_iio_info;
+	iio->modes = INDIO_DIRECT_MODE;
+	iio->channels = dht11_chan_spec;
+	iio->num_channels = ARRAY_SIZE(dht11_chan_spec);
+
+	return devm_iio_device_register(dev, iio);
+}
+
+static struct platform_driver dht11_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.of_match_table = dht11_dt_ids,
+	},
+	.probe  = dht11_probe,
+};
+
+module_platform_driver(dht11_driver);
+
+MODULE_AUTHOR("Harald Geyer <harald@ccbib.org>");
+MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
new file mode 100644
index 0000000..066e05f
--- /dev/null
+++ b/drivers/iio/humidity/hdc100x.c
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * hdc100x.c - Support for the TI HDC100x temperature + humidity sensors
+ *
+ * Copyright (C) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
+ *
+ * Datasheets:
+ * http://www.ti.com/product/HDC1000/datasheet
+ * http://www.ti.com/product/HDC1008/datasheet
+ * http://www.ti.com/product/HDC1010/datasheet
+ * http://www.ti.com/product/HDC1050/datasheet
+ * http://www.ti.com/product/HDC1080/datasheet
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define HDC100X_REG_TEMP			0x00
+#define HDC100X_REG_HUMIDITY			0x01
+
+#define HDC100X_REG_CONFIG			0x02
+#define HDC100X_REG_CONFIG_ACQ_MODE		BIT(12)
+#define HDC100X_REG_CONFIG_HEATER_EN		BIT(13)
+
+struct hdc100x_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	u16 config;
+
+	/* integration time of the sensor */
+	int adc_int_us[2];
+};
+
+/* integration time in us */
+static const int hdc100x_int_time[][3] = {
+	{ 6350, 3650, 0 },	/* IIO_TEMP channel*/
+	{ 6500, 3850, 2500 },	/* IIO_HUMIDITYRELATIVE channel */
+};
+
+/* HDC100X_REG_CONFIG shift and mask values */
+static const struct {
+	int shift;
+	int mask;
+} hdc100x_resolution_shift[2] = {
+	{ /* IIO_TEMP channel */
+		.shift = 10,
+		.mask = 1
+	},
+	{ /* IIO_HUMIDITYRELATIVE channel */
+		.shift = 8,
+		.mask = 3,
+	},
+};
+
+static IIO_CONST_ATTR(temp_integration_time_available,
+		"0.00365 0.00635");
+
+static IIO_CONST_ATTR(humidityrelative_integration_time_available,
+		"0.0025 0.00385 0.0065");
+
+static IIO_CONST_ATTR(out_current_heater_raw_available,
+		"0 1");
+
+static struct attribute *hdc100x_attributes[] = {
+	&iio_const_attr_temp_integration_time_available.dev_attr.attr,
+	&iio_const_attr_humidityrelative_integration_time_available.dev_attr.attr,
+	&iio_const_attr_out_current_heater_raw_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group hdc100x_attribute_group = {
+	.attrs = hdc100x_attributes,
+};
+
+static const struct iio_chan_spec hdc100x_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.address = HDC100X_REG_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_INT_TIME) |
+			BIT(IIO_CHAN_INFO_OFFSET),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_BE,
+		},
+	},
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.address = HDC100X_REG_HUMIDITY,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_INT_TIME),
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_BE,
+		},
+	},
+	{
+		.type = IIO_CURRENT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.extend_name = "heater",
+		.output = 1,
+		.scan_index = -1,
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+static const unsigned long hdc100x_scan_masks[] = {0x3, 0};
+
+static int hdc100x_update_config(struct hdc100x_data *data, int mask, int val)
+{
+	int tmp = (~mask & data->config) | val;
+	int ret;
+
+	ret = i2c_smbus_write_word_swapped(data->client,
+						HDC100X_REG_CONFIG, tmp);
+	if (!ret)
+		data->config = tmp;
+
+	return ret;
+}
+
+static int hdc100x_set_it_time(struct hdc100x_data *data, int chan, int val2)
+{
+	int shift = hdc100x_resolution_shift[chan].shift;
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hdc100x_int_time[chan]); i++) {
+		if (val2 && val2 == hdc100x_int_time[chan][i]) {
+			ret = hdc100x_update_config(data,
+				hdc100x_resolution_shift[chan].mask << shift,
+				i << shift);
+			if (!ret)
+				data->adc_int_us[chan] = val2;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int hdc100x_get_measurement(struct hdc100x_data *data,
+				   struct iio_chan_spec const *chan)
+{
+	struct i2c_client *client = data->client;
+	int delay = data->adc_int_us[chan->address];
+	int ret;
+	__be16 val;
+
+	/* start measurement */
+	ret = i2c_smbus_write_byte(client, chan->address);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot start measurement");
+		return ret;
+	}
+
+	/* wait for integration time to pass */
+	usleep_range(delay, delay + 1000);
+
+	/* read measurement */
+	ret = i2c_master_recv(data->client, (char *)&val, sizeof(val));
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot read sensor data\n");
+		return ret;
+	}
+	return be16_to_cpu(val);
+}
+
+static int hdc100x_get_heater_status(struct hdc100x_data *data)
+{
+	return !!(data->config & HDC100X_REG_CONFIG_HEATER_EN);
+}
+
+static int hdc100x_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan, int *val,
+			    int *val2, long mask)
+{
+	struct hdc100x_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW: {
+		int ret;
+
+		mutex_lock(&data->lock);
+		if (chan->type == IIO_CURRENT) {
+			*val = hdc100x_get_heater_status(data);
+			ret = IIO_VAL_INT;
+		} else {
+			ret = iio_device_claim_direct_mode(indio_dev);
+			if (ret) {
+				mutex_unlock(&data->lock);
+				return ret;
+			}
+
+			ret = hdc100x_get_measurement(data, chan);
+			iio_device_release_direct_mode(indio_dev);
+			if (ret >= 0) {
+				*val = ret;
+				ret = IIO_VAL_INT;
+			}
+		}
+		mutex_unlock(&data->lock);
+		return ret;
+	}
+	case IIO_CHAN_INFO_INT_TIME:
+		*val = 0;
+		*val2 = data->adc_int_us[chan->address];
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_TEMP) {
+			*val = 165000;
+			*val2 = 65536;
+			return IIO_VAL_FRACTIONAL;
+		} else {
+			*val = 100;
+			*val2 = 65536;
+			return IIO_VAL_FRACTIONAL;
+		}
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = -15887;
+		*val2 = 515151;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hdc100x_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct hdc100x_data *data = iio_priv(indio_dev);
+	int ret = -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		if (val != 0)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		ret = hdc100x_set_it_time(data, chan->address, val2);
+		mutex_unlock(&data->lock);
+		return ret;
+	case IIO_CHAN_INFO_RAW:
+		if (chan->type != IIO_CURRENT || val2 != 0)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN,
+					val ? HDC100X_REG_CONFIG_HEATER_EN : 0);
+		mutex_unlock(&data->lock);
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hdc100x_buffer_postenable(struct iio_dev *indio_dev)
+{
+	struct hdc100x_data *data = iio_priv(indio_dev);
+	int ret;
+
+	/* Buffer is enabled. First set ACQ Mode, then attach poll func */
+	mutex_lock(&data->lock);
+	ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE,
+				    HDC100X_REG_CONFIG_ACQ_MODE);
+	mutex_unlock(&data->lock);
+	if (ret)
+		return ret;
+
+	return iio_triggered_buffer_postenable(indio_dev);
+}
+
+static int hdc100x_buffer_predisable(struct iio_dev *indio_dev)
+{
+	struct hdc100x_data *data = iio_priv(indio_dev);
+	int ret;
+
+	/* First detach poll func, then reset ACQ mode. OK to disable buffer */
+	ret = iio_triggered_buffer_predisable(indio_dev);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->lock);
+	ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0);
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static const struct iio_buffer_setup_ops hdc_buffer_setup_ops = {
+	.postenable  = hdc100x_buffer_postenable,
+	.predisable  = hdc100x_buffer_predisable,
+};
+
+static irqreturn_t hdc100x_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct hdc100x_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+	int delay = data->adc_int_us[0] + data->adc_int_us[1];
+	int ret;
+	s16 buf[8];  /* 2x s16 + padding + 8 byte timestamp */
+
+	/* dual read starts at temp register */
+	mutex_lock(&data->lock);
+	ret = i2c_smbus_write_byte(client, HDC100X_REG_TEMP);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot start measurement\n");
+		goto err;
+	}
+	usleep_range(delay, delay + 1000);
+
+	ret = i2c_master_recv(client, (u8 *)buf, 4);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot read sensor data\n");
+		goto err;
+	}
+
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
+err:
+	mutex_unlock(&data->lock);
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static const struct iio_info hdc100x_info = {
+	.read_raw = hdc100x_read_raw,
+	.write_raw = hdc100x_write_raw,
+	.attrs = &hdc100x_attribute_group,
+};
+
+static int hdc100x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct iio_dev *indio_dev;
+	struct hdc100x_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
+				     I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
+		return -EOPNOTSUPP;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = dev_name(&client->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &hdc100x_info;
+
+	indio_dev->channels = hdc100x_channels;
+	indio_dev->num_channels = ARRAY_SIZE(hdc100x_channels);
+	indio_dev->available_scan_masks = hdc100x_scan_masks;
+
+	/* be sure we are in a known state */
+	hdc100x_set_it_time(data, 0, hdc100x_int_time[0][0]);
+	hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]);
+	hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0);
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+					 hdc100x_trigger_handler,
+					 &hdc_buffer_setup_ops);
+	if (ret < 0) {
+		dev_err(&client->dev, "iio triggered buffer setup failed\n");
+		return ret;
+	}
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		iio_triggered_buffer_cleanup(indio_dev);
+
+	return ret;
+}
+
+static int hdc100x_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id hdc100x_id[] = {
+	{ "hdc100x", 0 },
+	{ "hdc1000", 0 },
+	{ "hdc1008", 0 },
+	{ "hdc1010", 0 },
+	{ "hdc1050", 0 },
+	{ "hdc1080", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, hdc100x_id);
+
+static const struct of_device_id hdc100x_dt_ids[] = {
+	{ .compatible = "ti,hdc1000" },
+	{ .compatible = "ti,hdc1008" },
+	{ .compatible = "ti,hdc1010" },
+	{ .compatible = "ti,hdc1050" },
+	{ .compatible = "ti,hdc1080" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, hdc100x_dt_ids);
+
+static struct i2c_driver hdc100x_driver = {
+	.driver = {
+		.name	= "hdc100x",
+		.of_match_table = of_match_ptr(hdc100x_dt_ids),
+	},
+	.probe = hdc100x_probe,
+	.remove = hdc100x_remove,
+	.id_table = hdc100x_id,
+};
+module_i2c_driver(hdc100x_driver);
+
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
+MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
new file mode 100644
index 0000000..4bc95f3
--- /dev/null
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -0,0 +1,315 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2017, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.
+ */
+#include <linux/device.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "hid-sensor-trigger.h"
+
+struct hid_humidity_state {
+	struct hid_sensor_common common_attributes;
+	struct hid_sensor_hub_attribute_info humidity_attr;
+	s32 humidity_data;
+	int scale_pre_decml;
+	int scale_post_decml;
+	int scale_precision;
+	int value_offset;
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec humidity_channels[] = {
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+			BIT(IIO_CHAN_INFO_HYSTERESIS),
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(1)
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+					int channel, int size)
+{
+	channels[channel].scan_type.sign = 's';
+	/* Real storage bits will change based on the report desc. */
+	channels[channel].scan_type.realbits = size * 8;
+	/* Maximum size of a sample to capture is s32 */
+	channels[channel].scan_type.storagebits = sizeof(s32) * 8;
+}
+
+static int humidity_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct hid_humidity_state *humid_st = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (chan->type != IIO_HUMIDITYRELATIVE)
+			return -EINVAL;
+		hid_sensor_power_state(&humid_st->common_attributes, true);
+		*val = sensor_hub_input_attr_get_raw_value(
+				humid_st->common_attributes.hsdev,
+				HID_USAGE_SENSOR_HUMIDITY,
+				HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
+				humid_st->humidity_attr.report_id,
+				SENSOR_HUB_SYNC,
+				humid_st->humidity_attr.logical_minimum < 0);
+		hid_sensor_power_state(&humid_st->common_attributes, false);
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = humid_st->scale_pre_decml;
+		*val2 = humid_st->scale_post_decml;
+
+		return humid_st->scale_precision;
+
+	case IIO_CHAN_INFO_OFFSET:
+		*val = humid_st->value_offset;
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return hid_sensor_read_samp_freq_value(
+				&humid_st->common_attributes, val, val2);
+
+	case IIO_CHAN_INFO_HYSTERESIS:
+		return hid_sensor_read_raw_hyst_value(
+				&humid_st->common_attributes, val, val2);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int humidity_write_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int val, int val2, long mask)
+{
+	struct hid_humidity_state *humid_st = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return hid_sensor_write_samp_freq_value(
+				&humid_st->common_attributes, val, val2);
+
+	case IIO_CHAN_INFO_HYSTERESIS:
+		return hid_sensor_write_raw_hyst_value(
+				&humid_st->common_attributes, val, val2);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info humidity_info = {
+	.read_raw = &humidity_read_raw,
+	.write_raw = &humidity_write_raw,
+};
+
+/* Callback handler to send event after all samples are received and captured */
+static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
+				unsigned int usage_id, void *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct hid_humidity_state *humid_st = iio_priv(indio_dev);
+
+	if (atomic_read(&humid_st->common_attributes.data_ready))
+		iio_push_to_buffers_with_timestamp(indio_dev,
+					&humid_st->humidity_data,
+					iio_get_time_ns(indio_dev));
+
+	return 0;
+}
+
+/* Capture samples in local storage */
+static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
+				unsigned int usage_id, size_t raw_len,
+				char *raw_data, void *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct hid_humidity_state *humid_st = iio_priv(indio_dev);
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY:
+		humid_st->humidity_data = *(s32 *)raw_data;
+
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/* Parse report which is specific to an usage id */
+static int humidity_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				struct iio_chan_spec *channels,
+				unsigned int usage_id,
+				struct hid_humidity_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+					usage_id,
+					HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
+					&st->humidity_attr);
+	if (ret < 0)
+		return ret;
+
+	humidity_adjust_channel_bit_mask(channels, 0, st->humidity_attr.size);
+
+	st->scale_precision = hid_sensor_format_scale(
+						HID_USAGE_SENSOR_HUMIDITY,
+						&st->humidity_attr,
+						&st->scale_pre_decml,
+						&st->scale_post_decml);
+
+	/* Set Sensitivity field ids, when there is no individual modifier */
+	if (st->common_attributes.sensitivity.index < 0)
+		sensor_hub_input_get_attribute_info(hsdev,
+			HID_FEATURE_REPORT, usage_id,
+			HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
+			HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
+			&st->common_attributes.sensitivity);
+
+	return ret;
+}
+
+static struct hid_sensor_hub_callbacks humidity_callbacks = {
+	.send_event = &humidity_proc_event,
+	.capture_sample = &humidity_capture_sample,
+};
+
+/* Function to initialize the processing for usage id */
+static int hid_humidity_probe(struct platform_device *pdev)
+{
+	static const char *name = "humidity";
+	struct iio_dev *indio_dev;
+	struct hid_humidity_state *humid_st;
+	struct iio_chan_spec *humid_chans;
+	struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*humid_st));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	humid_st = iio_priv(indio_dev);
+	humid_st->common_attributes.hsdev = hsdev;
+	humid_st->common_attributes.pdev = pdev;
+
+	ret = hid_sensor_parse_common_attributes(hsdev,
+					HID_USAGE_SENSOR_HUMIDITY,
+					&humid_st->common_attributes);
+	if (ret)
+		return ret;
+
+	humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels,
+					sizeof(humidity_channels), GFP_KERNEL);
+	if (!humid_chans)
+		return -ENOMEM;
+
+	ret = humidity_parse_report(pdev, hsdev, humid_chans,
+				HID_USAGE_SENSOR_HUMIDITY, humid_st);
+	if (ret)
+		return ret;
+
+	indio_dev->channels = humid_chans;
+	indio_dev->num_channels = ARRAY_SIZE(humidity_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &humidity_info;
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev,
+					&iio_pollfunc_store_time, NULL, NULL);
+	if (ret)
+		return ret;
+
+	atomic_set(&humid_st->common_attributes.data_ready, 0);
+	ret = hid_sensor_setup_trigger(indio_dev, name,
+				&humid_st->common_attributes);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	humidity_callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY,
+					&humidity_callbacks);
+	if (ret)
+		goto error_remove_trigger;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_remove_callback;
+
+	return ret;
+
+error_remove_callback:
+	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
+error_remove_trigger:
+	hid_sensor_remove_trigger(&humid_st->common_attributes);
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int hid_humidity_remove(struct platform_device *pdev)
+{
+	struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct hid_humidity_state *humid_st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
+	hid_sensor_remove_trigger(&humid_st->common_attributes);
+
+	return 0;
+}
+
+static const struct platform_device_id hid_humidity_ids[] = {
+	{
+		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+		.name = "HID-SENSOR-200032",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_humidity_ids);
+
+static struct platform_driver hid_humidity_platform_driver = {
+	.id_table = hid_humidity_ids,
+	.driver = {
+		.name	= KBUILD_MODNAME,
+		.pm	= &hid_sensor_pm_ops,
+	},
+	.probe		= hid_humidity_probe,
+	.remove		= hid_humidity_remove,
+};
+module_platform_driver(hid_humidity_platform_driver);
+
+MODULE_DESCRIPTION("HID Environmental humidity sensor");
+MODULE_AUTHOR("Song Hongyan <hongyan.song@intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/hts221.h b/drivers/iio/humidity/hts221.h
new file mode 100644
index 0000000..e41a3d8
--- /dev/null
+++ b/drivers/iio/humidity/hts221.h
@@ -0,0 +1,53 @@
+/*
+ * STMicroelectronics hts221 sensor driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef HTS221_H
+#define HTS221_H
+
+#define HTS221_DEV_NAME		"hts221"
+
+#include <linux/iio/iio.h>
+
+#define HTS221_DATA_SIZE	2
+
+enum hts221_sensor_type {
+	HTS221_SENSOR_H,
+	HTS221_SENSOR_T,
+	HTS221_SENSOR_MAX,
+};
+
+struct hts221_sensor {
+	u8 cur_avg_idx;
+	int slope, b_gen;
+};
+
+struct hts221_hw {
+	const char *name;
+	struct device *dev;
+	struct regmap *regmap;
+
+	struct iio_trigger *trig;
+	int irq;
+
+	struct hts221_sensor sensors[HTS221_SENSOR_MAX];
+
+	bool enabled;
+	u8 odr;
+};
+
+extern const struct dev_pm_ops hts221_pm_ops;
+
+int hts221_probe(struct device *dev, int irq, const char *name,
+		 struct regmap *regmap);
+int hts221_set_enable(struct hts221_hw *hw, bool enable);
+int hts221_allocate_buffers(struct hts221_hw *hw);
+int hts221_allocate_trigger(struct hts221_hw *hw);
+
+#endif /* HTS221_H */
diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c
new file mode 100644
index 0000000..1a94b0b
--- /dev/null
+++ b/drivers/iio/humidity/hts221_buffer.c
@@ -0,0 +1,205 @@
+/*
+ * STMicroelectronics hts221 sensor driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/buffer.h>
+
+#include <linux/platform_data/st_sensors_pdata.h>
+
+#include "hts221.h"
+
+#define HTS221_REG_DRDY_HL_ADDR		0x22
+#define HTS221_REG_DRDY_HL_MASK		BIT(7)
+#define HTS221_REG_DRDY_PP_OD_ADDR	0x22
+#define HTS221_REG_DRDY_PP_OD_MASK	BIT(6)
+#define HTS221_REG_DRDY_EN_ADDR		0x22
+#define HTS221_REG_DRDY_EN_MASK		BIT(2)
+#define HTS221_REG_STATUS_ADDR		0x27
+#define HTS221_RH_DRDY_MASK		BIT(1)
+#define HTS221_TEMP_DRDY_MASK		BIT(0)
+
+static int hts221_trig_set_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig);
+	struct hts221_hw *hw = iio_priv(iio_dev);
+
+	return regmap_update_bits(hw->regmap, HTS221_REG_DRDY_EN_ADDR,
+				  HTS221_REG_DRDY_EN_MASK,
+				  FIELD_PREP(HTS221_REG_DRDY_EN_MASK, state));
+}
+
+static const struct iio_trigger_ops hts221_trigger_ops = {
+	.set_trigger_state = hts221_trig_set_state,
+};
+
+static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)
+{
+	struct hts221_hw *hw = private;
+	int err, status;
+
+	err = regmap_read(hw->regmap, HTS221_REG_STATUS_ADDR, &status);
+	if (err < 0)
+		return IRQ_HANDLED;
+
+	/*
+	 * H_DA bit (humidity data available) is routed to DRDY line.
+	 * Humidity sample is computed after temperature one.
+	 * Here we can assume data channels are both available if H_DA bit
+	 * is set in status register
+	 */
+	if (!(status & HTS221_RH_DRDY_MASK))
+		return IRQ_NONE;
+
+	iio_trigger_poll_chained(hw->trig);
+
+	return IRQ_HANDLED;
+}
+
+int hts221_allocate_trigger(struct hts221_hw *hw)
+{
+	struct iio_dev *iio_dev = iio_priv_to_dev(hw);
+	bool irq_active_low = false, open_drain = false;
+	struct device_node *np = hw->dev->of_node;
+	struct st_sensors_platform_data *pdata;
+	unsigned long irq_type;
+	int err;
+
+	irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
+
+	switch (irq_type) {
+	case IRQF_TRIGGER_HIGH:
+	case IRQF_TRIGGER_RISING:
+		break;
+	case IRQF_TRIGGER_LOW:
+	case IRQF_TRIGGER_FALLING:
+		irq_active_low = true;
+		break;
+	default:
+		dev_info(hw->dev,
+			 "mode %lx unsupported, using IRQF_TRIGGER_RISING\n",
+			 irq_type);
+		irq_type = IRQF_TRIGGER_RISING;
+		break;
+	}
+
+	err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_HL_ADDR,
+				 HTS221_REG_DRDY_HL_MASK,
+				 FIELD_PREP(HTS221_REG_DRDY_HL_MASK,
+					    irq_active_low));
+	if (err < 0)
+		return err;
+
+	pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
+	if ((np && of_property_read_bool(np, "drive-open-drain")) ||
+	    (pdata && pdata->open_drain)) {
+		irq_type |= IRQF_SHARED;
+		open_drain = true;
+	}
+
+	err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_PP_OD_ADDR,
+				 HTS221_REG_DRDY_PP_OD_MASK,
+				 FIELD_PREP(HTS221_REG_DRDY_PP_OD_MASK,
+					    open_drain));
+	if (err < 0)
+		return err;
+
+	err = devm_request_threaded_irq(hw->dev, hw->irq, NULL,
+					hts221_trigger_handler_thread,
+					irq_type | IRQF_ONESHOT,
+					hw->name, hw);
+	if (err) {
+		dev_err(hw->dev, "failed to request trigger irq %d\n",
+			hw->irq);
+		return err;
+	}
+
+	hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger",
+					  iio_dev->name);
+	if (!hw->trig)
+		return -ENOMEM;
+
+	iio_trigger_set_drvdata(hw->trig, iio_dev);
+	hw->trig->ops = &hts221_trigger_ops;
+	hw->trig->dev.parent = hw->dev;
+	iio_dev->trig = iio_trigger_get(hw->trig);
+
+	return devm_iio_trigger_register(hw->dev, hw->trig);
+}
+
+static int hts221_buffer_preenable(struct iio_dev *iio_dev)
+{
+	return hts221_set_enable(iio_priv(iio_dev), true);
+}
+
+static int hts221_buffer_postdisable(struct iio_dev *iio_dev)
+{
+	return hts221_set_enable(iio_priv(iio_dev), false);
+}
+
+static const struct iio_buffer_setup_ops hts221_buffer_ops = {
+	.preenable = hts221_buffer_preenable,
+	.postenable = iio_triggered_buffer_postenable,
+	.predisable = iio_triggered_buffer_predisable,
+	.postdisable = hts221_buffer_postdisable,
+};
+
+static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
+{
+	u8 buffer[ALIGN(2 * HTS221_DATA_SIZE, sizeof(s64)) + sizeof(s64)];
+	struct iio_poll_func *pf = p;
+	struct iio_dev *iio_dev = pf->indio_dev;
+	struct hts221_hw *hw = iio_priv(iio_dev);
+	struct iio_chan_spec const *ch;
+	int err;
+
+	/* humidity data */
+	ch = &iio_dev->channels[HTS221_SENSOR_H];
+	err = regmap_bulk_read(hw->regmap, ch->address,
+			       buffer, HTS221_DATA_SIZE);
+	if (err < 0)
+		goto out;
+
+	/* temperature data */
+	ch = &iio_dev->channels[HTS221_SENSOR_T];
+	err = regmap_bulk_read(hw->regmap, ch->address,
+			       buffer + HTS221_DATA_SIZE, HTS221_DATA_SIZE);
+	if (err < 0)
+		goto out;
+
+	iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+					   iio_get_time_ns(iio_dev));
+
+out:
+	iio_trigger_notify_done(hw->trig);
+
+	return IRQ_HANDLED;
+}
+
+int hts221_allocate_buffers(struct hts221_hw *hw)
+{
+	return devm_iio_triggered_buffer_setup(hw->dev, iio_priv_to_dev(hw),
+					NULL, hts221_buffer_handler_thread,
+					&hts221_buffer_ops);
+}
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics hts221 buffer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c
new file mode 100644
index 0000000..166946d
--- /dev/null
+++ b/drivers/iio/humidity/hts221_core.c
@@ -0,0 +1,676 @@
+/*
+ * STMicroelectronics hts221 sensor driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/iio/sysfs.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
+
+#include "hts221.h"
+
+#define HTS221_REG_WHOAMI_ADDR		0x0f
+#define HTS221_REG_WHOAMI_VAL		0xbc
+
+#define HTS221_REG_CNTRL1_ADDR		0x20
+#define HTS221_REG_CNTRL2_ADDR		0x21
+
+#define HTS221_REG_AVG_ADDR		0x10
+#define HTS221_REG_H_OUT_L		0x28
+#define HTS221_REG_T_OUT_L		0x2a
+
+#define HTS221_HUMIDITY_AVG_MASK	0x07
+#define HTS221_TEMP_AVG_MASK		0x38
+
+#define HTS221_ODR_MASK			0x03
+#define HTS221_BDU_MASK			BIT(2)
+#define HTS221_ENABLE_MASK		BIT(7)
+
+/* calibration registers */
+#define HTS221_REG_0RH_CAL_X_H		0x36
+#define HTS221_REG_1RH_CAL_X_H		0x3a
+#define HTS221_REG_0RH_CAL_Y_H		0x30
+#define HTS221_REG_1RH_CAL_Y_H		0x31
+#define HTS221_REG_0T_CAL_X_L		0x3c
+#define HTS221_REG_1T_CAL_X_L		0x3e
+#define HTS221_REG_0T_CAL_Y_H		0x32
+#define HTS221_REG_1T_CAL_Y_H		0x33
+#define HTS221_REG_T1_T0_CAL_Y_H	0x35
+
+struct hts221_odr {
+	u8 hz;
+	u8 val;
+};
+
+#define HTS221_AVG_DEPTH		8
+struct hts221_avg {
+	u8 addr;
+	u8 mask;
+	u16 avg_avl[HTS221_AVG_DEPTH];
+};
+
+static const struct hts221_odr hts221_odr_table[] = {
+	{  1, 0x01 },	/* 1Hz */
+	{  7, 0x02 },	/* 7Hz */
+	{ 13, 0x03 },	/* 12.5Hz */
+};
+
+static const struct hts221_avg hts221_avg_list[] = {
+	{
+		.addr = HTS221_REG_AVG_ADDR,
+		.mask = HTS221_HUMIDITY_AVG_MASK,
+		.avg_avl = {
+			4, /* 0.4 %RH */
+			8, /* 0.3 %RH */
+			16, /* 0.2 %RH */
+			32, /* 0.15 %RH */
+			64, /* 0.1 %RH */
+			128, /* 0.07 %RH */
+			256, /* 0.05 %RH */
+			512, /* 0.03 %RH */
+		},
+	},
+	{
+		.addr = HTS221_REG_AVG_ADDR,
+		.mask = HTS221_TEMP_AVG_MASK,
+		.avg_avl = {
+			2, /* 0.08 degC */
+			4, /* 0.05 degC */
+			8, /* 0.04 degC */
+			16, /* 0.03 degC */
+			32, /* 0.02 degC */
+			64, /* 0.015 degC */
+			128, /* 0.01 degC */
+			256, /* 0.007 degC */
+		},
+	},
+};
+
+static const struct iio_chan_spec hts221_channels[] = {
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.address = HTS221_REG_H_OUT_L,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_OFFSET) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_LE,
+		},
+	},
+	{
+		.type = IIO_TEMP,
+		.address = HTS221_REG_T_OUT_L,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_OFFSET) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_LE,
+		},
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+static int hts221_check_whoami(struct hts221_hw *hw)
+{
+	int err, data;
+
+	err = regmap_read(hw->regmap, HTS221_REG_WHOAMI_ADDR, &data);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to read whoami register\n");
+		return err;
+	}
+
+	if (data != HTS221_REG_WHOAMI_VAL) {
+		dev_err(hw->dev, "wrong whoami {%02x vs %02x}\n",
+			data, HTS221_REG_WHOAMI_VAL);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int hts221_update_odr(struct hts221_hw *hw, u8 odr)
+{
+	int i, err;
+
+	for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)
+		if (hts221_odr_table[i].hz == odr)
+			break;
+
+	if (i == ARRAY_SIZE(hts221_odr_table))
+		return -EINVAL;
+
+	err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+				 HTS221_ODR_MASK,
+				 FIELD_PREP(HTS221_ODR_MASK,
+					    hts221_odr_table[i].val));
+	if (err < 0)
+		return err;
+
+	hw->odr = odr;
+
+	return 0;
+}
+
+static int hts221_update_avg(struct hts221_hw *hw,
+			     enum hts221_sensor_type type,
+			     u16 val)
+{
+	const struct hts221_avg *avg = &hts221_avg_list[type];
+	int i, err, data;
+
+	for (i = 0; i < HTS221_AVG_DEPTH; i++)
+		if (avg->avg_avl[i] == val)
+			break;
+
+	if (i == HTS221_AVG_DEPTH)
+		return -EINVAL;
+
+	data = ((i << __ffs(avg->mask)) & avg->mask);
+	err = regmap_update_bits(hw->regmap, avg->addr,
+				 avg->mask, data);
+	if (err < 0)
+		return err;
+
+	hw->sensors[type].cur_avg_idx = i;
+
+	return 0;
+}
+
+static ssize_t hts221_sysfs_sampling_freq(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	int i;
+	ssize_t len = 0;
+
+	for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+				 hts221_odr_table[i].hz);
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static ssize_t
+hts221_sysfs_rh_oversampling_avail(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_H];
+	ssize_t len = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+				 avg->avg_avl[i]);
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static ssize_t
+hts221_sysfs_temp_oversampling_avail(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_T];
+	ssize_t len = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+				 avg->avg_avl[i]);
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+int hts221_set_enable(struct hts221_hw *hw, bool enable)
+{
+	int err;
+
+	err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+				 HTS221_ENABLE_MASK,
+				 FIELD_PREP(HTS221_ENABLE_MASK, enable));
+	if (err < 0)
+		return err;
+
+	hw->enabled = enable;
+
+	return 0;
+}
+
+static int hts221_parse_temp_caldata(struct hts221_hw *hw)
+{
+	int err, *slope, *b_gen, cal0, cal1;
+	s16 cal_x0, cal_x1, cal_y0, cal_y1;
+	__le16 val;
+
+	err = regmap_read(hw->regmap, HTS221_REG_0T_CAL_Y_H, &cal0);
+	if (err < 0)
+		return err;
+
+	err = regmap_read(hw->regmap, HTS221_REG_T1_T0_CAL_Y_H, &cal1);
+	if (err < 0)
+		return err;
+	cal_y0 = ((cal1 & 0x3) << 8) | cal0;
+
+	err = regmap_read(hw->regmap, HTS221_REG_1T_CAL_Y_H, &cal0);
+	if (err < 0)
+		return err;
+	cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0;
+
+	err = regmap_bulk_read(hw->regmap, HTS221_REG_0T_CAL_X_L,
+			       &val, sizeof(val));
+	if (err < 0)
+		return err;
+	cal_x0 = le16_to_cpu(val);
+
+	err = regmap_bulk_read(hw->regmap, HTS221_REG_1T_CAL_X_L,
+			       &val, sizeof(val));
+	if (err < 0)
+		return err;
+	cal_x1 = le16_to_cpu(val);
+
+	slope = &hw->sensors[HTS221_SENSOR_T].slope;
+	b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen;
+
+	*slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0);
+	*b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) /
+		 (cal_x1 - cal_x0);
+	*b_gen *= 8;
+
+	return 0;
+}
+
+static int hts221_parse_rh_caldata(struct hts221_hw *hw)
+{
+	int err, *slope, *b_gen, data;
+	s16 cal_x0, cal_x1, cal_y0, cal_y1;
+	__le16 val;
+
+	err = regmap_read(hw->regmap, HTS221_REG_0RH_CAL_Y_H, &data);
+	if (err < 0)
+		return err;
+	cal_y0 = data;
+
+	err = regmap_read(hw->regmap, HTS221_REG_1RH_CAL_Y_H, &data);
+	if (err < 0)
+		return err;
+	cal_y1 = data;
+
+	err = regmap_bulk_read(hw->regmap, HTS221_REG_0RH_CAL_X_H,
+			       &val, sizeof(val));
+	if (err < 0)
+		return err;
+	cal_x0 = le16_to_cpu(val);
+
+	err = regmap_bulk_read(hw->regmap, HTS221_REG_1RH_CAL_X_H,
+			       &val, sizeof(val));
+	if (err < 0)
+		return err;
+	cal_x1 = le16_to_cpu(val);
+
+	slope = &hw->sensors[HTS221_SENSOR_H].slope;
+	b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen;
+
+	*slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0);
+	*b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) /
+		 (cal_x1 - cal_x0);
+	*b_gen *= 8;
+
+	return 0;
+}
+
+static int hts221_get_sensor_scale(struct hts221_hw *hw,
+				   enum iio_chan_type ch_type,
+				   int *val, int *val2)
+{
+	s64 tmp;
+	s32 rem, div, data;
+
+	switch (ch_type) {
+	case IIO_HUMIDITYRELATIVE:
+		data = hw->sensors[HTS221_SENSOR_H].slope;
+		div = (1 << 4) * 1000;
+		break;
+	case IIO_TEMP:
+		data = hw->sensors[HTS221_SENSOR_T].slope;
+		div = (1 << 6) * 1000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tmp = div_s64(data * 1000000000LL, div);
+	tmp = div_s64_rem(tmp, 1000000000LL, &rem);
+
+	*val = tmp;
+	*val2 = rem;
+
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int hts221_get_sensor_offset(struct hts221_hw *hw,
+				    enum iio_chan_type ch_type,
+				    int *val, int *val2)
+{
+	s64 tmp;
+	s32 rem, div, data;
+
+	switch (ch_type) {
+	case IIO_HUMIDITYRELATIVE:
+		data = hw->sensors[HTS221_SENSOR_H].b_gen;
+		div = hw->sensors[HTS221_SENSOR_H].slope;
+		break;
+	case IIO_TEMP:
+		data = hw->sensors[HTS221_SENSOR_T].b_gen;
+		div = hw->sensors[HTS221_SENSOR_T].slope;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tmp = div_s64(data * 1000000000LL, div);
+	tmp = div_s64_rem(tmp, 1000000000LL, &rem);
+
+	*val = tmp;
+	*val2 = rem;
+
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
+{
+	__le16 data;
+	int err;
+
+	err = hts221_set_enable(hw, true);
+	if (err < 0)
+		return err;
+
+	msleep(50);
+
+	err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data));
+	if (err < 0)
+		return err;
+
+	hts221_set_enable(hw, false);
+
+	*val = (s16)le16_to_cpu(data);
+
+	return IIO_VAL_INT;
+}
+
+static int hts221_read_raw(struct iio_dev *iio_dev,
+			   struct iio_chan_spec const *ch,
+			   int *val, int *val2, long mask)
+{
+	struct hts221_hw *hw = iio_priv(iio_dev);
+	int ret;
+
+	ret = iio_device_claim_direct_mode(iio_dev);
+	if (ret)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = hts221_read_oneshot(hw, ch->address, val);
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		ret = hts221_get_sensor_scale(hw, ch->type, val, val2);
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		ret = hts221_get_sensor_offset(hw, ch->type, val, val2);
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val = hw->odr;
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
+		u8 idx;
+		const struct hts221_avg *avg;
+
+		switch (ch->type) {
+		case IIO_HUMIDITYRELATIVE:
+			avg = &hts221_avg_list[HTS221_SENSOR_H];
+			idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx;
+			*val = avg->avg_avl[idx];
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_TEMP:
+			avg = &hts221_avg_list[HTS221_SENSOR_T];
+			idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx;
+			*val = avg->avg_avl[idx];
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	}
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	iio_device_release_direct_mode(iio_dev);
+
+	return ret;
+}
+
+static int hts221_write_raw(struct iio_dev *iio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	struct hts221_hw *hw = iio_priv(iio_dev);
+	int ret;
+
+	ret = iio_device_claim_direct_mode(iio_dev);
+	if (ret)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = hts221_update_odr(hw, val);
+		break;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		switch (chan->type) {
+		case IIO_HUMIDITYRELATIVE:
+			ret = hts221_update_avg(hw, HTS221_SENSOR_H, val);
+			break;
+		case IIO_TEMP:
+			ret = hts221_update_avg(hw, HTS221_SENSOR_T, val);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	iio_device_release_direct_mode(iio_dev);
+
+	return ret;
+}
+
+static int hts221_validate_trigger(struct iio_dev *iio_dev,
+				   struct iio_trigger *trig)
+{
+	struct hts221_hw *hw = iio_priv(iio_dev);
+
+	return hw->trig == trig ? 0 : -EINVAL;
+}
+
+static IIO_DEVICE_ATTR(in_humidity_oversampling_ratio_available, S_IRUGO,
+		       hts221_sysfs_rh_oversampling_avail, NULL, 0);
+static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, S_IRUGO,
+		       hts221_sysfs_temp_oversampling_avail, NULL, 0);
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hts221_sysfs_sampling_freq);
+
+static struct attribute *hts221_attributes[] = {
+	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_in_humidity_oversampling_ratio_available.dev_attr.attr,
+	&iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group hts221_attribute_group = {
+	.attrs = hts221_attributes,
+};
+
+static const struct iio_info hts221_info = {
+	.attrs = &hts221_attribute_group,
+	.read_raw = hts221_read_raw,
+	.write_raw = hts221_write_raw,
+	.validate_trigger = hts221_validate_trigger,
+};
+
+static const unsigned long hts221_scan_masks[] = {0x3, 0x0};
+
+int hts221_probe(struct device *dev, int irq, const char *name,
+		 struct regmap *regmap)
+{
+	struct iio_dev *iio_dev;
+	struct hts221_hw *hw;
+	int err;
+	u8 data;
+
+	iio_dev = devm_iio_device_alloc(dev, sizeof(*hw));
+	if (!iio_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, (void *)iio_dev);
+
+	hw = iio_priv(iio_dev);
+	hw->name = name;
+	hw->dev = dev;
+	hw->irq = irq;
+	hw->regmap = regmap;
+
+	err = hts221_check_whoami(hw);
+	if (err < 0)
+		return err;
+
+	iio_dev->modes = INDIO_DIRECT_MODE;
+	iio_dev->dev.parent = hw->dev;
+	iio_dev->available_scan_masks = hts221_scan_masks;
+	iio_dev->channels = hts221_channels;
+	iio_dev->num_channels = ARRAY_SIZE(hts221_channels);
+	iio_dev->name = HTS221_DEV_NAME;
+	iio_dev->info = &hts221_info;
+
+	/* enable Block Data Update */
+	err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+				 HTS221_BDU_MASK,
+				 FIELD_PREP(HTS221_BDU_MASK, 1));
+	if (err < 0)
+		return err;
+
+	err = hts221_update_odr(hw, hts221_odr_table[0].hz);
+	if (err < 0)
+		return err;
+
+	/* configure humidity sensor */
+	err = hts221_parse_rh_caldata(hw);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to get rh calibration data\n");
+		return err;
+	}
+
+	data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3];
+	err = hts221_update_avg(hw, HTS221_SENSOR_H, data);
+	if (err < 0) {
+		dev_err(hw->dev, "failed to set rh oversampling ratio\n");
+		return err;
+	}
+
+	/* configure temperature sensor */
+	err = hts221_parse_temp_caldata(hw);
+	if (err < 0) {
+		dev_err(hw->dev,
+			"failed to get temperature calibration data\n");
+		return err;
+	}
+
+	data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3];
+	err = hts221_update_avg(hw, HTS221_SENSOR_T, data);
+	if (err < 0) {
+		dev_err(hw->dev,
+			"failed to set temperature oversampling ratio\n");
+		return err;
+	}
+
+	if (hw->irq > 0) {
+		err = hts221_allocate_buffers(hw);
+		if (err < 0)
+			return err;
+
+		err = hts221_allocate_trigger(hw);
+		if (err)
+			return err;
+	}
+
+	return devm_iio_device_register(hw->dev, iio_dev);
+}
+EXPORT_SYMBOL(hts221_probe);
+
+static int __maybe_unused hts221_suspend(struct device *dev)
+{
+	struct iio_dev *iio_dev = dev_get_drvdata(dev);
+	struct hts221_hw *hw = iio_priv(iio_dev);
+
+	return regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+				  HTS221_ENABLE_MASK,
+				  FIELD_PREP(HTS221_ENABLE_MASK, false));
+}
+
+static int __maybe_unused hts221_resume(struct device *dev)
+{
+	struct iio_dev *iio_dev = dev_get_drvdata(dev);
+	struct hts221_hw *hw = iio_priv(iio_dev);
+	int err = 0;
+
+	if (hw->enabled)
+		err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+					 HTS221_ENABLE_MASK,
+					 FIELD_PREP(HTS221_ENABLE_MASK,
+						    true));
+	return err;
+}
+
+const struct dev_pm_ops hts221_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(hts221_suspend, hts221_resume)
+};
+EXPORT_SYMBOL(hts221_pm_ops);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c
new file mode 100644
index 0000000..b5b3f40
--- /dev/null
+++ b/drivers/iio/humidity/hts221_i2c.c
@@ -0,0 +1,77 @@
+/*
+ * STMicroelectronics hts221 i2c driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+#include "hts221.h"
+
+#define HTS221_I2C_AUTO_INCREMENT	BIT(7)
+
+static const struct regmap_config hts221_i2c_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.write_flag_mask = HTS221_I2C_AUTO_INCREMENT,
+	.read_flag_mask = HTS221_I2C_AUTO_INCREMENT,
+};
+
+static int hts221_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(client, &hts221_i2c_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&client->dev, "Failed to register i2c regmap %d\n",
+			(int)PTR_ERR(regmap));
+		return PTR_ERR(regmap);
+	}
+
+	return hts221_probe(&client->dev, client->irq,
+			    client->name, regmap);
+}
+
+static const struct acpi_device_id hts221_acpi_match[] = {
+	{"SMO9100", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, hts221_acpi_match);
+
+static const struct of_device_id hts221_i2c_of_match[] = {
+	{ .compatible = "st,hts221", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hts221_i2c_of_match);
+
+static const struct i2c_device_id hts221_i2c_id_table[] = {
+	{ HTS221_DEV_NAME },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table);
+
+static struct i2c_driver hts221_driver = {
+	.driver = {
+		.name = "hts221_i2c",
+		.pm = &hts221_pm_ops,
+		.of_match_table = of_match_ptr(hts221_i2c_of_match),
+		.acpi_match_table = ACPI_PTR(hts221_acpi_match),
+	},
+	.probe = hts221_i2c_probe,
+	.id_table = hts221_i2c_id_table,
+};
+module_i2c_driver(hts221_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics hts221 i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c
new file mode 100644
index 0000000..9c005f0
--- /dev/null
+++ b/drivers/iio/humidity/hts221_spi.c
@@ -0,0 +1,69 @@
+/*
+ * STMicroelectronics hts221 spi driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+#include "hts221.h"
+
+#define HTS221_SPI_READ			BIT(7)
+#define HTS221_SPI_AUTO_INCREMENT	BIT(6)
+
+static const struct regmap_config hts221_spi_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.write_flag_mask = HTS221_SPI_AUTO_INCREMENT,
+	.read_flag_mask = HTS221_SPI_READ | HTS221_SPI_AUTO_INCREMENT,
+};
+
+static int hts221_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spi(spi, &hts221_spi_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&spi->dev, "Failed to register spi regmap %d\n",
+			(int)PTR_ERR(regmap));
+		return PTR_ERR(regmap);
+	}
+
+	return hts221_probe(&spi->dev, spi->irq,
+			    spi->modalias, regmap);
+}
+
+static const struct of_device_id hts221_spi_of_match[] = {
+	{ .compatible = "st,hts221", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hts221_spi_of_match);
+
+static const struct spi_device_id hts221_spi_id_table[] = {
+	{ HTS221_DEV_NAME },
+	{},
+};
+MODULE_DEVICE_TABLE(spi, hts221_spi_id_table);
+
+static struct spi_driver hts221_driver = {
+	.driver = {
+		.name = "hts221_spi",
+		.pm = &hts221_pm_ops,
+		.of_match_table = of_match_ptr(hts221_spi_of_match),
+	},
+	.probe = hts221_spi_probe,
+	.id_table = hts221_spi_id_table,
+};
+module_spi_driver(hts221_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics hts221 spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
new file mode 100644
index 0000000..f5a2701
--- /dev/null
+++ b/drivers/iio/humidity/htu21.c
@@ -0,0 +1,261 @@
+/*
+ * htu21.c - Support for Measurement-Specialties
+ *           htu21 temperature & humidity sensor
+ *	     and humidity part of MS8607 sensor
+ *
+ * Copyright (c) 2014 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/HTU21D.pdf
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+#define HTU21_RESET				0xFE
+
+enum {
+	HTU21,
+	MS8607
+};
+
+static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
+/* String copy of the above const for readability purpose */
+static const char htu21_show_samp_freq[] = "20 40 70 120";
+
+static int htu21_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *channel, int *val,
+			  int *val2, long mask)
+{
+	int ret, temperature;
+	unsigned int humidity;
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (channel->type) {
+		case IIO_TEMP:	/* in milli °C */
+			ret = ms_sensors_ht_read_temperature(dev_data,
+							     &temperature);
+			if (ret)
+				return ret;
+			*val = temperature;
+
+			return IIO_VAL_INT;
+		case IIO_HUMIDITYRELATIVE:	/* in milli %RH */
+			ret = ms_sensors_ht_read_humidity(dev_data,
+							  &humidity);
+			if (ret)
+				return ret;
+			*val = humidity;
+
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val = htu21_samp_freq[dev_data->res_index];
+
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int htu21_write_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int val, int val2, long mask)
+{
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+	int i, ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		i = ARRAY_SIZE(htu21_samp_freq);
+		while (i-- > 0)
+			if (val == htu21_samp_freq[i])
+				break;
+		if (i < 0)
+			return -EINVAL;
+		mutex_lock(&dev_data->lock);
+		dev_data->res_index = i;
+		ret = ms_sensors_write_resolution(dev_data, i);
+		mutex_unlock(&dev_data->lock);
+
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_chan_spec htu21_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	 },
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	 }
+};
+
+/*
+ * Meas Spec recommendation is to not read temperature
+ * on this driver part for MS8607
+ */
+static const struct iio_chan_spec ms8607_channels[] = {
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	 }
+};
+
+static ssize_t htu21_show_battery_low(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	return ms_sensors_show_battery_low(dev_data, buf);
+}
+
+static ssize_t htu21_show_heater(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	return ms_sensors_show_heater(dev_data, buf);
+}
+
+static ssize_t htu21_write_heater(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	return ms_sensors_write_heater(dev_data, buf, len);
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(htu21_show_samp_freq);
+static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
+		       htu21_show_battery_low, NULL, 0);
+static IIO_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR,
+		       htu21_show_heater, htu21_write_heater, 0);
+
+static struct attribute *htu21_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_battery_low.dev_attr.attr,
+	&iio_dev_attr_heater_enable.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group htu21_attribute_group = {
+	.attrs = htu21_attributes,
+};
+
+static const struct iio_info htu21_info = {
+	.read_raw = htu21_read_raw,
+	.write_raw = htu21_write_raw,
+	.attrs = &htu21_attribute_group,
+};
+
+static int htu21_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct ms_ht_dev *dev_data;
+	struct iio_dev *indio_dev;
+	int ret;
+	u64 serial_number;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WRITE_BYTE |
+				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+		dev_err(&client->dev,
+			"Adapter does not support some i2c transaction\n");
+		return -EOPNOTSUPP;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	dev_data = iio_priv(indio_dev);
+	dev_data->client = client;
+	dev_data->res_index = 0;
+	mutex_init(&dev_data->lock);
+
+	indio_dev->info = &htu21_info;
+	indio_dev->name = id->name;
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	if (id->driver_data == MS8607) {
+		indio_dev->channels = ms8607_channels;
+		indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
+	} else {
+		indio_dev->channels = htu21_channels;
+		indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
+	}
+
+	i2c_set_clientdata(client, indio_dev);
+
+	ret = ms_sensors_reset(client, HTU21_RESET, 15000);
+	if (ret)
+		return ret;
+
+	ret = ms_sensors_read_serial(client, &serial_number);
+	if (ret)
+		return ret;
+	dev_info(&client->dev, "Serial number : %llx", serial_number);
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id htu21_id[] = {
+	{"htu21", HTU21},
+	{"ms8607-humidity", MS8607},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, htu21_id);
+
+static const struct of_device_id htu21_of_match[] = {
+	{ .compatible = "meas,htu21", },
+	{ .compatible = "meas,ms8607-humidity", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, htu21_of_match);
+
+static struct i2c_driver htu21_driver = {
+	.probe = htu21_probe,
+	.id_table = htu21_id,
+	.driver = {
+		   .name = "htu21",
+		   .of_match_table = of_match_ptr(htu21_of_match),
+		   },
+};
+
+module_i2c_driver(htu21_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
new file mode 100644
index 0000000..1fd19f0
--- /dev/null
+++ b/drivers/iio/humidity/si7005.c
@@ -0,0 +1,188 @@
+/*
+ * si7005.c - Support for Silabs Si7005 humidity and temperature sensor
+ *
+ * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * TODO: heater, fast mode, processed mode (temp. / linearity compensation)
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define SI7005_STATUS 0x00
+#define SI7005_DATA 0x01 /* 16-bit, MSB */
+#define SI7005_CONFIG 0x03
+#define SI7005_ID 0x11
+
+#define SI7005_STATUS_NRDY BIT(0)
+#define SI7005_CONFIG_TEMP BIT(4)
+#define SI7005_CONFIG_START BIT(0)
+
+#define SI7005_ID_7005 0x50
+#define SI7005_ID_7015 0xf0
+
+struct si7005_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	u8 config;
+};
+
+static int si7005_read_measurement(struct si7005_data *data, bool temp)
+{
+	int tries = 50;
+	int ret;
+
+	mutex_lock(&data->lock);
+
+	ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG,
+		data->config | SI7005_CONFIG_START |
+		(temp ? SI7005_CONFIG_TEMP : 0));
+	if (ret < 0)
+		goto done;
+
+	while (tries-- > 0) {
+		msleep(20);
+		ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS);
+		if (ret < 0)
+			goto done;
+		if (!(ret & SI7005_STATUS_NRDY))
+			break;
+	}
+	if (tries < 0) {
+		ret = -EIO;
+		goto done;
+	}
+
+	ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA);
+
+done:
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int si7005_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan, int *val,
+			    int *val2, long mask)
+{
+	struct si7005_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = si7005_read_measurement(data, chan->type == IIO_TEMP);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_TEMP) {
+			*val = 7;
+			*val2 = 812500;
+		} else {
+			*val = 3;
+			*val2 = 906250;
+		}
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		if (chan->type == IIO_TEMP)
+			*val = -50 * 32 * 4;
+		else
+			*val = -24 * 16 * 16;
+		return IIO_VAL_INT;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_chan_spec si7005_channels[] = {
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+	},
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+	}
+};
+
+static const struct iio_info si7005_info = {
+	.read_raw = si7005_read_raw,
+};
+
+static int si7005_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct iio_dev *indio_dev;
+	struct si7005_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -EOPNOTSUPP;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = dev_name(&client->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &si7005_info;
+
+	indio_dev->channels = si7005_channels;
+	indio_dev->num_channels = ARRAY_SIZE(si7005_channels);
+
+	ret = i2c_smbus_read_byte_data(client, SI7005_ID);
+	if (ret < 0)
+		return ret;
+	if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015)
+		return -ENODEV;
+
+	ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG);
+	if (ret < 0)
+		return ret;
+	data->config = ret;
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id si7005_id[] = {
+	{ "si7005", 0 },
+	{ "th02", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, si7005_id);
+
+static struct i2c_driver si7005_driver = {
+	.driver = {
+		.name	= "si7005",
+	},
+	.probe = si7005_probe,
+	.id_table = si7005_id,
+};
+module_i2c_driver(si7005_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c
new file mode 100644
index 0000000..1b2ec8d
--- /dev/null
+++ b/drivers/iio/humidity/si7020.c
@@ -0,0 +1,174 @@
+/*
+ * si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors
+ * Copyright (c) 2013,2014  Uplogix, Inc.
+ * David Barksdale <dbarksdale@uplogix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors
+ * are i2c devices which have an identical programming interface for
+ * measuring relative humidity and temperature. The Si7013 has an additional
+ * temperature input which this driver does not support.
+ *
+ * Data Sheets:
+ *   Si7013: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7013.pdf
+ *   Si7020: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7020.pdf
+ *   Si7021: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7021.pdf
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* Measure Relative Humidity, Hold Master Mode */
+#define SI7020CMD_RH_HOLD	0xE5
+/* Measure Temperature, Hold Master Mode */
+#define SI7020CMD_TEMP_HOLD	0xE3
+/* Software Reset */
+#define SI7020CMD_RESET		0xFE
+
+static int si7020_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan, int *val,
+			   int *val2, long mask)
+{
+	struct i2c_client **client = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = i2c_smbus_read_word_swapped(*client,
+						  chan->type == IIO_TEMP ?
+						  SI7020CMD_TEMP_HOLD :
+						  SI7020CMD_RH_HOLD);
+		if (ret < 0)
+			return ret;
+		*val = ret >> 2;
+		/*
+		 * Humidity values can slightly exceed the 0-100%RH
+		 * range and should be corrected by software
+		 */
+		if (chan->type == IIO_HUMIDITYRELATIVE)
+			*val = clamp_val(*val, 786, 13893);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_TEMP)
+			*val = 175720; /* = 175.72 * 1000 */
+		else
+			*val = 125 * 1000;
+		*val2 = 65536 >> 2;
+		return IIO_VAL_FRACTIONAL;
+	case IIO_CHAN_INFO_OFFSET:
+		/*
+		 * Since iio_convert_raw_to_processed_unlocked assumes offset
+		 * is an integer we have to round these values and lose
+		 * accuracy.
+		 * Relative humidity will be 0.0032959% too high and
+		 * temperature will be 0.00277344 degrees too high.
+		 * This is no big deal because it's within the accuracy of the
+		 * sensor.
+		 */
+		if (chan->type == IIO_TEMP)
+			*val = -4368; /* = -46.85 * (65536 >> 2) / 175.72 */
+		else
+			*val = -786; /* = -6 * (65536 >> 2) / 125 */
+		return IIO_VAL_INT;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_chan_spec si7020_channels[] = {
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+	},
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+	}
+};
+
+static const struct iio_info si7020_info = {
+	.read_raw = si7020_read_raw,
+};
+
+static int si7020_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct iio_dev *indio_dev;
+	struct i2c_client **data;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WRITE_BYTE |
+				     I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EOPNOTSUPP;
+
+	/* Reset device, loads default settings. */
+	ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
+	if (ret < 0)
+		return ret;
+	/* Wait the maximum power-up time after software reset. */
+	msleep(15);
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	*data = client;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = dev_name(&client->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &si7020_info;
+	indio_dev->channels = si7020_channels;
+	indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id si7020_id[] = {
+	{ "si7020", 0 },
+	{ "th06", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, si7020_id);
+
+static const struct of_device_id si7020_dt_ids[] = {
+	{ .compatible = "silabs,si7020" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, si7020_dt_ids);
+
+static struct i2c_driver si7020_driver = {
+	.driver = {
+		.name = "si7020",
+		.of_match_table = of_match_ptr(si7020_dt_ids),
+	},
+	.probe		= si7020_probe,
+	.id_table	= si7020_id,
+};
+
+module_i2c_driver(si7020_driver);
+MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors");
+MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
+MODULE_LICENSE("GPL");