diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 738b56f862b455a904517103301125f7c723a0a3..d760b0224ef7b99f30632f07bf7a0986c6ce92e5 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -260,6 +260,10 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_z_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_scale
 KernelVersion:	2.6.35
@@ -447,6 +451,14 @@ What:		/sys/.../iio:deviceX/events/in_magn_y_thresh_rising_en
 What:		/sys/.../iio:deviceX/events/in_magn_y_thresh_falling_en
 What:		/sys/.../iio:deviceX/events/in_magn_z_thresh_rising_en
 What:		/sys/.../iio:deviceX/events/in_magn_z_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_magnetic_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_magnetic_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_true_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_true_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_thresh_rising_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_thresh_falling_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
@@ -492,6 +504,14 @@ What:		/sys/.../iio:deviceX/events/in_magn_y_roc_rising_en
 What:		/sys/.../iio:deviceX/events/in_magn_y_roc_falling_en
 What:		/sys/.../iio:deviceX/events/in_magn_z_roc_rising_en
 What:		/sys/.../iio:deviceX/events/in_magn_z_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_magnetic_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_magnetic_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_true_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_true_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_roc_falling_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_roc_rising_en
+What:		/sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_roc_falling_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_supply_roc_rising_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_supply_roc_falling_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_roc_rising_en
@@ -538,6 +558,14 @@ What:		/sys/.../events/in_magn_y_raw_thresh_rising_value
 What:		/sys/.../events/in_magn_y_raw_thresh_falling_value
 What:		/sys/.../events/in_magn_z_raw_thresh_rising_value
 What:		/sys/.../events/in_magn_z_raw_thresh_falling_value
+What:		/sys/.../events/in_rot_from_north_magnetic_raw_thresh_rising_value
+What:		/sys/.../events/in_rot_from_north_magnetic_raw_thresh_falling_value
+What:		/sys/.../events/in_rot_from_north_true_raw_thresh_rising_value
+What:		/sys/.../events/in_rot_from_north_true_raw_thresh_falling_value
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_thresh_rising_value
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_thresh_falling_value
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_raw_thresh_rising_value
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_raw_thresh_falling_value
 What:		/sys/.../events/in_voltageY_supply_raw_thresh_rising_value
 What:		/sys/.../events/in_voltageY_supply_raw_thresh_falling_value
 What:		/sys/.../events/in_voltageY_raw_thresh_rising_value
@@ -588,6 +616,18 @@ What:		/sys/.../events/in_magn_y_thresh_either_hysteresis
 What:		/sys/.../events/in_magn_z_thresh_rising_hysteresis
 What:		/sys/.../events/in_magn_z_thresh_falling_hysteresis
 What:		/sys/.../events/in_magn_z_thresh_either_hysteresis
+What:		/sys/.../events/in_rot_from_north_magnetic_thresh_rising_hysteresis
+What:		/sys/.../events/in_rot_from_north_magnetic_thresh_falling_hysteresis
+What:		/sys/.../events/in_rot_from_north_magnetic_thresh_either_hysteresis
+What:		/sys/.../events/in_rot_from_north_true_thresh_rising_hysteresis
+What:		/sys/.../events/in_rot_from_north_true_thresh_falling_hysteresis
+What:		/sys/.../events/in_rot_from_north_true_thresh_either_hysteresis
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_hysteresis
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_hysteresis
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_either_hysteresis
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_thresh_rising_hysteresis
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_thresh_falling_hysteresis
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_thresh_either_hysteresis
 What:		/sys/.../events/in_voltageY_thresh_rising_hysteresis
 What:		/sys/.../events/in_voltageY_thresh_falling_hysteresis
 What:		/sys/.../events/in_voltageY_thresh_either_hysteresis
@@ -635,6 +675,14 @@ What:		/sys/.../events/in_magn_y_raw_roc_rising_value
 What:		/sys/.../events/in_magn_y_raw_roc_falling_value
 What:		/sys/.../events/in_magn_z_raw_roc_rising_value
 What:		/sys/.../events/in_magn_z_raw_roc_falling_value
+What:		/sys/.../events/in_rot_from_north_magnetic_raw_roc_rising_value
+What:		/sys/.../events/in_rot_from_north_magnetic_raw_roc_falling_value
+What:		/sys/.../events/in_rot_from_north_true_raw_roc_rising_value
+What:		/sys/.../events/in_rot_from_north_true_raw_roc_falling_value
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_roc_rising_value
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_roc_falling_value
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_raw_roc_rising_value
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_raw_roc_falling_value
 What:		/sys/.../events/in_voltageY_supply_raw_roc_rising_value
 What:		/sys/.../events/in_voltageY_supply_raw_roc_falling_value
 What:		/sys/.../events/in_voltageY_raw_roc_rising_value
@@ -690,6 +738,22 @@ What:		/sys/.../events/in_magn_z_thresh_rising_period
 What:		/sys/.../events/in_magn_z_thresh_falling_period
 What:		/sys/.../events/in_magn_z_roc_rising_period
 What:		/sys/.../events/in_magn_z_roc_falling_period
+What:		/sys/.../events/in_rot_from_north_magnetic_thresh_rising_period
+What:		/sys/.../events/in_rot_from_north_magnetic_thresh_falling_period
+What:		/sys/.../events/in_rot_from_north_magnetic_roc_rising_period
+What:		/sys/.../events/in_rot_from_north_magnetic_roc_falling_period
+What:		/sys/.../events/in_rot_from_north_true_thresh_rising_period
+What:		/sys/.../events/in_rot_from_north_true_thresh_falling_period
+What:		/sys/.../events/in_rot_from_north_true_roc_rising_period
+What:		/sys/.../events/in_rot_from_north_true_roc_falling_period
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_period
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_period
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_roc_rising_period
+What:		/sys/.../events/in_rot_from_north_magnetic_tilt_comp_roc_falling_period
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_thresh_rising_period
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_thresh_falling_period
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_roc_rising_period
+What:		/sys/.../events/in_rot_from_north_true_tilt_comp_roc_falling_period
 What:		/sys/.../events/in_voltageY_supply_thresh_rising_period
 What:		/sys/.../events/in_voltageY_supply_thresh_falling_period
 What:		/sys/.../events/in_voltageY_supply_roc_rising_period
@@ -787,6 +851,10 @@ What:		/sys/.../iio:deviceX/scan_elements/in_anglvel_z_en
 What:		/sys/.../iio:deviceX/scan_elements/in_magn_x_en
 What:		/sys/.../iio:deviceX/scan_elements/in_magn_y_en
 What:		/sys/.../iio:deviceX/scan_elements/in_magn_z_en
+What:		/sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_en
+What:		/sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_en
+What:		/sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_en
+What:		/sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_en
 What:		/sys/.../iio:deviceX/scan_elements/in_timestamp_en
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_supply_en
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_en
@@ -853,6 +921,10 @@ What:		/sys/.../iio:deviceX/scan_elements/in_anglvel_z_index
 What:		/sys/.../iio:deviceX/scan_elements/in_magn_x_index
 What:		/sys/.../iio:deviceX/scan_elements/in_magn_y_index
 What:		/sys/.../iio:deviceX/scan_elements/in_magn_z_index
+What:		/sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_index
+What:		/sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_index
+What:		/sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_index
+What:		/sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_index
 What:		/sys/.../iio:deviceX/scan_elements/in_incli_x_index
 What:		/sys/.../iio:deviceX/scan_elements/in_incli_y_index
 What:		/sys/.../iio:deviceX/scan_elements/in_timestamp_index
@@ -946,3 +1018,13 @@ Description:
 		x y z w. Here x, y, and z component represents the axis about
 		which a rotation will occur and w component represents the
 		amount of rotation.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_raw
+KernelVersion:	3.15
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw value of rotation from true/magnetic north measured with
+		or without compensation from tilt sensors.
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
index 832fe8cc24d706e586242deebfd670791c7ad8b4..adc61b095bd1b07d5094fee65654f1caa365fa21 100644
--- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
@@ -14,14 +14,21 @@ Required properties:
 				for exynos4412/5250 controllers.
 			Must be "samsung,exynos-adc-v2" for
 				future controllers.
+			Must be "samsung,exynos3250-adc" for
+				controllers compatible with ADC of Exynos3250.
 - reg:			Contains ADC register address range (base address and
 			length) and the address of the phy enable register.
 - interrupts: 		Contains the interrupt information for the timer. The
 			format is being dependent on which interrupt controller
 			the Samsung device uses.
 - #io-channel-cells = <1>; As ADC has multiple outputs
-- clocks		From common clock binding: handle to adc clock.
-- clock-names		From common clock binding: Shall be "adc".
+- clocks		From common clock bindings: handles to clocks specified
+			in "clock-names" property, in the same order.
+- clock-names		From common clock bindings: list of clock input names
+			used by ADC block:
+			- "adc" : ADC bus clock
+			- "sclk" : ADC special clock (only for Exynos3250 and
+				   compatible ADC block)
 - vdd-supply		VDD input supply.
 
 Note: child nodes can be added for auto probing from device tree.
@@ -41,6 +48,20 @@ adc: adc@12D10000 {
 	vdd-supply = <&buck5_reg>;
 };
 
+Example: adding device info in dtsi file for Exynos3250 with additional sclk
+
+adc: adc@126C0000 {
+	compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2;
+	reg = <0x126C0000 0x100>, <0x10020718 0x4>;
+	interrupts = <0 137 0>;
+	#io-channel-cells = <1>;
+	io-channel-ranges;
+
+	clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
+	clock-names = "adc", "sclk";
+
+	vdd-supply = <&buck5_reg>;
+};
 
 Example: Adding child nodes in dts file
 
diff --git a/Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt b/Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt
index b8cbdd517abc507f4b57d528ca4dd3bd19eacadd..8e191eef014e6112696b3c82678fb20dbe3dc553 100644
--- a/Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt
+++ b/Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt
@@ -6,6 +6,7 @@ Required properties:
   Other models which are supported with driver are:
 	"honeywell,hmc5883"
 	"honeywell,hmc5883l"
+	"honeywell,hmc5983"
   - reg : the I2C address of the magnetometer - typically 0x1e
 
 Optional properties:
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 3e678fa335bf7dc2981bb3a7c7a19f6871f68617..aaaac798120012d66abdfaa83c010ac36b8123e5 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -261,10 +261,11 @@ pdma1: pdma@12690000 {
 		};
 
 		adc: adc@126C0000 {
-			compatible = "samsung,exynos-adc-v3";
+			compatible = "samsung,exynos3250-adc",
+				     "samsung,exynos-adc-v2";
 			reg = <0x126C0000 0x100>, <0x10020718 0x4>;
 			interrupts = <0 137 0>;
-			clock-names = "adc", "sclk_tsadc";
+			clock-names = "adc", "sclk";
 			clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
 			#io-channel-cells = <1>;
 			io-channel-ranges;
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 72a6dbbc18d16bbf96f60dfde63efb9a1aeed83a..7941cf2d31eec0783031fb304843614ed0911726 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -98,7 +98,7 @@ static const struct {
 	int val2;
 	int odr_bits;
 } samp_freq_table[] = { {0, 781000, 0x08}, {1, 563000, 0x09},
-			{3, 125000, 0x0A}, {6, 25000, 0x0B}, {12, 5000, 0},
+			{3, 125000, 0x0A}, {6, 250000, 0x0B}, {12, 500000, 0},
 			{25, 0, 0x01}, {50, 0, 0x02}, {100, 0, 0x03},
 			{200, 0, 0x04}, {400, 0, 0x05}, {800, 0, 0x06},
 			{1600, 0, 0x07} };
@@ -138,19 +138,6 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
 	return 0;
 }
 
-static int kxcjk1013_chip_ack_intr(struct kxcjk1013_data *data)
-{
-	int ret;
-
-	ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_rel\n");
-		return ret;
-	}
-
-	return ret;
-}
-
 static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
 {
 	int ret;
@@ -466,7 +453,7 @@ static const struct attribute_group kxcjk1013_attrs_group = {
 		.realbits = 12,						\
 		.storagebits = 16,					\
 		.shift = 4,						\
-		.endianness = IIO_LE,					\
+		.endianness = IIO_CPU,					\
 	},								\
 }
 
@@ -498,15 +485,11 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
 			 indio_dev->masklength) {
 		ret = kxcjk1013_get_acc_reg(data, bit);
 		if (ret < 0) {
-			kxcjk1013_chip_ack_intr(data);
 			mutex_unlock(&data->mutex);
 			goto err;
 		}
 		data->buffer[i++] = ret;
 	}
-
-	kxcjk1013_chip_ack_intr(data);
-
 	mutex_unlock(&data->mutex);
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
@@ -517,6 +500,21 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
+static int kxcjk1013_trig_try_reen(struct iio_trigger *trig)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct kxcjk1013_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_int_rel\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
 						bool state)
 {
@@ -543,6 +541,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
 
 static const struct iio_trigger_ops kxcjk1013_trigger_ops = {
 	.set_trigger_state = kxcjk1013_data_rdy_trigger_set_state,
+	.try_reenable = kxcjk1013_trig_try_reen,
 	.owner = THIS_MODULE,
 };
 
@@ -645,6 +644,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
 		iio_trigger_set_drvdata(trig, indio_dev);
 		data->trig = trig;
 		indio_dev->trig = trig;
+		iio_trigger_get(indio_dev->trig);
 
 		ret = iio_trigger_register(trig);
 		if (ret)
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 6cf9ee18a2161f7e7972b037b7259a9ffa87cc83..e37412da15f5c8ea300c7a096368d564a0acfba0 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -32,6 +32,7 @@
 #include <linux/types.h>
 #include <linux/err.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -41,7 +42,7 @@
 #include <linux/iio/triggered_buffer.h>
 
 #define AD799X_CHANNEL_SHIFT			4
-#define AD799X_STORAGEBITS			16
+
 /*
  * AD7991, AD7995 and AD7999 defines
  */
@@ -55,10 +56,10 @@
  * AD7992, AD7993, AD7994, AD7997 and AD7998 defines
  */
 
-#define AD7998_FLTR				0x08
-#define AD7998_ALERT_EN				0x04
-#define AD7998_BUSY_ALERT			0x02
-#define AD7998_BUSY_ALERT_POL			0x01
+#define AD7998_FLTR				BIT(3)
+#define AD7998_ALERT_EN				BIT(2)
+#define AD7998_BUSY_ALERT			BIT(1)
+#define AD7998_BUSY_ALERT_POL			BIT(0)
 
 #define AD7998_CONV_RES_REG			0x0
 #define AD7998_ALERT_STAT_REG			0x1
@@ -69,7 +70,7 @@
 #define AD7998_DATAHIGH_REG(x)			((x) * 3 + 0x5)
 #define AD7998_HYST_REG(x)			((x) * 3 + 0x6)
 
-#define AD7998_CYC_MASK				0x7
+#define AD7998_CYC_MASK				GENMASK(2, 0)
 #define AD7998_CYC_DIS				0x0
 #define AD7998_CYC_TCONF_32			0x1
 #define AD7998_CYC_TCONF_64			0x2
@@ -85,10 +86,8 @@
  * AD7997 and AD7997 defines
  */
 
-#define AD7997_8_READ_SINGLE			0x80
-#define AD7997_8_READ_SEQUENCE			0x70
-/* TODO: move this into a common header */
-#define RES_MASK(bits)	((1 << (bits)) - 1)
+#define AD7997_8_READ_SINGLE			BIT(7)
+#define AD7997_8_READ_SEQUENCE			(BIT(6) | BIT(5) | BIT(4))
 
 enum {
 	ad7991,
@@ -102,22 +101,32 @@ enum {
 };
 
 /**
- * struct ad799x_chip_info - chip specific information
+ * struct ad799x_chip_config - chip specific information
  * @channel:		channel specification
- * @num_channels:	number of channels
  * @default_config:	device default configuration
  * @info:		pointer to iio_info struct
  */
-struct ad799x_chip_info {
-	struct iio_chan_spec		channel[9];
-	int				num_channels;
+struct ad799x_chip_config {
+	const struct iio_chan_spec	channel[9];
 	u16				default_config;
 	const struct iio_info		*info;
 };
 
+/**
+ * struct ad799x_chip_info - chip specific information
+ * @num_channels:	number of channels
+ * @noirq_config:	device configuration w/o IRQ
+ * @irq_config:		device configuration w/IRQ
+ */
+struct ad799x_chip_info {
+	int				num_channels;
+	const struct ad799x_chip_config	noirq_config;
+	const struct ad799x_chip_config	irq_config;
+};
+
 struct ad799x_state {
 	struct i2c_client		*client;
-	const struct ad799x_chip_info	*chip_info;
+	const struct ad799x_chip_config	*chip_config;
 	struct regulator		*reg;
 	struct regulator		*vref;
 	unsigned			id;
@@ -127,6 +136,30 @@ struct ad799x_state {
 	unsigned int			transfer_size;
 };
 
+static int ad799x_write_config(struct ad799x_state *st, u16 val)
+{
+	switch (st->id) {
+	case ad7997:
+	case ad7998:
+		return i2c_smbus_write_word_swapped(st->client, AD7998_CONF_REG,
+			val);
+	default:
+		return i2c_smbus_write_byte_data(st->client, AD7998_CONF_REG,
+			val);
+	}
+}
+
+static int ad799x_read_config(struct ad799x_state *st)
+{
+	switch (st->id) {
+	case ad7997:
+	case ad7998:
+		return i2c_smbus_read_word_swapped(st->client, AD7998_CONF_REG);
+	default:
+		return i2c_smbus_read_byte_data(st->client, AD7998_CONF_REG);
+	}
+}
+
 /**
  * ad799x_trigger_handler() bh of trigger launched polling to ring buffer
  *
@@ -175,66 +208,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
-/*
- * ad799x register access by I2C
- */
-static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data)
-{
-	struct i2c_client *client = st->client;
-	int ret = 0;
-
-	ret = i2c_smbus_read_word_swapped(client, reg);
-	if (ret < 0) {
-		dev_err(&client->dev, "I2C read error\n");
-		return ret;
-	}
-
-	*data = (u16)ret;
-
-	return 0;
-}
-
-static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data)
-{
-	struct i2c_client *client = st->client;
-	int ret = 0;
-
-	ret = i2c_smbus_read_byte_data(client, reg);
-	if (ret < 0) {
-		dev_err(&client->dev, "I2C read error\n");
-		return ret;
-	}
-
-	*data = (u8)ret;
-
-	return 0;
-}
-
-static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data)
-{
-	struct i2c_client *client = st->client;
-	int ret = 0;
-
-	ret = i2c_smbus_write_word_swapped(client, reg, data);
-	if (ret < 0)
-		dev_err(&client->dev, "I2C write error\n");
-
-	return ret;
-}
-
-static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data)
-{
-	struct i2c_client *client = st->client;
-	int ret = 0;
-
-	ret = i2c_smbus_write_byte_data(client, reg, data);
-	if (ret < 0)
-		dev_err(&client->dev, "I2C write error\n");
-
-	return ret;
-}
-
-static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev,
+static int ad799x_update_scan_mode(struct iio_dev *indio_dev,
 	const unsigned long *scan_mask)
 {
 	struct ad799x_state *st = iio_priv(indio_dev);
@@ -247,33 +221,33 @@ static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev,
 	st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2;
 
 	switch (st->id) {
+	case ad7992:
+	case ad7993:
+	case ad7994:
 	case ad7997:
 	case ad7998:
-		return ad799x_i2c_write16(st, AD7998_CONF_REG,
-			st->config | (*scan_mask << AD799X_CHANNEL_SHIFT));
+		st->config &= ~(GENMASK(7, 0) << AD799X_CHANNEL_SHIFT);
+		st->config |= (*scan_mask << AD799X_CHANNEL_SHIFT);
+		return ad799x_write_config(st, st->config);
 	default:
-		break;
+		return 0;
 	}
-
-	return 0;
 }
 
 static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
 {
-	u16 rxbuf;
 	u8 cmd;
-	int ret;
 
 	switch (st->id) {
 	case ad7991:
 	case ad7995:
 	case ad7999:
-		cmd = st->config | ((1 << ch) << AD799X_CHANNEL_SHIFT);
+		cmd = st->config | (BIT(ch) << AD799X_CHANNEL_SHIFT);
 		break;
 	case ad7992:
 	case ad7993:
 	case ad7994:
-		cmd = (1 << ch) << AD799X_CHANNEL_SHIFT;
+		cmd = BIT(ch) << AD799X_CHANNEL_SHIFT;
 		break;
 	case ad7997:
 	case ad7998:
@@ -283,11 +257,7 @@ static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
 		return -EINVAL;
 	}
 
-	ret = ad799x_i2c_read16(st, cmd, &rxbuf);
-	if (ret < 0)
-		return ret;
-
-	return rxbuf;
+	return i2c_smbus_read_word_swapped(st->client, cmd);
 }
 
 static int ad799x_read_raw(struct iio_dev *indio_dev,
@@ -311,7 +281,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
 		if (ret < 0)
 			return ret;
 		*val = (ret >> chan->scan_type.shift) &
-			RES_MASK(chan->scan_type.realbits);
+			GENMASK(chan->scan_type.realbits - 1, 0);
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
 		ret = regulator_get_voltage(st->vref);
@@ -332,6 +302,7 @@ static const unsigned int ad7998_frequencies[] = {
 	[AD7998_CYC_TCONF_1024]	= 488,
 	[AD7998_CYC_TCONF_2048]	= 244,
 };
+
 static ssize_t ad799x_read_frequency(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
@@ -339,15 +310,11 @@ static ssize_t ad799x_read_frequency(struct device *dev,
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad799x_state *st = iio_priv(indio_dev);
 
-	int ret;
-	u8 val;
-	ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val);
-	if (ret)
+	int ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
+	if (ret < 0)
 		return ret;
 
-	val &= AD7998_CYC_MASK;
-
-	return sprintf(buf, "%u\n", ad7998_frequencies[val]);
+	return sprintf(buf, "%u\n", ad7998_frequencies[ret & AD7998_CYC_MASK]);
 }
 
 static ssize_t ad799x_write_frequency(struct device *dev,
@@ -360,18 +327,17 @@ static ssize_t ad799x_write_frequency(struct device *dev,
 
 	long val;
 	int ret, i;
-	u8 t;
 
 	ret = kstrtol(buf, 10, &val);
 	if (ret)
 		return ret;
 
 	mutex_lock(&indio_dev->mlock);
-	ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t);
-	if (ret)
+	ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
+	if (ret < 0)
 		goto error_ret_mutex;
 	/* Wipe the bits clean */
-	t &= ~AD7998_CYC_MASK;
+	ret &= ~AD7998_CYC_MASK;
 
 	for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++)
 		if (val == ad7998_frequencies[i])
@@ -380,13 +346,17 @@ static ssize_t ad799x_write_frequency(struct device *dev,
 		ret = -EINVAL;
 		goto error_ret_mutex;
 	}
-	t |= i;
-	ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t);
+
+	ret = i2c_smbus_write_byte_data(st->client, AD7998_CYCLE_TMR_REG,
+		ret | i);
+	if (ret < 0)
+		goto error_ret_mutex;
+	ret = len;
 
 error_ret_mutex:
 	mutex_unlock(&indio_dev->mlock);
 
-	return ret ? ret : len;
+	return ret;
 }
 
 static int ad799x_read_event_config(struct iio_dev *indio_dev,
@@ -394,7 +364,48 @@ static int ad799x_read_event_config(struct iio_dev *indio_dev,
 				    enum iio_event_type type,
 				    enum iio_event_direction dir)
 {
-	return 1;
+	struct ad799x_state *st = iio_priv(indio_dev);
+
+	if (!(st->config & AD7998_ALERT_EN))
+		return 0;
+
+	if ((st->config >> AD799X_CHANNEL_SHIFT) & BIT(chan->scan_index))
+		return 1;
+
+	return 0;
+}
+
+static int ad799x_write_event_config(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir,
+				     int state)
+{
+	struct ad799x_state *st = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	if (iio_buffer_enabled(indio_dev)) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	if (state)
+		st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
+	else
+		st->config &= ~(BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT);
+
+	if (st->config >> AD799X_CHANNEL_SHIFT)
+		st->config |= AD7998_ALERT_EN;
+	else
+		st->config &= ~AD7998_ALERT_EN;
+
+	ret = ad799x_write_config(st, st->config);
+
+done:
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
 }
 
 static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan,
@@ -426,11 +437,12 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev,
 	int ret;
 	struct ad799x_state *st = iio_priv(indio_dev);
 
-	if (val < 0 || val > RES_MASK(chan->scan_type.realbits))
+	if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
 		return -EINVAL;
 
 	mutex_lock(&indio_dev->mlock);
-	ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info),
+	ret = i2c_smbus_write_word_swapped(st->client,
+		ad799x_threshold_reg(chan, dir, info),
 		val << chan->scan_type.shift);
 	mutex_unlock(&indio_dev->mlock);
 
@@ -446,16 +458,15 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
 {
 	int ret;
 	struct ad799x_state *st = iio_priv(indio_dev);
-	u16 valin;
 
 	mutex_lock(&indio_dev->mlock);
-	ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info),
-		&valin);
+	ret = i2c_smbus_read_word_swapped(st->client,
+		ad799x_threshold_reg(chan, dir, info));
 	mutex_unlock(&indio_dev->mlock);
 	if (ret < 0)
 		return ret;
-	*val = (valin >> chan->scan_type.shift) &
-		RES_MASK(chan->scan_type.realbits);
+	*val = (ret >> chan->scan_type.shift) &
+		GENMASK(chan->scan_type.realbits - 1 , 0);
 
 	return IIO_VAL_INT;
 }
@@ -464,20 +475,18 @@ static irqreturn_t ad799x_event_handler(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
 	struct ad799x_state *st = iio_priv(private);
-	u8 status;
 	int i, ret;
 
-	ret = ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status);
-	if (ret)
+	ret = i2c_smbus_read_byte_data(st->client, AD7998_ALERT_STAT_REG);
+	if (ret <= 0)
 		goto done;
 
-	if (!status)
+	if (i2c_smbus_write_byte_data(st->client, AD7998_ALERT_STAT_REG,
+		AD7998_ALERT_STAT_CLEAR) < 0)
 		goto done;
 
-	ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR);
-
 	for (i = 0; i < 8; i++) {
-		if (status & (1 << i))
+		if (ret & BIT(i))
 			iio_push_event(indio_dev,
 				       i & 0x1 ?
 				       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
@@ -516,14 +525,21 @@ static const struct iio_info ad7991_info = {
 	.driver_module = THIS_MODULE,
 };
 
-static const struct iio_info ad7993_4_7_8_info = {
+static const struct iio_info ad7993_4_7_8_noirq_info = {
+	.read_raw = &ad799x_read_raw,
+	.driver_module = THIS_MODULE,
+	.update_scan_mode = ad799x_update_scan_mode,
+};
+
+static const struct iio_info ad7993_4_7_8_irq_info = {
 	.read_raw = &ad799x_read_raw,
 	.event_attrs = &ad799x_event_attrs_group,
 	.read_event_config = &ad799x_read_event_config,
+	.write_event_config = &ad799x_write_event_config,
 	.read_event_value = &ad799x_read_event_value,
 	.write_event_value = &ad799x_write_event_value,
 	.driver_module = THIS_MODULE,
-	.update_scan_mode = ad7997_8_update_scan_mode,
+	.update_scan_mode = ad799x_update_scan_mode,
 };
 
 static const struct iio_event_spec ad799x_events[] = {
@@ -571,103 +587,175 @@ static const struct iio_event_spec ad799x_events[] = {
 
 static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
 	[ad7991] = {
-		.channel = {
-			AD799X_CHANNEL(0, 12),
-			AD799X_CHANNEL(1, 12),
-			AD799X_CHANNEL(2, 12),
-			AD799X_CHANNEL(3, 12),
-			IIO_CHAN_SOFT_TIMESTAMP(4),
-		},
 		.num_channels = 5,
-		.info = &ad7991_info,
+		.noirq_config = {
+			.channel = {
+				AD799X_CHANNEL(0, 12),
+				AD799X_CHANNEL(1, 12),
+				AD799X_CHANNEL(2, 12),
+				AD799X_CHANNEL(3, 12),
+				IIO_CHAN_SOFT_TIMESTAMP(4),
+			},
+			.info = &ad7991_info,
+		},
 	},
 	[ad7995] = {
-		.channel = {
-			AD799X_CHANNEL(0, 10),
-			AD799X_CHANNEL(1, 10),
-			AD799X_CHANNEL(2, 10),
-			AD799X_CHANNEL(3, 10),
-			IIO_CHAN_SOFT_TIMESTAMP(4),
-		},
 		.num_channels = 5,
-		.info = &ad7991_info,
+		.noirq_config = {
+			.channel = {
+				AD799X_CHANNEL(0, 10),
+				AD799X_CHANNEL(1, 10),
+				AD799X_CHANNEL(2, 10),
+				AD799X_CHANNEL(3, 10),
+				IIO_CHAN_SOFT_TIMESTAMP(4),
+			},
+			.info = &ad7991_info,
+		},
 	},
 	[ad7999] = {
-		.channel = {
-			AD799X_CHANNEL(0, 8),
-			AD799X_CHANNEL(1, 8),
-			AD799X_CHANNEL(2, 8),
-			AD799X_CHANNEL(3, 8),
-			IIO_CHAN_SOFT_TIMESTAMP(4),
-		},
 		.num_channels = 5,
-		.info = &ad7991_info,
+		.noirq_config = {
+			.channel = {
+				AD799X_CHANNEL(0, 8),
+				AD799X_CHANNEL(1, 8),
+				AD799X_CHANNEL(2, 8),
+				AD799X_CHANNEL(3, 8),
+				IIO_CHAN_SOFT_TIMESTAMP(4),
+			},
+			.info = &ad7991_info,
+		},
 	},
 	[ad7992] = {
-		.channel = {
-			AD799X_CHANNEL_WITH_EVENTS(0, 12),
-			AD799X_CHANNEL_WITH_EVENTS(1, 12),
-			IIO_CHAN_SOFT_TIMESTAMP(3),
-		},
 		.num_channels = 3,
-		.default_config = AD7998_ALERT_EN,
-		.info = &ad7993_4_7_8_info,
+		.noirq_config = {
+			.channel = {
+				AD799X_CHANNEL(0, 12),
+				AD799X_CHANNEL(1, 12),
+				IIO_CHAN_SOFT_TIMESTAMP(3),
+			},
+			.info = &ad7993_4_7_8_noirq_info,
+		},
+		.irq_config = {
+			.channel = {
+				AD799X_CHANNEL_WITH_EVENTS(0, 12),
+				AD799X_CHANNEL_WITH_EVENTS(1, 12),
+				IIO_CHAN_SOFT_TIMESTAMP(3),
+			},
+			.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
+			.info = &ad7993_4_7_8_irq_info,
+		},
 	},
 	[ad7993] = {
-		.channel = {
-			AD799X_CHANNEL_WITH_EVENTS(0, 10),
-			AD799X_CHANNEL_WITH_EVENTS(1, 10),
-			AD799X_CHANNEL_WITH_EVENTS(2, 10),
-			AD799X_CHANNEL_WITH_EVENTS(3, 10),
-			IIO_CHAN_SOFT_TIMESTAMP(4),
-		},
 		.num_channels = 5,
-		.default_config = AD7998_ALERT_EN,
-		.info = &ad7993_4_7_8_info,
+		.noirq_config = {
+			.channel = {
+				AD799X_CHANNEL(0, 10),
+				AD799X_CHANNEL(1, 10),
+				AD799X_CHANNEL(2, 10),
+				AD799X_CHANNEL(3, 10),
+				IIO_CHAN_SOFT_TIMESTAMP(4),
+			},
+			.info = &ad7993_4_7_8_noirq_info,
+		},
+		.irq_config = {
+			.channel = {
+				AD799X_CHANNEL_WITH_EVENTS(0, 10),
+				AD799X_CHANNEL_WITH_EVENTS(1, 10),
+				AD799X_CHANNEL_WITH_EVENTS(2, 10),
+				AD799X_CHANNEL_WITH_EVENTS(3, 10),
+				IIO_CHAN_SOFT_TIMESTAMP(4),
+			},
+			.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
+			.info = &ad7993_4_7_8_irq_info,
+		},
 	},
 	[ad7994] = {
-		.channel = {
-			AD799X_CHANNEL_WITH_EVENTS(0, 12),
-			AD799X_CHANNEL_WITH_EVENTS(1, 12),
-			AD799X_CHANNEL_WITH_EVENTS(2, 12),
-			AD799X_CHANNEL_WITH_EVENTS(3, 12),
-			IIO_CHAN_SOFT_TIMESTAMP(4),
-		},
 		.num_channels = 5,
-		.default_config = AD7998_ALERT_EN,
-		.info = &ad7993_4_7_8_info,
+		.noirq_config = {
+			.channel = {
+				AD799X_CHANNEL(0, 12),
+				AD799X_CHANNEL(1, 12),
+				AD799X_CHANNEL(2, 12),
+				AD799X_CHANNEL(3, 12),
+				IIO_CHAN_SOFT_TIMESTAMP(4),
+			},
+			.info = &ad7993_4_7_8_noirq_info,
+		},
+		.irq_config = {
+			.channel = {
+				AD799X_CHANNEL_WITH_EVENTS(0, 12),
+				AD799X_CHANNEL_WITH_EVENTS(1, 12),
+				AD799X_CHANNEL_WITH_EVENTS(2, 12),
+				AD799X_CHANNEL_WITH_EVENTS(3, 12),
+				IIO_CHAN_SOFT_TIMESTAMP(4),
+			},
+			.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
+			.info = &ad7993_4_7_8_irq_info,
+		},
 	},
 	[ad7997] = {
-		.channel = {
-			AD799X_CHANNEL_WITH_EVENTS(0, 10),
-			AD799X_CHANNEL_WITH_EVENTS(1, 10),
-			AD799X_CHANNEL_WITH_EVENTS(2, 10),
-			AD799X_CHANNEL_WITH_EVENTS(3, 10),
-			AD799X_CHANNEL(4, 10),
-			AD799X_CHANNEL(5, 10),
-			AD799X_CHANNEL(6, 10),
-			AD799X_CHANNEL(7, 10),
-			IIO_CHAN_SOFT_TIMESTAMP(8),
-		},
 		.num_channels = 9,
-		.default_config = AD7998_ALERT_EN,
-		.info = &ad7993_4_7_8_info,
+		.noirq_config = {
+			.channel = {
+				AD799X_CHANNEL(0, 10),
+				AD799X_CHANNEL(1, 10),
+				AD799X_CHANNEL(2, 10),
+				AD799X_CHANNEL(3, 10),
+				AD799X_CHANNEL(4, 10),
+				AD799X_CHANNEL(5, 10),
+				AD799X_CHANNEL(6, 10),
+				AD799X_CHANNEL(7, 10),
+				IIO_CHAN_SOFT_TIMESTAMP(8),
+			},
+			.info = &ad7993_4_7_8_noirq_info,
+		},
+		.irq_config = {
+			.channel = {
+				AD799X_CHANNEL_WITH_EVENTS(0, 10),
+				AD799X_CHANNEL_WITH_EVENTS(1, 10),
+				AD799X_CHANNEL_WITH_EVENTS(2, 10),
+				AD799X_CHANNEL_WITH_EVENTS(3, 10),
+				AD799X_CHANNEL(4, 10),
+				AD799X_CHANNEL(5, 10),
+				AD799X_CHANNEL(6, 10),
+				AD799X_CHANNEL(7, 10),
+				IIO_CHAN_SOFT_TIMESTAMP(8),
+			},
+			.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
+			.info = &ad7993_4_7_8_irq_info,
+		},
 	},
 	[ad7998] = {
-		.channel = {
-			AD799X_CHANNEL_WITH_EVENTS(0, 12),
-			AD799X_CHANNEL_WITH_EVENTS(1, 12),
-			AD799X_CHANNEL_WITH_EVENTS(2, 12),
-			AD799X_CHANNEL_WITH_EVENTS(3, 12),
-			AD799X_CHANNEL(4, 12),
-			AD799X_CHANNEL(5, 12),
-			AD799X_CHANNEL(6, 12),
-			AD799X_CHANNEL(7, 12),
-			IIO_CHAN_SOFT_TIMESTAMP(8),
-		},
 		.num_channels = 9,
-		.default_config = AD7998_ALERT_EN,
-		.info = &ad7993_4_7_8_info,
+		.noirq_config = {
+			.channel = {
+				AD799X_CHANNEL(0, 12),
+				AD799X_CHANNEL(1, 12),
+				AD799X_CHANNEL(2, 12),
+				AD799X_CHANNEL(3, 12),
+				AD799X_CHANNEL(4, 12),
+				AD799X_CHANNEL(5, 12),
+				AD799X_CHANNEL(6, 12),
+				AD799X_CHANNEL(7, 12),
+				IIO_CHAN_SOFT_TIMESTAMP(8),
+			},
+			.info = &ad7993_4_7_8_noirq_info,
+		},
+		.irq_config = {
+			.channel = {
+				AD799X_CHANNEL_WITH_EVENTS(0, 12),
+				AD799X_CHANNEL_WITH_EVENTS(1, 12),
+				AD799X_CHANNEL_WITH_EVENTS(2, 12),
+				AD799X_CHANNEL_WITH_EVENTS(3, 12),
+				AD799X_CHANNEL(4, 12),
+				AD799X_CHANNEL(5, 12),
+				AD799X_CHANNEL(6, 12),
+				AD799X_CHANNEL(7, 12),
+				IIO_CHAN_SOFT_TIMESTAMP(8),
+			},
+			.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
+			.info = &ad7993_4_7_8_irq_info,
+		},
 	},
 };
 
@@ -677,6 +765,8 @@ static int ad799x_probe(struct i2c_client *client,
 	int ret;
 	struct ad799x_state *st;
 	struct iio_dev *indio_dev;
+	const struct ad799x_chip_info *chip_info =
+		&ad799x_chip_info_tbl[id->driver_data];
 
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
 	if (indio_dev == NULL)
@@ -687,8 +777,10 @@ static int ad799x_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, indio_dev);
 
 	st->id = id->driver_data;
-	st->chip_info = &ad799x_chip_info_tbl[st->id];
-	st->config = st->chip_info->default_config;
+	if (client->irq > 0 && chip_info->irq_config.info)
+		st->chip_config = &chip_info->irq_config;
+	else
+		st->chip_config = &chip_info->noirq_config;
 
 	/* TODO: Add pdata options for filtering and bit delay */
 
@@ -711,11 +803,19 @@ static int ad799x_probe(struct i2c_client *client,
 
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->name = id->name;
-	indio_dev->info = st->chip_info->info;
+	indio_dev->info = st->chip_config->info;
 
 	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = st->chip_info->channel;
-	indio_dev->num_channels = st->chip_info->num_channels;
+	indio_dev->channels = st->chip_config->channel;
+	indio_dev->num_channels = chip_info->num_channels;
+
+	ret = ad799x_write_config(st, st->chip_config->default_config);
+	if (ret < 0)
+		goto error_disable_reg;
+	ret = ad799x_read_config(st);
+	if (ret < 0)
+		goto error_disable_reg;
+	st->config = ret;
 
 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
 		&ad799x_trigger_handler, NULL);
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 010578f1d76264e68dec04fbd361b6958003f5cb..fc9dfc23ecb761ca1c39652e645ea642cf6d799c 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -24,6 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -39,11 +40,6 @@
 #include <linux/iio/machine.h>
 #include <linux/iio/driver.h>
 
-enum adc_version {
-	ADC_V1,
-	ADC_V2
-};
-
 /* EXYNOS4412/5250 ADC_V1 registers definitions */
 #define ADC_V1_CON(x)		((x) + 0x00)
 #define ADC_V1_DLY(x)		((x) + 0x08)
@@ -75,8 +71,9 @@ enum adc_version {
 #define ADC_V2_CON2_ACH_SEL(x)	(((x) & 0xF) << 0)
 #define ADC_V2_CON2_ACH_MASK	0xF
 
-#define MAX_ADC_V2_CHANNELS	10
-#define MAX_ADC_V1_CHANNELS	8
+#define MAX_ADC_V2_CHANNELS		10
+#define MAX_ADC_V1_CHANNELS		8
+#define MAX_EXYNOS3250_ADC_CHANNELS	2
 
 /* Bit definitions common for ADC_V1 and ADC_V2 */
 #define ADC_CON_EN_START	(1u << 0)
@@ -85,9 +82,12 @@ enum adc_version {
 #define EXYNOS_ADC_TIMEOUT	(msecs_to_jiffies(100))
 
 struct exynos_adc {
+	struct exynos_adc_data	*data;
+	struct device		*dev;
 	void __iomem		*regs;
 	void __iomem		*enable_reg;
 	struct clk		*clk;
+	struct clk		*sclk;
 	unsigned int		irq;
 	struct regulator	*vdd;
 
@@ -97,43 +97,213 @@ struct exynos_adc {
 	unsigned int            version;
 };
 
-static const struct of_device_id exynos_adc_match[] = {
-	{ .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 },
-	{ .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 },
-	{},
+struct exynos_adc_data {
+	int num_channels;
+	bool needs_sclk;
+
+	void (*init_hw)(struct exynos_adc *info);
+	void (*exit_hw)(struct exynos_adc *info);
+	void (*clear_irq)(struct exynos_adc *info);
+	void (*start_conv)(struct exynos_adc *info, unsigned long addr);
 };
-MODULE_DEVICE_TABLE(of, exynos_adc_match);
 
-static inline unsigned int exynos_adc_get_version(struct platform_device *pdev)
+static void exynos_adc_unprepare_clk(struct exynos_adc *info)
 {
-	const struct of_device_id *match;
+	if (info->data->needs_sclk)
+		clk_unprepare(info->sclk);
+	clk_unprepare(info->clk);
+}
 
-	match = of_match_node(exynos_adc_match, pdev->dev.of_node);
-	return (unsigned int)match->data;
+static int exynos_adc_prepare_clk(struct exynos_adc *info)
+{
+	int ret;
+
+	ret = clk_prepare(info->clk);
+	if (ret) {
+		dev_err(info->dev, "failed preparing adc clock: %d\n", ret);
+		return ret;
+	}
+
+	if (info->data->needs_sclk) {
+		ret = clk_prepare(info->sclk);
+		if (ret) {
+			clk_unprepare(info->clk);
+			dev_err(info->dev,
+				"failed preparing sclk_adc clock: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void exynos_adc_disable_clk(struct exynos_adc *info)
+{
+	if (info->data->needs_sclk)
+		clk_disable(info->sclk);
+	clk_disable(info->clk);
+}
+
+static int exynos_adc_enable_clk(struct exynos_adc *info)
+{
+	int ret;
+
+	ret = clk_enable(info->clk);
+	if (ret) {
+		dev_err(info->dev, "failed enabling adc clock: %d\n", ret);
+		return ret;
+	}
+
+	if (info->data->needs_sclk) {
+		ret = clk_enable(info->sclk);
+		if (ret) {
+			clk_disable(info->clk);
+			dev_err(info->dev,
+				"failed enabling sclk_adc clock: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void exynos_adc_v1_init_hw(struct exynos_adc *info)
+{
+	u32 con1;
+
+	writel(1, info->enable_reg);
+
+	/* set default prescaler values and Enable prescaler */
+	con1 =  ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
+
+	/* Enable 12-bit ADC resolution */
+	con1 |= ADC_V1_CON_RES;
+	writel(con1, ADC_V1_CON(info->regs));
+}
+
+static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
+{
+	u32 con;
+
+	writel(0, info->enable_reg);
+
+	con = readl(ADC_V1_CON(info->regs));
+	con |= ADC_V1_CON_STANDBY;
+	writel(con, ADC_V1_CON(info->regs));
+}
+
+static void exynos_adc_v1_clear_irq(struct exynos_adc *info)
+{
+	writel(1, ADC_V1_INTCLR(info->regs));
+}
+
+static void exynos_adc_v1_start_conv(struct exynos_adc *info,
+				     unsigned long addr)
+{
+	u32 con1;
+
+	writel(addr, ADC_V1_MUX(info->regs));
+
+	con1 = readl(ADC_V1_CON(info->regs));
+	writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
+}
+
+static const struct exynos_adc_data exynos_adc_v1_data = {
+	.num_channels	= MAX_ADC_V1_CHANNELS,
+
+	.init_hw	= exynos_adc_v1_init_hw,
+	.exit_hw	= exynos_adc_v1_exit_hw,
+	.clear_irq	= exynos_adc_v1_clear_irq,
+	.start_conv	= exynos_adc_v1_start_conv,
+};
+
+static void exynos_adc_v2_init_hw(struct exynos_adc *info)
+{
+	u32 con1, con2;
+
+	writel(1, info->enable_reg);
+
+	con1 = ADC_V2_CON1_SOFT_RESET;
+	writel(con1, ADC_V2_CON1(info->regs));
+
+	con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
+		ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
+	writel(con2, ADC_V2_CON2(info->regs));
+
+	/* Enable interrupts */
+	writel(1, ADC_V2_INT_EN(info->regs));
+}
+
+static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
+{
+	u32 con;
+
+	writel(0, info->enable_reg);
+
+	con = readl(ADC_V2_CON1(info->regs));
+	con &= ~ADC_CON_EN_START;
+	writel(con, ADC_V2_CON1(info->regs));
 }
 
-static void exynos_adc_hw_init(struct exynos_adc *info)
+static void exynos_adc_v2_clear_irq(struct exynos_adc *info)
+{
+	writel(1, ADC_V2_INT_ST(info->regs));
+}
+
+static void exynos_adc_v2_start_conv(struct exynos_adc *info,
+				     unsigned long addr)
 {
 	u32 con1, con2;
 
-	if (info->version == ADC_V2) {
-		con1 = ADC_V2_CON1_SOFT_RESET;
-		writel(con1, ADC_V2_CON1(info->regs));
+	con2 = readl(ADC_V2_CON2(info->regs));
+	con2 &= ~ADC_V2_CON2_ACH_MASK;
+	con2 |= ADC_V2_CON2_ACH_SEL(addr);
+	writel(con2, ADC_V2_CON2(info->regs));
 
-		con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
-			ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
-		writel(con2, ADC_V2_CON2(info->regs));
+	con1 = readl(ADC_V2_CON1(info->regs));
+	writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs));
+}
 
-		/* Enable interrupts */
-		writel(1, ADC_V2_INT_EN(info->regs));
-	} else {
-		/* set default prescaler values and Enable prescaler */
-		con1 =  ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
+static const struct exynos_adc_data exynos_adc_v2_data = {
+	.num_channels	= MAX_ADC_V2_CHANNELS,
 
-		/* Enable 12-bit ADC resolution */
-		con1 |= ADC_V1_CON_RES;
-		writel(con1, ADC_V1_CON(info->regs));
-	}
+	.init_hw	= exynos_adc_v2_init_hw,
+	.exit_hw	= exynos_adc_v2_exit_hw,
+	.clear_irq	= exynos_adc_v2_clear_irq,
+	.start_conv	= exynos_adc_v2_start_conv,
+};
+
+static const struct exynos_adc_data exynos3250_adc_data = {
+	.num_channels	= MAX_EXYNOS3250_ADC_CHANNELS,
+	.needs_sclk	= true,
+
+	.init_hw	= exynos_adc_v2_init_hw,
+	.exit_hw	= exynos_adc_v2_exit_hw,
+	.clear_irq	= exynos_adc_v2_clear_irq,
+	.start_conv	= exynos_adc_v2_start_conv,
+};
+
+static const struct of_device_id exynos_adc_match[] = {
+	{
+		.compatible = "samsung,exynos-adc-v1",
+		.data = &exynos_adc_v1_data,
+	}, {
+		.compatible = "samsung,exynos-adc-v2",
+		.data = &exynos_adc_v2_data,
+	}, {
+		.compatible = "samsung,exynos3250-adc",
+		.data = &exynos3250_adc_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, exynos_adc_match);
+
+static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+
+	match = of_match_node(exynos_adc_match, pdev->dev.of_node);
+	return (struct exynos_adc_data *)match->data;
 }
 
 static int exynos_read_raw(struct iio_dev *indio_dev,
@@ -144,7 +314,6 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
 {
 	struct exynos_adc *info = iio_priv(indio_dev);
 	unsigned long timeout;
-	u32 con1, con2;
 	int ret;
 
 	if (mask != IIO_CHAN_INFO_RAW)
@@ -154,28 +323,15 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
 	reinit_completion(&info->completion);
 
 	/* Select the channel to be used and Trigger conversion */
-	if (info->version == ADC_V2) {
-		con2 = readl(ADC_V2_CON2(info->regs));
-		con2 &= ~ADC_V2_CON2_ACH_MASK;
-		con2 |= ADC_V2_CON2_ACH_SEL(chan->address);
-		writel(con2, ADC_V2_CON2(info->regs));
-
-		con1 = readl(ADC_V2_CON1(info->regs));
-		writel(con1 | ADC_CON_EN_START,
-				ADC_V2_CON1(info->regs));
-	} else {
-		writel(chan->address, ADC_V1_MUX(info->regs));
-
-		con1 = readl(ADC_V1_CON(info->regs));
-		writel(con1 | ADC_CON_EN_START,
-				ADC_V1_CON(info->regs));
-	}
+	if (info->data->start_conv)
+		info->data->start_conv(info, chan->address);
 
 	timeout = wait_for_completion_timeout
 			(&info->completion, EXYNOS_ADC_TIMEOUT);
 	if (timeout == 0) {
 		dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
-		exynos_adc_hw_init(info);
+		if (info->data->init_hw)
+			info->data->init_hw(info);
 		ret = -ETIMEDOUT;
 	} else {
 		*val = info->value;
@@ -193,13 +349,11 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
 	struct exynos_adc *info = (struct exynos_adc *)dev_id;
 
 	/* Read value */
-	info->value = readl(ADC_V1_DATX(info->regs)) &
-						ADC_DATX_MASK;
+	info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK;
+
 	/* clear irq */
-	if (info->version == ADC_V2)
-		writel(1, ADC_V2_INT_ST(info->regs));
-	else
-		writel(1, ADC_V1_INTCLR(info->regs));
+	if (info->data->clear_irq)
+		info->data->clear_irq(info);
 
 	complete(&info->completion);
 
@@ -277,6 +431,12 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
 	info = iio_priv(indio_dev);
 
+	info->data = exynos_adc_get_data(pdev);
+	if (!info->data) {
+		dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
+		return -EINVAL;
+	}
+
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	info->regs = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(info->regs))
@@ -294,6 +454,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
 	}
 
 	info->irq = irq;
+	info->dev = &pdev->dev;
 
 	init_completion(&info->completion);
 
@@ -304,6 +465,16 @@ static int exynos_adc_probe(struct platform_device *pdev)
 		return PTR_ERR(info->clk);
 	}
 
+	if (info->data->needs_sclk) {
+		info->sclk = devm_clk_get(&pdev->dev, "sclk");
+		if (IS_ERR(info->sclk)) {
+			dev_err(&pdev->dev,
+				"failed getting sclk clock, err = %ld\n",
+				PTR_ERR(info->sclk));
+			return PTR_ERR(info->sclk);
+		}
+	}
+
 	info->vdd = devm_regulator_get(&pdev->dev, "vdd");
 	if (IS_ERR(info->vdd)) {
 		dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
@@ -315,13 +486,13 @@ static int exynos_adc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = clk_prepare_enable(info->clk);
+	ret = exynos_adc_prepare_clk(info);
 	if (ret)
 		goto err_disable_reg;
 
-	writel(1, info->enable_reg);
-
-	info->version = exynos_adc_get_version(pdev);
+	ret = exynos_adc_enable_clk(info);
+	if (ret)
+		goto err_unprepare_clk;
 
 	platform_set_drvdata(pdev, indio_dev);
 
@@ -331,11 +502,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
 	indio_dev->info = &exynos_adc_iio_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = exynos_adc_iio_channels;
-
-	if (info->version == ADC_V1)
-		indio_dev->num_channels = MAX_ADC_V1_CHANNELS;
-	else
-		indio_dev->num_channels = MAX_ADC_V2_CHANNELS;
+	indio_dev->num_channels = info->data->num_channels;
 
 	ret = request_irq(info->irq, exynos_adc_isr,
 					0, dev_name(&pdev->dev), info);
@@ -349,7 +516,8 @@ static int exynos_adc_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_irq;
 
-	exynos_adc_hw_init(info);
+	if (info->data->init_hw)
+		info->data->init_hw(info);
 
 	ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
 	if (ret < 0) {
@@ -366,8 +534,11 @@ static int exynos_adc_probe(struct platform_device *pdev)
 err_irq:
 	free_irq(info->irq, info);
 err_disable_clk:
-	writel(0, info->enable_reg);
-	clk_disable_unprepare(info->clk);
+	if (info->data->exit_hw)
+		info->data->exit_hw(info);
+	exynos_adc_disable_clk(info);
+err_unprepare_clk:
+	exynos_adc_unprepare_clk(info);
 err_disable_reg:
 	regulator_disable(info->vdd);
 	return ret;
@@ -382,8 +553,10 @@ static int exynos_adc_remove(struct platform_device *pdev)
 				exynos_adc_remove_devices);
 	iio_device_unregister(indio_dev);
 	free_irq(info->irq, info);
-	writel(0, info->enable_reg);
-	clk_disable_unprepare(info->clk);
+	if (info->data->exit_hw)
+		info->data->exit_hw(info);
+	exynos_adc_disable_clk(info);
+	exynos_adc_unprepare_clk(info);
 	regulator_disable(info->vdd);
 
 	return 0;
@@ -394,20 +567,10 @@ static int exynos_adc_suspend(struct device *dev)
 {
 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct exynos_adc *info = iio_priv(indio_dev);
-	u32 con;
 
-	if (info->version == ADC_V2) {
-		con = readl(ADC_V2_CON1(info->regs));
-		con &= ~ADC_CON_EN_START;
-		writel(con, ADC_V2_CON1(info->regs));
-	} else {
-		con = readl(ADC_V1_CON(info->regs));
-		con |= ADC_V1_CON_STANDBY;
-		writel(con, ADC_V1_CON(info->regs));
-	}
-
-	writel(0, info->enable_reg);
-	clk_disable_unprepare(info->clk);
+	if (info->data->exit_hw)
+		info->data->exit_hw(info);
+	exynos_adc_disable_clk(info);
 	regulator_disable(info->vdd);
 
 	return 0;
@@ -423,12 +586,12 @@ static int exynos_adc_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	ret = clk_prepare_enable(info->clk);
+	ret = exynos_adc_enable_clk(info);
 	if (ret)
 		return ret;
 
-	writel(1, info->enable_reg);
-	exynos_adc_hw_init(info);
+	if (info->data->init_hw)
+		info->data->init_hw(info);
 
 	return 0;
 }
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 4b1f375c5659d0e11330d8eba6da959a398fa4d5..af3e76d652ba0a51f9fdd777079edf9c30304b99 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -87,6 +87,10 @@ static const char * const iio_modifier_names[] = {
 	[IIO_MOD_QUATERNION] = "quaternion",
 	[IIO_MOD_TEMP_AMBIENT] = "ambient",
 	[IIO_MOD_TEMP_OBJECT] = "object",
+	[IIO_MOD_NORTH_MAGN] = "from_north_magnetic",
+	[IIO_MOD_NORTH_TRUE] = "from_north_true",
+	[IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
+	[IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
 };
 
 /* relies on pairs of these shared then separate */
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index b2b0937d5133cd38137ce50c0edaf4b2ca004d83..3ec777a8f64edf5466e351995f24b14ba5414f66 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -35,6 +35,10 @@ enum magn_3d_channel {
 	CHANNEL_SCAN_INDEX_X,
 	CHANNEL_SCAN_INDEX_Y,
 	CHANNEL_SCAN_INDEX_Z,
+	CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP,
+	CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP,
+	CHANNEL_SCAN_INDEX_NORTH_MAGN,
+	CHANNEL_SCAN_INDEX_NORTH_TRUE,
 	MAGN_3D_CHANNEL_MAX,
 };
 
@@ -42,7 +46,12 @@ struct magn_3d_state {
 	struct hid_sensor_hub_callbacks callbacks;
 	struct hid_sensor_common common_attributes;
 	struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
-	u32 magn_val[MAGN_3D_CHANNEL_MAX];
+
+	/* dynamically sized array to hold sensor values */
+	u32 *iio_vals;
+	/* array of pointers to sensor value */
+	u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX];
+
 	int scale_pre_decml;
 	int scale_post_decml;
 	int scale_precision;
@@ -52,7 +61,11 @@ struct magn_3d_state {
 static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
 	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS,
 	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS,
-	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS
+	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS,
+	HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH,
+	HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH,
+	HID_USAGE_SENSOR_ORIENT_MAGN_NORTH,
+	HID_USAGE_SENSOR_ORIENT_TRUE_NORTH,
 };
 
 /* Channel definitions */
@@ -66,7 +79,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
 		BIT(IIO_CHAN_INFO_SCALE) |
 		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 		BIT(IIO_CHAN_INFO_HYSTERESIS),
-		.scan_index = CHANNEL_SCAN_INDEX_X,
 	}, {
 		.type = IIO_MAGN,
 		.modified = 1,
@@ -76,7 +88,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
 		BIT(IIO_CHAN_INFO_SCALE) |
 		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 		BIT(IIO_CHAN_INFO_HYSTERESIS),
-		.scan_index = CHANNEL_SCAN_INDEX_Y,
 	}, {
 		.type = IIO_MAGN,
 		.modified = 1,
@@ -86,7 +97,42 @@ static const struct iio_chan_spec magn_3d_channels[] = {
 		BIT(IIO_CHAN_INFO_SCALE) |
 		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 		BIT(IIO_CHAN_INFO_HYSTERESIS),
-		.scan_index = CHANNEL_SCAN_INDEX_Z,
+	}, {
+		.type = IIO_ROT,
+		.modified = 1,
+		.channel2 = IIO_MOD_NORTH_MAGN_TILT_COMP,
+		.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),
+	}, {
+		.type = IIO_ROT,
+		.modified = 1,
+		.channel2 = IIO_MOD_NORTH_TRUE_TILT_COMP,
+		.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),
+	}, {
+		.type = IIO_ROT,
+		.modified = 1,
+		.channel2 = IIO_MOD_NORTH_MAGN,
+		.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),
+	}, {
+		.type = IIO_ROT,
+		.modified = 1,
+		.channel2 = IIO_MOD_NORTH_TRUE,
+		.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),
 	}
 };
 
@@ -126,8 +172,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
 		msleep_interruptible(poll_value * 2);
 
 		report_id =
-			magn_state->magn[chan->scan_index].report_id;
-		address = magn_3d_addresses[chan->scan_index];
+			magn_state->magn[chan->address].report_id;
+		address = magn_3d_addresses[chan->address];
 		if (report_id >= 0)
 			*val = sensor_hub_input_attr_get_raw_value(
 				magn_state->common_attributes.hsdev,
@@ -218,8 +264,8 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
 	dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n");
 	if (atomic_read(&magn_state->common_attributes.data_ready))
 		hid_sensor_push_data(indio_dev,
-				magn_state->magn_val,
-				sizeof(magn_state->magn_val));
+				magn_state->iio_vals,
+				sizeof(magn_state->iio_vals));
 
 	return 0;
 }
@@ -233,52 +279,126 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
 	struct iio_dev *indio_dev = platform_get_drvdata(priv);
 	struct magn_3d_state *magn_state = iio_priv(indio_dev);
 	int offset;
-	int ret = -EINVAL;
+	int ret = 0;
+	u32 *iio_val = NULL;
 
 	switch (usage_id) {
 	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS:
 	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS:
 	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS:
-		offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS;
-		magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] =
-						*(u32 *)raw_data;
-		ret = 0;
+		offset = (usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS)
+				+ CHANNEL_SCAN_INDEX_X;
+	break;
+	case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH:
+	case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH:
+	case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH:
+	case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH:
+		offset = (usage_id - HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH)
+				+ CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP;
 	break;
 	default:
-		break;
+		return -EINVAL;
 	}
 
+	iio_val = magn_state->magn_val_addr[offset];
+
+	if (iio_val != NULL)
+		*iio_val = *((u32 *)raw_data);
+	else
+		ret = -EINVAL;
+
 	return ret;
 }
 
 /* Parse report which is specific to an usage id*/
 static int magn_3d_parse_report(struct platform_device *pdev,
 				struct hid_sensor_hub_device *hsdev,
-				struct iio_chan_spec *channels,
+				struct iio_chan_spec **channels,
+				int *chan_count,
 				unsigned usage_id,
 				struct magn_3d_state *st)
 {
-	int ret;
 	int i;
+	int attr_count = 0;
+	struct iio_chan_spec *_channels;
+
+	/* Scan for each usage attribute supported */
+	for (i = 0; i < MAGN_3D_CHANNEL_MAX; i++) {
+		int status;
+		u32 address = magn_3d_addresses[i];
+
+		/* Check if usage attribute exists in the sensor hub device */
+		status = sensor_hub_input_get_attribute_info(hsdev,
+			HID_INPUT_REPORT,
+			usage_id,
+			address,
+			&(st->magn[i]));
+		if (!status)
+			attr_count++;
+	}
 
-	for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
-		ret = sensor_hub_input_get_attribute_info(hsdev,
-				HID_INPUT_REPORT,
-				usage_id,
-				HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i,
-				&st->magn[CHANNEL_SCAN_INDEX_X + i]);
-		if (ret < 0)
-			break;
-		magn_3d_adjust_channel_bit_mask(channels,
-				CHANNEL_SCAN_INDEX_X + i,
-				st->magn[CHANNEL_SCAN_INDEX_X + i].size);
+	if (attr_count <= 0) {
+		dev_err(&pdev->dev,
+			"failed to find any supported usage attributes in report\n");
+		return  -EINVAL;
 	}
-	dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n",
+
+	dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n",
+			attr_count);
+	dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n",
 			st->magn[0].index,
 			st->magn[0].report_id,
 			st->magn[1].index, st->magn[1].report_id,
 			st->magn[2].index, st->magn[2].report_id);
 
+	/* Setup IIO channel array */
+	_channels = devm_kcalloc(&pdev->dev, attr_count,
+				sizeof(struct iio_chan_spec),
+				GFP_KERNEL);
+	if (!_channels) {
+		dev_err(&pdev->dev,
+			"failed to allocate space for iio channels\n");
+		return -ENOMEM;
+	}
+
+	st->iio_vals = devm_kcalloc(&pdev->dev, attr_count,
+				sizeof(u32),
+				GFP_KERNEL);
+	if (!st->iio_vals) {
+		dev_err(&pdev->dev,
+			"failed to allocate space for iio values array\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0, *chan_count = 0;
+	i < MAGN_3D_CHANNEL_MAX && *chan_count < attr_count;
+	i++){
+		if (st->magn[i].index >= 0) {
+			/* Setup IIO channel struct */
+			(_channels[*chan_count]) = magn_3d_channels[i];
+			(_channels[*chan_count]).scan_index = *chan_count;
+			(_channels[*chan_count]).address = i;
+
+			/* Set magn_val_addr to iio value address */
+			st->magn_val_addr[i] = &(st->iio_vals[*chan_count]);
+			magn_3d_adjust_channel_bit_mask(_channels,
+							*chan_count,
+							st->magn[i].size);
+			(*chan_count)++;
+		}
+	}
+
+	if (*chan_count <= 0) {
+		dev_err(&pdev->dev,
+			"failed to find any magnetic channels setup\n");
+		return -EINVAL;
+	}
+
+	*channels = _channels;
+
+	dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n",
+			*chan_count);
+
 	st->scale_precision = hid_sensor_format_scale(
 				HID_USAGE_SENSOR_COMPASS_3D,
 				&st->magn[CHANNEL_SCAN_INDEX_X],
@@ -296,7 +416,7 @@ static int magn_3d_parse_report(struct platform_device *pdev,
 			st->common_attributes.sensitivity.report_id);
 	}
 
-	return ret;
+	return 0;
 }
 
 /* Function to initialize the processing for usage id */
@@ -308,6 +428,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
 	struct magn_3d_state *magn_state;
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 	struct iio_chan_spec *channels;
+	int chan_count = 0;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev,
 					  sizeof(struct magn_3d_state));
@@ -328,22 +449,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels),
-			   GFP_KERNEL);
-	if (!channels) {
-		dev_err(&pdev->dev, "failed to duplicate channels\n");
-		return -ENOMEM;
-	}
-
-	ret = magn_3d_parse_report(pdev, hsdev, channels,
+	ret = magn_3d_parse_report(pdev, hsdev,
+				&channels, &chan_count,
 				HID_USAGE_SENSOR_COMPASS_3D, magn_state);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to setup attributes\n");
-		goto error_free_dev_mem;
+		dev_err(&pdev->dev, "failed to parse report\n");
+		return ret;
 	}
 
 	indio_dev->channels = channels;
-	indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels);
+	indio_dev->num_channels = chan_count;
 	indio_dev->dev.parent = &pdev->dev;
 	indio_dev->info = &magn_3d_info;
 	indio_dev->name = name;
@@ -353,7 +468,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
 		NULL, NULL);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
-		goto error_free_dev_mem;
+		return ret;
 	}
 	atomic_set(&magn_state->common_attributes.data_ready, 0);
 	ret = hid_sensor_setup_trigger(indio_dev, name,
@@ -387,8 +502,6 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
 	hid_sensor_remove_trigger(&magn_state->common_attributes);
 error_unreg_buffer_funcs:
 	iio_triggered_buffer_cleanup(indio_dev);
-error_free_dev_mem:
-	kfree(indio_dev->channels);
 	return ret;
 }
 
@@ -403,7 +516,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
 	iio_device_unregister(indio_dev);
 	hid_sensor_remove_trigger(&magn_state->common_attributes);
 	iio_triggered_buffer_cleanup(indio_dev);
-	kfree(indio_dev->channels);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
index 34634da1f9f733fd0268a728fc5e3653aeedff58..dec814a7a0735c809a9b8093b9c1782ab15de034 100644
--- a/drivers/staging/iio/magnetometer/Kconfig
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -4,15 +4,37 @@
 menu "Magnetometer sensors"
 
 config SENSORS_HMC5843
-	tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer"
-	depends on I2C
+	tristate
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
+
+config SENSORS_HMC5843_I2C
+	tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer (I2C)"
+	depends on I2C
+	select SENSORS_HMC5843
+	select REGMAP_I2C
 	help
 	  Say Y here to add support for the Honeywell HMC5843, HMC5883 and
 	  HMC5883L 3-Axis Magnetometer (digital compass).
 
-	  To compile this driver as a module, choose M here: the module
-	  will be called hmc5843.
+	  This driver can also be compiled as a set of modules.
+	  If so, these modules will be created:
+	  - hmc5843_core (core functions)
+	  - hmc5843_i2c (support for HMC5843, HMC5883, HMC5883L and HMC5983)
+
+config SENSORS_HMC5843_SPI
+	tristate "Honeywell HMC5983 3-Axis Magnetometer (SPI)"
+	depends on SPI_MASTER
+	select SENSORS_HMC5843
+	select REGMAP_SPI
+	help
+	  Say Y here to add support for the Honeywell HMC5983 3-Axis Magnetometer
+	  (digital compass).
+
+	  This driver can also be compiled as a set of modules.
+	  If so, these modules will be created:
+	  - hmc5843_core (core functions)
+	  - hmc5843_spi (support for HMC5983)
+
 
 endmenu
diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile
index f9bfb2e11d7df3ec509fd3dbb2ce77acce9ff336..33761a19a956f942e564967ca6c2029a0ddcb13c 100644
--- a/drivers/staging/iio/magnetometer/Makefile
+++ b/drivers/staging/iio/magnetometer/Makefile
@@ -2,4 +2,6 @@
 # Makefile for industrial I/O Magnetometer sensors
 #
 
-obj-$(CONFIG_SENSORS_HMC5843)	+= hmc5843.o
+obj-$(CONFIG_SENSORS_HMC5843)		+= hmc5843_core.o
+obj-$(CONFIG_SENSORS_HMC5843_I2C)	+= hmc5843_i2c.o
+obj-$(CONFIG_SENSORS_HMC5843_SPI)	+= hmc5843_spi.o
diff --git a/drivers/staging/iio/magnetometer/hmc5843.h b/drivers/staging/iio/magnetometer/hmc5843.h
new file mode 100644
index 0000000000000000000000000000000000000000..b784e3eb4591edec159129f709f5a72672bfe460
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/hmc5843.h
@@ -0,0 +1,59 @@
+/*
+ * Header file for hmc5843 driver
+ *
+ * Split from hmc5843.c
+ * Copyright (C) Josef Gajdusek <atx@atx.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * */
+
+
+#ifndef HMC5843_CORE_H
+#define HMC5843_CORE_H
+
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+
+#define HMC5843_CONFIG_REG_A			0x00
+#define HMC5843_CONFIG_REG_B			0x01
+#define HMC5843_MODE_REG			0x02
+#define HMC5843_DATA_OUT_MSB_REGS		0x03
+#define HMC5843_STATUS_REG			0x09
+#define HMC5843_ID_REG				0x0a
+#define HMC5843_ID_END				0x0c
+
+enum hmc5843_ids {
+	HMC5843_ID,
+	HMC5883_ID,
+	HMC5883L_ID,
+	HMC5983_ID,
+};
+
+struct hmc5843_data {
+	struct device *dev;
+	struct mutex lock;
+	struct regmap *regmap;
+	const struct hmc5843_chip_info *variant;
+	__be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */
+};
+
+int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
+		enum hmc5843_ids id);
+int hmc5843_common_remove(struct device *dev);
+
+int hmc5843_common_suspend(struct device *dev);
+int hmc5843_common_resume(struct device *dev);
+
+#ifdef CONFIG_PM_SLEEP
+static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops,
+		hmc5843_common_suspend,
+		hmc5843_common_resume);
+#define HMC5843_PM_OPS (&hmc5843_pm_ops)
+#else
+#define HMC5843_PM_OPS NULL
+#endif
+
+#endif /* HMC5843_CORE_H */
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843_core.c
similarity index 72%
rename from drivers/staging/iio/magnetometer/hmc5843.c
rename to drivers/staging/iio/magnetometer/hmc5843_core.c
index f595fdcc79b0ba57a1016763314b106f6f0e529d..914ae1acd31d65572b20a91029262a97e77b53bd 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843_core.c
@@ -4,6 +4,8 @@
 
     Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>.
 
+    Split to multiple files by Josef Gajdusek <atx@atx.name> - 2014
+
     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
@@ -20,7 +22,7 @@
 */
 
 #include <linux/module.h>
-#include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/trigger_consumer.h>
@@ -28,18 +30,7 @@
 #include <linux/iio/triggered_buffer.h>
 #include <linux/delay.h>
 
-#define HMC5843_CONFIG_REG_A			0x00
-#define HMC5843_CONFIG_REG_B			0x01
-#define HMC5843_MODE_REG			0x02
-#define HMC5843_DATA_OUT_MSB_REGS		0x03
-#define HMC5843_STATUS_REG			0x09
-#define HMC5843_ID_REG				0x0a
-
-enum hmc5843_ids {
-	HMC5843_ID,
-	HMC5883_ID,
-	HMC5883L_ID,
-};
+#include "hmc5843.h"
 
 /*
  * Range gain settings in (+-)Ga
@@ -48,7 +39,7 @@ enum hmc5843_ids {
  */
 #define HMC5843_RANGE_GAIN_OFFSET		0x05
 #define HMC5843_RANGE_GAIN_DEFAULT		0x01
-#define HMC5843_RANGE_GAINS			8
+#define HMC5843_RANGE_GAIN_MASK		0xe0
 
 /* Device status */
 #define HMC5843_DATA_READY			0x01
@@ -67,7 +58,7 @@ enum hmc5843_ids {
  */
 #define HMC5843_RATE_OFFSET			0x02
 #define HMC5843_RATE_DEFAULT			0x04
-#define HMC5843_RATES				7
+#define HMC5843_RATE_MASK		0x1c
 
 /* Device measurement configuration */
 #define HMC5843_MEAS_CONF_NORMAL		0x00
@@ -76,15 +67,15 @@ enum hmc5843_ids {
 #define HMC5843_MEAS_CONF_MASK			0x03
 
 /* Scaling factors: 10000000/Gain */
-static const int hmc5843_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
+static const int hmc5843_regval_to_nanoscale[] = {
 	6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
 };
 
-static const int hmc5883_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
+static const int hmc5883_regval_to_nanoscale[] = {
 	7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
 };
 
-static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
+static const int hmc5883l_regval_to_nanoscale[] = {
 	7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
 };
 
@@ -101,32 +92,27 @@ static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
  * 6		| 50			| 75
  * 7		| Not used		| Not used
  */
-static const int hmc5843_regval_to_samp_freq[7][2] = {
+static const int hmc5843_regval_to_samp_freq[][2] = {
 	{0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0}
 };
 
-static const int hmc5883_regval_to_samp_freq[7][2] = {
+static const int hmc5883_regval_to_samp_freq[][2] = {
 	{0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0},
 	{75, 0}
 };
 
+static const int hmc5983_regval_to_samp_freq[][2] = {
+	{0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0},
+	{75, 0}, {220, 0}
+};
+
 /* Describe chip variants */
 struct hmc5843_chip_info {
 	const struct iio_chan_spec *channels;
 	const int (*regval_to_samp_freq)[2];
+	const int n_regval_to_samp_freq;
 	const int *regval_to_nanoscale;
-};
-
-/* Each client has this additional data */
-struct hmc5843_data {
-	struct i2c_client *client;
-	struct mutex lock;
-	u8 rate;
-	u8 meas_conf;
-	u8 operating_mode;
-	u8 range;
-	const struct hmc5843_chip_info *variant;
-	__be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */
+	const int n_regval_to_nanoscale;
 };
 
 /* The lower two bits contain the current conversion mode */
@@ -135,10 +121,8 @@ static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode)
 	int ret;
 
 	mutex_lock(&data->lock);
-	ret = i2c_smbus_write_byte_data(data->client, HMC5843_MODE_REG,
-					operating_mode & HMC5843_MODE_MASK);
-	if (ret >= 0)
-		data->operating_mode = operating_mode;
+	ret = regmap_update_bits(data->regmap, HMC5843_MODE_REG,
+			HMC5843_MODE_MASK, operating_mode);
 	mutex_unlock(&data->lock);
 
 	return ret;
@@ -146,21 +130,21 @@ static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode)
 
 static int hmc5843_wait_measurement(struct hmc5843_data *data)
 {
-	s32 result;
 	int tries = 150;
+	int val;
+	int ret;
 
 	while (tries-- > 0) {
-		result = i2c_smbus_read_byte_data(data->client,
-			HMC5843_STATUS_REG);
-		if (result < 0)
-			return result;
-		if (result & HMC5843_DATA_READY)
+		ret = regmap_read(data->regmap, HMC5843_STATUS_REG, &val);
+		if (ret < 0)
+			return ret;
+		if (val & HMC5843_DATA_READY)
 			break;
 		msleep(20);
 	}
 
 	if (tries < 0) {
-		dev_err(&data->client->dev, "data not ready\n");
+		dev_err(data->dev, "data not ready\n");
 		return -EIO;
 	}
 
@@ -171,20 +155,20 @@ static int hmc5843_wait_measurement(struct hmc5843_data *data)
 static int hmc5843_read_measurement(struct hmc5843_data *data,
 				    int idx, int *val)
 {
-	s32 result;
 	__be16 values[3];
+	int ret;
 
 	mutex_lock(&data->lock);
-	result = hmc5843_wait_measurement(data);
-	if (result < 0) {
+	ret = hmc5843_wait_measurement(data);
+	if (ret < 0) {
 		mutex_unlock(&data->lock);
-		return result;
+		return ret;
 	}
-	result = i2c_smbus_read_i2c_block_data(data->client,
-		HMC5843_DATA_OUT_MSB_REGS, sizeof(values), (u8 *) values);
+	ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
+			values, sizeof(values));
 	mutex_unlock(&data->lock);
-	if (result < 0)
-		return -EINVAL;
+	if (ret < 0)
+		return ret;
 
 	*val = sign_extend32(be16_to_cpu(values[idx]), 15);
 	return IIO_VAL_INT;
@@ -208,16 +192,13 @@ static int hmc5843_read_measurement(struct hmc5843_data *data,
  *     and BN.
  *
  */
-static s32 hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf)
+static int hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf)
 {
 	int ret;
 
 	mutex_lock(&data->lock);
-	ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A,
-		(meas_conf & HMC5843_MEAS_CONF_MASK) |
-		(data->rate << HMC5843_RATE_OFFSET));
-	if (ret >= 0)
-		data->meas_conf = meas_conf;
+	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_A,
+			HMC5843_MEAS_CONF_MASK, meas_conf);
 	mutex_unlock(&data->lock);
 
 	return ret;
@@ -228,7 +209,15 @@ static ssize_t hmc5843_show_measurement_configuration(struct device *dev,
 						char *buf)
 {
 	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
-	return sprintf(buf, "%d\n", data->meas_conf);
+	int val;
+	int ret;
+
+	ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &val);
+	if (ret)
+		return ret;
+	val &= HMC5843_MEAS_CONF_MASK;
+
+	return sprintf(buf, "%d\n", val);
 }
 
 static ssize_t hmc5843_set_measurement_configuration(struct device *dev,
@@ -264,7 +253,7 @@ static ssize_t hmc5843_show_samp_freq_avail(struct device *dev,
 	size_t len = 0;
 	int i;
 
-	for (i = 0; i < HMC5843_RATES; i++)
+	for (i = 0; i < data->variant->n_regval_to_samp_freq; i++)
 		len += scnprintf(buf + len, PAGE_SIZE - len,
 			"%d.%d ", data->variant->regval_to_samp_freq[i][0],
 			data->variant->regval_to_samp_freq[i][1]);
@@ -282,10 +271,8 @@ static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate)
 	int ret;
 
 	mutex_lock(&data->lock);
-	ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A,
-		data->meas_conf | (rate << HMC5843_RATE_OFFSET));
-	if (ret >= 0)
-		data->rate = rate;
+	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_A,
+			HMC5843_RATE_MASK, rate << HMC5843_RATE_OFFSET);
 	mutex_unlock(&data->lock);
 
 	return ret;
@@ -296,7 +283,7 @@ static int hmc5843_get_samp_freq_index(struct hmc5843_data *data,
 {
 	int i;
 
-	for (i = 0; i < HMC5843_RATES; i++)
+	for (i = 0; i < data->variant->n_regval_to_samp_freq; i++)
 		if (val == data->variant->regval_to_samp_freq[i][0] &&
 			val2 == data->variant->regval_to_samp_freq[i][1])
 			return i;
@@ -309,10 +296,9 @@ static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range)
 	int ret;
 
 	mutex_lock(&data->lock);
-	ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_B,
-		range << HMC5843_RANGE_GAIN_OFFSET);
-	if (ret >= 0)
-		data->range = range;
+	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_B,
+			HMC5843_RANGE_GAIN_MASK,
+			range << HMC5843_RANGE_GAIN_OFFSET);
 	mutex_unlock(&data->lock);
 
 	return ret;
@@ -326,7 +312,7 @@ static ssize_t hmc5843_show_scale_avail(struct device *dev,
 	size_t len = 0;
 	int i;
 
-	for (i = 0; i < HMC5843_RANGE_GAINS; i++)
+	for (i = 0; i < data->variant->n_regval_to_nanoscale; i++)
 		len += scnprintf(buf + len, PAGE_SIZE - len,
 			"0.%09d ", data->variant->regval_to_nanoscale[i]);
 
@@ -346,7 +332,7 @@ static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2)
 	if (val != 0)
 		return -EINVAL;
 
-	for (i = 0; i < HMC5843_RANGE_GAINS; i++)
+	for (i = 0; i < data->variant->n_regval_to_nanoscale; i++)
 		if (val2 == data->variant->regval_to_nanoscale[i])
 			return i;
 
@@ -358,17 +344,27 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
 			    int *val, int *val2, long mask)
 {
 	struct hmc5843_data *data = iio_priv(indio_dev);
+	int rval;
+	int ret;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
 		return hmc5843_read_measurement(data, chan->scan_index, val);
 	case IIO_CHAN_INFO_SCALE:
+		ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_B, &rval);
+		if (ret < 0)
+			return ret;
+		rval >>= HMC5843_RANGE_GAIN_OFFSET;
 		*val = 0;
-		*val2 = data->variant->regval_to_nanoscale[data->range];
+		*val2 = data->variant->regval_to_nanoscale[rval];
 		return IIO_VAL_INT_PLUS_NANO;
 	case IIO_CHAN_INFO_SAMP_FREQ:
-		*val = data->variant->regval_to_samp_freq[data->rate][0];
-		*val2 = data->variant->regval_to_samp_freq[data->rate][1];
+		ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &rval);
+		if (ret < 0)
+			return ret;
+		rval >>= HMC5843_RATE_OFFSET;
+		*val = data->variant->regval_to_samp_freq[rval][0];
+		*val2 = data->variant->regval_to_samp_freq[rval][1];
 		return IIO_VAL_INT_PLUS_MICRO;
 	}
 	return -EINVAL;
@@ -426,9 +422,9 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
 		goto done;
 	}
 
-	ret = i2c_smbus_read_i2c_block_data(data->client,
-		HMC5843_DATA_OUT_MSB_REGS, 3 * sizeof(__be16),
-			(u8 *) data->buffer);
+	ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
+			data->buffer, 3 * sizeof(__be16));
+
 	mutex_unlock(&data->lock);
 	if (ret < 0)
 		goto done;
@@ -466,7 +462,7 @@ static const struct iio_chan_spec hmc5843_channels[] = {
 	IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
-/* Beware: Y and Z are exchanged on HMC5883 */
+/* Beware: Y and Z are exchanged on HMC5883 and 5983 */
 static const struct iio_chan_spec hmc5883_channels[] = {
 	HMC5843_CHANNEL(X, 0),
 	HMC5843_CHANNEL(Z, 1),
@@ -489,18 +485,39 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
 	[HMC5843_ID] = {
 		.channels = hmc5843_channels,
 		.regval_to_samp_freq = hmc5843_regval_to_samp_freq,
+		.n_regval_to_samp_freq =
+				ARRAY_SIZE(hmc5843_regval_to_samp_freq),
 		.regval_to_nanoscale = hmc5843_regval_to_nanoscale,
+		.n_regval_to_nanoscale =
+				ARRAY_SIZE(hmc5843_regval_to_nanoscale),
 	},
 	[HMC5883_ID] = {
 		.channels = hmc5883_channels,
 		.regval_to_samp_freq = hmc5883_regval_to_samp_freq,
+		.n_regval_to_samp_freq =
+				ARRAY_SIZE(hmc5883_regval_to_samp_freq),
 		.regval_to_nanoscale = hmc5883_regval_to_nanoscale,
+		.n_regval_to_nanoscale =
+				ARRAY_SIZE(hmc5883_regval_to_nanoscale),
 	},
 	[HMC5883L_ID] = {
 		.channels = hmc5883_channels,
 		.regval_to_samp_freq = hmc5883_regval_to_samp_freq,
+		.n_regval_to_samp_freq =
+				ARRAY_SIZE(hmc5883_regval_to_samp_freq),
 		.regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
+		.n_regval_to_nanoscale =
+				ARRAY_SIZE(hmc5883l_regval_to_nanoscale),
 	},
+	[HMC5983_ID] = {
+		.channels = hmc5883_channels,
+		.regval_to_samp_freq = hmc5983_regval_to_samp_freq,
+		.n_regval_to_samp_freq =
+				ARRAY_SIZE(hmc5983_regval_to_samp_freq),
+		.regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
+		.n_regval_to_nanoscale =
+				ARRAY_SIZE(hmc5883l_regval_to_nanoscale),
+	}
 };
 
 static int hmc5843_init(struct hmc5843_data *data)
@@ -508,12 +525,12 @@ static int hmc5843_init(struct hmc5843_data *data)
 	int ret;
 	u8 id[3];
 
-	ret = i2c_smbus_read_i2c_block_data(data->client, HMC5843_ID_REG,
-		sizeof(id), id);
+	ret = regmap_bulk_read(data->regmap, HMC5843_ID_REG,
+			id, ARRAY_SIZE(id));
 	if (ret < 0)
 		return ret;
 	if (id[0] != 'H' || id[1] != '4' || id[2] != '3') {
-		dev_err(&data->client->dev, "no HMC5843/5883/5883L sensor\n");
+		dev_err(data->dev, "no HMC5843/5883/5883L/5983 sensor\n");
 		return -ENODEV;
 	}
 
@@ -539,27 +556,43 @@ static const struct iio_info hmc5843_info = {
 
 static const unsigned long hmc5843_scan_masks[] = {0x7, 0};
 
-static int hmc5843_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
+
+int hmc5843_common_suspend(struct device *dev)
+{
+	return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)),
+			HMC5843_MODE_CONVERSION_CONTINUOUS);
+}
+EXPORT_SYMBOL(hmc5843_common_suspend);
+
+int hmc5843_common_resume(struct device *dev)
+{
+	return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)),
+			HMC5843_MODE_SLEEP);
+}
+EXPORT_SYMBOL(hmc5843_common_resume);
+
+int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
+		enum hmc5843_ids id)
 {
 	struct hmc5843_data *data;
 	struct iio_dev *indio_dev;
 	int ret;
 
-	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
+	dev_set_drvdata(dev, indio_dev);
+
 	/* default settings at probe */
 	data = iio_priv(indio_dev);
-	data->client = client;
-	data->variant = &hmc5843_chip_info_tbl[id->driver_data];
+	data->dev = dev;
+	data->regmap = regmap;
+	data->variant = &hmc5843_chip_info_tbl[id];
 	mutex_init(&data->lock);
 
-	i2c_set_clientdata(client, indio_dev);
+	indio_dev->dev.parent = dev;
 	indio_dev->info = &hmc5843_info;
-	indio_dev->name = id->name;
-	indio_dev->dev.parent = &client->dev;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = data->variant->channels;
 	indio_dev->num_channels = 4;
@@ -584,10 +617,11 @@ static int hmc5843_probe(struct i2c_client *client,
 	iio_triggered_buffer_cleanup(indio_dev);
 	return ret;
 }
+EXPORT_SYMBOL(hmc5843_common_probe);
 
-static int hmc5843_remove(struct i2c_client *client)
+int hmc5843_common_remove(struct device *dev)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
 	iio_device_unregister(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
@@ -597,58 +631,8 @@ static int hmc5843_remove(struct i2c_client *client)
 
 	return 0;
 }
-
-#ifdef CONFIG_PM_SLEEP
-static int hmc5843_suspend(struct device *dev)
-{
-	struct hmc5843_data *data = iio_priv(i2c_get_clientdata(
-		to_i2c_client(dev)));
-
-	return hmc5843_set_mode(data, HMC5843_MODE_SLEEP);
-}
-
-static int hmc5843_resume(struct device *dev)
-{
-	struct hmc5843_data *data = iio_priv(i2c_get_clientdata(
-		to_i2c_client(dev)));
-
-	return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS);
-}
-
-static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume);
-#define HMC5843_PM_OPS (&hmc5843_pm_ops)
-#else
-#define HMC5843_PM_OPS NULL
-#endif
-
-static const struct i2c_device_id hmc5843_id[] = {
-	{ "hmc5843", HMC5843_ID },
-	{ "hmc5883", HMC5883_ID },
-	{ "hmc5883l", HMC5883L_ID },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, hmc5843_id);
-
-static const struct of_device_id hmc5843_of_match[] = {
-	{ .compatible = "honeywell,hmc5843", .data = (void *)HMC5843_ID },
-	{ .compatible = "honeywell,hmc5883", .data = (void *)HMC5883_ID },
-	{ .compatible = "honeywell,hmc5883l", .data = (void *)HMC5883L_ID },
-	{}
-};
-MODULE_DEVICE_TABLE(of, hmc5843_of_match);
-
-static struct i2c_driver hmc5843_driver = {
-	.driver = {
-		.name	= "hmc5843",
-		.pm	= HMC5843_PM_OPS,
-		.of_match_table = hmc5843_of_match,
-	},
-	.id_table	= hmc5843_id,
-	.probe		= hmc5843_probe,
-	.remove		= hmc5843_remove,
-};
-module_i2c_driver(hmc5843_driver);
+EXPORT_SYMBOL(hmc5843_common_remove);
 
 MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com>");
-MODULE_DESCRIPTION("HMC5843/5883/5883L driver");
+MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 core driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/magnetometer/hmc5843_i2c.c b/drivers/staging/iio/magnetometer/hmc5843_i2c.c
new file mode 100644
index 0000000000000000000000000000000000000000..6acd614cdbc6529ae22d4df7c53548f1e3852455
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/hmc5843_i2c.c
@@ -0,0 +1,104 @@
+/*
+ * i2c driver for hmc5843/5843/5883/5883l/5983
+ *
+ * Split from hmc5843.c
+ * Copyright (C) Josef Gajdusek <atx@atx.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include "hmc5843.h"
+
+static const struct regmap_range hmc5843_readable_ranges[] = {
+		regmap_reg_range(0, HMC5843_ID_END),
+};
+
+static struct regmap_access_table hmc5843_readable_table = {
+		.yes_ranges = hmc5843_readable_ranges,
+		.n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges),
+};
+
+static const struct regmap_range hmc5843_writable_ranges[] = {
+		regmap_reg_range(0, HMC5843_MODE_REG),
+};
+
+static struct regmap_access_table hmc5843_writable_table = {
+		.yes_ranges = hmc5843_writable_ranges,
+		.n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges),
+};
+
+static const struct regmap_range hmc5843_volatile_ranges[] = {
+		regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG),
+};
+
+static struct regmap_access_table hmc5843_volatile_table = {
+		.yes_ranges = hmc5843_volatile_ranges,
+		.n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges),
+};
+
+static struct regmap_config hmc5843_i2c_regmap_config = {
+		.reg_bits = 8,
+		.val_bits = 8,
+
+		.rd_table = &hmc5843_readable_table,
+		.wr_table = &hmc5843_writable_table,
+		.volatile_table = &hmc5843_volatile_table,
+
+		.cache_type = REGCACHE_RBTREE,
+};
+
+static int hmc5843_i2c_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	return hmc5843_common_probe(&client->dev,
+			devm_regmap_init_i2c(client, &hmc5843_i2c_regmap_config),
+			id->driver_data);
+}
+
+static int hmc5843_i2c_remove(struct i2c_client *client)
+{
+	return hmc5843_common_remove(&client->dev);
+}
+
+static const struct i2c_device_id hmc5843_id[] = {
+	{ "hmc5843", HMC5843_ID },
+	{ "hmc5883", HMC5883_ID },
+	{ "hmc5883l", HMC5883L_ID },
+	{ "hmc5983", HMC5983_ID },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, hmc5843_id);
+
+static const struct of_device_id hmc5843_of_match[] = {
+	{ .compatible = "honeywell,hmc5843", .data = (void *)HMC5843_ID },
+	{ .compatible = "honeywell,hmc5883", .data = (void *)HMC5883_ID },
+	{ .compatible = "honeywell,hmc5883l", .data = (void *)HMC5883L_ID },
+	{ .compatible = "honeywell,hmc5983", .data = (void *)HMC5983_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(of, hmc5843_of_match);
+
+static struct i2c_driver hmc5843_driver = {
+	.driver = {
+		.name	= "hmc5843",
+		.pm	= HMC5843_PM_OPS,
+		.of_match_table = hmc5843_of_match,
+	},
+	.id_table	= hmc5843_id,
+	.probe		= hmc5843_i2c_probe,
+	.remove		= hmc5843_i2c_remove,
+};
+module_i2c_driver(hmc5843_driver);
+
+MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>");
+MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 i2c driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/magnetometer/hmc5843_spi.c b/drivers/staging/iio/magnetometer/hmc5843_spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..98c4b57101c9d91bc494fb209a416d3dd37d5fc8
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/hmc5843_spi.c
@@ -0,0 +1,100 @@
+/*
+ * SPI driver for hmc5983
+ *
+ * Copyright (C) Josef Gajdusek <atx@atx.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+
+#include "hmc5843.h"
+
+static const struct regmap_range hmc5843_readable_ranges[] = {
+		regmap_reg_range(0, HMC5843_ID_END),
+};
+
+static struct regmap_access_table hmc5843_readable_table = {
+		.yes_ranges = hmc5843_readable_ranges,
+		.n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges),
+};
+
+static const struct regmap_range hmc5843_writable_ranges[] = {
+		regmap_reg_range(0, HMC5843_MODE_REG),
+};
+
+static struct regmap_access_table hmc5843_writable_table = {
+		.yes_ranges = hmc5843_writable_ranges,
+		.n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges),
+};
+
+static const struct regmap_range hmc5843_volatile_ranges[] = {
+		regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG),
+};
+
+static struct regmap_access_table hmc5843_volatile_table = {
+		.yes_ranges = hmc5843_volatile_ranges,
+		.n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges),
+};
+
+static struct regmap_config hmc5843_spi_regmap_config = {
+		.reg_bits = 8,
+		.val_bits = 8,
+
+		.rd_table = &hmc5843_readable_table,
+		.wr_table = &hmc5843_writable_table,
+		.volatile_table = &hmc5843_volatile_table,
+
+		/* Autoincrement address pointer */
+		.read_flag_mask = 0xc0,
+
+		.cache_type = REGCACHE_RBTREE,
+};
+
+static int hmc5843_spi_probe(struct spi_device *spi)
+{
+	int ret;
+
+	spi->mode = SPI_MODE_3;
+	spi->max_speed_hz = 8000000;
+	spi->bits_per_word = 8;
+	ret = spi_setup(spi);
+	if (ret)
+		return ret;
+
+	return hmc5843_common_probe(&spi->dev,
+			devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config),
+			HMC5983_ID);
+}
+
+static int hmc5843_spi_remove(struct spi_device *spi)
+{
+	return hmc5843_common_remove(&spi->dev);
+}
+
+static const struct spi_device_id hmc5843_id[] = {
+	{ "hmc5983", HMC5983_ID },
+	{ }
+};
+
+static struct spi_driver hmc5843_driver = {
+		.driver = {
+				.name = "hmc5843",
+				.pm = HMC5843_PM_OPS,
+				.owner = THIS_MODULE,
+		},
+		.id_table = hmc5843_id,
+		.probe = hmc5843_spi_probe,
+		.remove = hmc5843_spi_remove,
+};
+
+module_spi_driver(hmc5843_driver);
+
+MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>");
+MODULE_DESCRIPTION("HMC5983 SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index 4a848d6be3bf73b8521059cbd71b43a9a3deba95..4a2af8adf874619a9d9badf066a4dda6d1ddee16 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -56,6 +56,10 @@ enum iio_modifier {
 	IIO_MOD_QUATERNION,
 	IIO_MOD_TEMP_AMBIENT,
 	IIO_MOD_TEMP_OBJECT,
+	IIO_MOD_NORTH_MAGN,
+	IIO_MOD_NORTH_TRUE,
+	IIO_MOD_NORTH_MAGN_TILT_COMP,
+	IIO_MOD_NORTH_TRUE_TILT_COMP
 };
 
 enum iio_event_type {